From bef09004cc1d7e356d6051571e39825079926c3c Mon Sep 17 00:00:00 2001 From: Geng Zhang Date: Sun, 24 Mar 2019 15:02:11 +0800 Subject: [PATCH] Init project. --- .github/ISSUE_TEMPLATE/Ask_Question.md | 27 + .github/ISSUE_TEMPLATE/Bug_Report.md | 25 + .github/PULL_REQUEST_TEMPLATE.md | 14 + .gitignore | 19 + .travis.yml | 15 + LICENSE | 201 +++ README.md | 44 + appveyor.yml | 30 + client/all/pom.xml | 273 ++++ client/api/pom.xml | 53 + .../client/api/ConfigDataObserver.java | 35 + .../registry/client/api/Configurator.java | 48 + .../sofa/registry/client/api/EventBus.java | 65 + .../registry/client/api/EventSubscriber.java | 41 + .../sofa/registry/client/api/Publisher.java | 33 + .../sofa/registry/client/api/Register.java | 77 + .../registry/client/api/RegistryClient.java | 65 + .../client/api/RegistryClientConfig.java | 172 +++ .../sofa/registry/client/api/Subscriber.java | 57 + .../client/api/SubscriberDataObserver.java | 36 + .../api/exception/DuplicateException.java | 62 + .../exception/RegistryClientException.java | 62 + .../registry/client/api/model/ConfigData.java | 32 + .../sofa/registry/client/api/model/Event.java | 25 + .../client/api/model/RegistryType.java | 27 + .../registry/client/api/model/UserData.java | 43 + .../api/registration/BaseRegistration.java | 94 ++ .../ConfiguratorRegistration.java | 67 + .../registration/PublisherRegistration.java | 46 + .../registration/SubscriberRegistration.java | 92 ++ .../api/exception/DuplicateExceptionTest.java | 45 + .../RegistryClientExceptionTest.java | 44 + .../registration/BaseRegistrationTest.java | 40 + .../ConfiguratorRegistrationTest.java | 43 + .../PublisherRegistrationTest.java | 33 + .../SubscriberRegistrationTest.java | 46 + .../core/model/ReceivedConfigDataTest.java | 47 + .../registry/core/model/ReceivedDataTest.java | 58 + .../sofa/registry/core/model/ResultTest.java | 36 + .../registry/core/model/ScopeEnumTest.java | 32 + client/impl/pom.xml | 102 ++ .../registry/client/auth/AuthManager.java | 37 + .../registry/client/auth/NoopAuthManager.java | 46 + .../client/constants/ValueConstants.java | 40 + .../client/constants/VersionConstants.java | 27 + .../event/ConfiguratorProcessEvent.java | 138 ++ .../client/event/DefaultEventBus.java | 152 ++ .../client/event/LookoutSubscriber.java | 130 ++ .../client/event/SubscriberProcessEvent.java | 138 ++ .../client/factory/NamedThreadFactory.java | 71 + .../client/model/ConfiguratorData.java | 71 + .../registry/client/model/SegmentData.java | 93 ++ .../provider/AbstractInternalRegister.java | 407 +++++ .../client/provider/DefaultConfigData.java | 51 + .../client/provider/DefaultConfigurator.java | 226 +++ .../provider/DefaultObserverHandler.java | 192 +++ .../client/provider/DefaultPublisher.java | 180 +++ .../provider/DefaultRegistryClient.java | 609 ++++++++ .../provider/DefaultRegistryClientConfig.java | 462 ++++++ .../DefaultRegistryClientConfigBuilder.java | 293 ++++ .../client/provider/DefaultServerManager.java | 166 ++ .../client/provider/DefaultServerNode.java | 175 +++ .../client/provider/DefaultSubscriber.java | 315 ++++ .../client/provider/DefaultUserData.java | 86 ++ .../client/provider/RegisterCache.java | 157 ++ .../sofa/registry/client/remoting/Client.java | 56 + .../client/remoting/ClientConnection.java | 300 ++++ .../ClientConnectionCloseEventProcessor.java | 46 + .../ClientConnectionOpenEventProcessor.java | 46 + .../remoting/ReceivedConfigDataProcessor.java | 115 ++ .../remoting/ReceivedDataProcessor.java | 124 ++ .../client/remoting/ServerManager.java | 41 + .../registry/client/remoting/ServerNode.java | 55 + .../client/task/AbstractWorkerThread.java | 72 + .../registry/client/task/ObserverHandler.java | 42 + .../client/task/SyncConfigThread.java | 135 ++ .../sofa/registry/client/task/TaskEvent.java | 153 ++ .../sofa/registry/client/task/TaskQueue.java | 95 ++ .../sofa/registry/client/task/Worker.java | 46 + .../registry/client/task/WorkerThread.java | 196 +++ .../registry/client/util/CommonUtils.java | 37 + .../registry/client/util/HttpClientUtils.java | 124 ++ .../client/util/ServerNodeParser.java | 140 ++ .../registry/client/util/StringUtils.java | 118 ++ .../registry/client/log/log4j/log-conf.xml | 62 + .../registry/client/log/log4j2/log-conf.xml | 86 ++ .../registry/client/log/logback/log-conf.xml | 84 + .../sofa/registry/client/MockServer.java | 224 +++ .../sofa/registry/client/base/BaseTest.java | 72 + .../client/event/DefaultEventBusTest.java | 90 ++ .../client/event/LookoutSubscriberTest.java | 82 + .../sofa/registry/client/event/TestEvent.java | 51 + .../client/event/TestEventSubscriber.java | 57 + .../client/model/ConfiguratorDataTest.java | 37 + .../provider/DefaultRegistryClientTest.java | 300 ++++ .../provider/DefaultServerManagerTest.java | 72 + .../provider/DefaultSubscriberTest.java | 284 ++++ .../client/provider/RegisterOrderTest.java | 224 +++ .../ReceivedConfigDataProcessorTest.java | 81 + .../remoting/ReceivedDataProcessorTest.java | 91 ++ .../client/task/SyncConfigThreadTest.java | 92 ++ .../registry/client/task/TaskEventTest.java | 107 ++ .../registry/client/util/CommonUtilsTest.java | 35 + .../client/util/HttpClientUtilsTest.java | 106 ++ .../client/util/ServerNodeParserTest.java | 106 ++ .../registry/client/util/StringUtilsTest.java | 89 ++ client/log/pom.xml | 54 + .../registry/client/log/LoggerFactory.java | 101 ++ .../client/log/LoggerFactoryTest.java | 64 + client/pom.xml | 93 ++ core/pom.xml | 45 + .../core/constants/EventTypeConstants.java | 29 + .../registry/core/model/BaseRegister.java | 347 +++++ .../core/model/ConfiguratorRegister.java | 27 + .../sofa/registry/core/model/DataBox.java | 71 + .../core/model/PublisherRegister.java | 59 + .../core/model/ReceivedConfigData.java | 160 ++ .../registry/core/model/ReceivedData.java | 253 +++ .../registry/core/model/RegisterResponse.java | 139 ++ .../sofa/registry/core/model/Result.java | 79 + .../sofa/registry/core/model/ScopeEnum.java | 42 + .../core/model/SubscriberRegister.java | 56 + .../core/model/SyncConfigRequest.java | 80 + .../core/model/SyncConfigResponse.java | 81 + pom.xml | 510 +++++++ server/common/model/pom.xml | 37 + .../registry/common/model/CommonResponse.java | 111 ++ .../registry/common/model/ElementType.java | 36 + .../common/model/GenericResponse.java | 70 + .../sofa/registry/common/model/Node.java | 67 + .../registry/common/model/PublishType.java | 35 + .../common/model/PushDataRetryRequest.java | 66 + .../registry/common/model/ServerDataBox.java | 214 +++ .../model/ServerDataBoxInputStream.java | 55 + .../common/model/console/PersistenceData.java | 134 ++ .../model/constants/ValueConstants.java | 59 + .../model/dataserver/ClientOffRequest.java | 96 ++ .../common/model/dataserver/Datum.java | 269 ++++ .../model/dataserver/GetDataRequest.java | 95 ++ .../dataserver/GetDataVersionRequest.java | 66 + .../dataserver/NotifyDataSyncRequest.java | 137 ++ .../dataserver/NotifyFetchDatumRequest.java | 110 ++ .../model/dataserver/NotifyOnlineRequest.java | 67 + .../model/dataserver/PublishDataRequest.java | 85 ++ .../SessionServerRegisterRequest.java | 77 + .../common/model/dataserver/SyncData.java | 135 ++ .../model/dataserver/SyncDataRequest.java | 134 ++ .../dataserver/UnPublishDataRequest.java | 115 ++ .../model/metaserver/DataCenterNodes.java | 117 ++ .../common/model/metaserver/DataNode.java | 224 +++ .../common/model/metaserver/DataOperator.java | 26 + .../metaserver/FetchProvideDataRequest.java | 54 + .../metaserver/GetChangeListRequest.java | 82 + .../model/metaserver/GetNodesRequest.java | 56 + .../common/model/metaserver/MetaNode.java | 141 ++ .../model/metaserver/NodeChangeResult.java | 143 ++ .../metaserver/NotifyProvideDataChange.java | 109 ++ .../common/model/metaserver/ProvideData.java | 112 ++ .../model/metaserver/ReNewNodesRequest.java | 77 + .../common/model/metaserver/SessionNode.java | 178 +++ .../metaserver/StatusConfirmRequest.java | 89 ++ .../sessionserver/CancelAddressRequest.java | 65 + .../sessionserver/DataChangeRequest.java | 121 ++ .../model/sessionserver/DataPushRequest.java | 71 + .../registry/common/model/store/BaseInfo.java | 388 +++++ .../registry/common/model/store/DataInfo.java | 168 ++ .../common/model/store/Publisher.java | 114 ++ .../common/model/store/StoreData.java | 44 + .../common/model/store/Subscriber.java | 164 ++ .../sofa/registry/common/model/store/URL.java | 265 ++++ .../registry/common/model/store/Watcher.java | 30 + .../common/model/store/WordCache.java | 63 + server/common/pom.xml | 25 + server/common/util/pom.xml | 61 + .../converter/ScopeEnumConverter.java | 39 + .../com/alipay/sofa/registry/log/Logger.java | 249 +++ .../sofa/registry/log/LoggerFactory.java | 63 + .../alipay/sofa/registry/log/SLF4JLogger.java | 321 ++++ .../sofa/registry/metrics/ReporterUtils.java | 49 + .../sofa/registry/metrics/TaskMetrics.java | 73 + .../com/alipay/sofa/registry/net/NetUtil.java | 199 +++ .../alipay/sofa/registry/task/Retryable.java | 31 + .../com/alipay/sofa/registry/task/Task.java | 51 + .../sofa/registry/task/TaskClosure.java | 34 + .../task/batcher/AcceptorExecutor.java | 320 ++++ .../registry/task/batcher/TaskDispatcher.java | 50 + .../task/batcher/TaskDispatchers.java | 147 ++ .../registry/task/batcher/TaskExecutors.java | 164 ++ .../registry/task/batcher/TaskHolder.java | 80 + .../registry/task/batcher/TaskProcessor.java | 54 + .../registry/task/batcher/TrafficShaper.java | 90 ++ .../listener/DefaultTaskListenerManager.java | 48 + .../registry/task/listener/TaskEvent.java | 201 +++ .../registry/task/listener/TaskListener.java | 40 + .../task/listener/TaskListenerManager.java | 45 + .../task/scheduler/TimedSupervisorTask.java | 105 ++ .../registry/timer/AsyncHashedWheelTimer.java | 198 +++ .../sofa/registry/util/CollectionUtils.java | 40 + .../alipay/sofa/registry/util/FileUtils.java | 263 ++++ .../registry/util/NamedThreadFactory.java | 65 + .../sofa/registry/util/ParaCheckUtil.java | 63 + .../sofa/registry/util/PropertySplitter.java | 98 ++ .../sofa/registry/util/VersionsMapUtils.java | 46 + .../converter/ScopeEnumConverterTest.java | 35 + .../alipay/sofa/registry/log/LoggerTest.java | 189 +++ .../sofa/registry/log/TestAppender.java | 57 + .../task/listener/TaskListenerTest.java | 101 ++ .../registry/util/CollectionUtilsTest.java | 49 + .../sofa/registry/util/FileUtilsTest.java | 64 + .../sofa/registry/util/ParaCheckUtilTest.java | 67 + .../registry/util/PropertySplitterTest.java | 78 + .../util/src/test/resources/logback-test.xml | 31 + server/consistency/pom.xml | 38 + .../consistency/hash/ConsistentHash.java | 151 ++ .../consistency/hash/HashFunction.java | 32 + .../registry/consistency/hash/HashNode.java | 32 + .../consistency/hash/MD5HashFunction.java | 58 + .../consistency/hash/MessageDigests.java | 111 ++ .../registry/consistency/hash/BackupTest.java | 135 ++ .../consistency/hash/ConsistentHashTest.java | 130 ++ .../consistency/hash/MessageDigestsTest.java | 89 ++ .../registry/consistency/hash/TestNode.java | 86 ++ server/distribution/data/bin/shutdown.bat | 21 + server/distribution/data/bin/shutdown.sh | 27 + server/distribution/data/bin/startup.bat | 53 + server/distribution/data/bin/startup.sh | 49 + .../data/conf/application.properties | 3 + .../data/conf/application.properties.example | 17 + .../distribution/data/distribution-data.xml | 48 + server/distribution/data/pom.xml | 52 + .../distribution/integration/bin/shutdown.bat | 21 + .../distribution/integration/bin/shutdown.sh | 27 + .../distribution/integration/bin/startup.bat | 53 + .../distribution/integration/bin/startup.sh | 52 + .../integration/conf/application.properties | 3 + .../conf/application.properties.example | 53 + .../integration/distribution-integration.xml | 48 + server/distribution/integration/pom.xml | 51 + server/distribution/meta/bin/shutdown.bat | 21 + server/distribution/meta/bin/shutdown.sh | 27 + server/distribution/meta/bin/startup.bat | 53 + server/distribution/meta/bin/startup.sh | 52 + .../meta/conf/application.properties | 2 + .../meta/conf/application.properties.example | 12 + .../distribution/meta/distribution-meta.xml | 48 + server/distribution/meta/pom.xml | 52 + server/distribution/pom.xml | 28 + server/distribution/session/bin/shutdown.bat | 21 + server/distribution/session/bin/shutdown.sh | 27 + server/distribution/session/bin/startup.bat | 53 + server/distribution/session/bin/startup.sh | 49 + .../session/conf/application.properties | 3 + .../conf/application.properties.example | 31 + .../session/distribution-session.xml | 48 + server/distribution/session/pom.xml | 52 + server/distribution/version | 0 server/pom.xml | 54 + server/remoting/api/pom.xml | 38 + .../registry/remoting/CallbackHandler.java | 41 + .../sofa/registry/remoting/Channel.java | 71 + .../registry/remoting/ChannelHandler.java | 117 ++ .../alipay/sofa/registry/remoting/Client.java | 60 + .../sofa/registry/remoting/Endpoint.java | 89 ++ .../registry/remoting/RemotingException.java | 33 + .../alipay/sofa/registry/remoting/Server.java | 60 + .../registry/remoting/exchange/Exchange.java | 65 + .../remoting/exchange/NodeExchanger.java | 43 + .../remoting/exchange/RequestException.java | 90 ++ .../remoting/exchange/message/Request.java | 63 + .../remoting/exchange/message/Response.java | 39 + .../remoting/RequestExceptionTest.java | 66 + server/remoting/bolt/pom.xml | 50 + .../bolt/AsyncUserProcessorAdapter.java | 81 + .../registry/remoting/bolt/BoltChannel.java | 140 ++ .../remoting/bolt/BoltChannelUtil.java | 49 + .../registry/remoting/bolt/BoltClient.java | 329 ++++ .../registry/remoting/bolt/BoltServer.java | 345 +++++ .../remoting/bolt/ConnectionEventAdapter.java | 95 ++ .../bolt/SyncUserProcessorAdapter.java | 72 + .../remoting/bolt/exchange/BoltExchange.java | 100 ++ .../remoting/bolt/BoltServerTest.java | 79 + server/remoting/http/pom.xml | 79 + .../remoting/jersey/JerseyChannel.java | 97 ++ .../remoting/jersey/JerseyClient.java | 199 +++ .../remoting/jersey/JerseyJettyServer.java | 227 +++ .../jersey/exchange/JerseyExchange.java | 107 ++ .../server/HttpChannelOverHttpCustom.java | 56 + .../jetty/server/HttpConnectionCustom.java | 43 + .../server/HttpConnectionCustomFactory.java | 43 + server/remoting/pom.xml | 25 + server/server/data/pom.xml | 111 ++ .../registry/server/data/DataApplication.java | 43 + .../server/data/bootstrap/CommonConfig.java | 79 + .../DataServerBeanConfiguration.java | 452 ++++++ .../data/bootstrap/DataServerBootstrap.java | 254 ++++ .../data/bootstrap/DataServerConfig.java | 602 ++++++++ .../data/bootstrap/DataServerInitializer.java | 65 + .../data/bootstrap/EnableDataServer.java | 37 + .../server/data/cache/BackupTriad.java | 133 ++ .../server/data/cache/CacheDigestTask.java | 95 ++ .../server/data/cache/DataServerCache.java | 375 +++++ .../data/cache/DataServerChangeItem.java | 79 + .../server/data/cache/DatumCache.java | 309 ++++ .../server/data/cache/MergeResult.java | 70 + .../server/data/cache/UnPublisher.java | 50 + .../server/data/change/ChangeData.java | 120 ++ .../server/data/change/DataChangeHandler.java | 194 +++ .../data/change/DataChangeTypeEnum.java | 32 + .../data/change/DataSourceTypeEnum.java | 50 + .../data/change/event/ClientChangeEvent.java | 87 ++ .../data/change/event/DataChangeEvent.java | 99 ++ .../change/event/DataChangeEventCenter.java | 137 ++ .../change/event/DataChangeEventQueue.java | 258 ++++ .../change/event/DataChangeScopeEnum.java | 26 + .../data/change/event/IDataChangeEvent.java | 31 + .../data/change/notify/BackUpNotifier.java | 51 + .../change/notify/IDataChangeNotifier.java | 44 + .../change/notify/SessionServerNotifier.java | 204 +++ .../change/notify/TempPublisherNotifier.java | 157 ++ .../LocalDataServerCleanHandler.java | 170 +++ .../server/data/datasync/AcceptorStore.java | 58 + .../server/data/datasync/Operator.java | 128 ++ .../server/data/datasync/SyncDataService.java | 42 + .../datasync/sync/AbstractAcceptorStore.java | 273 ++++ .../server/data/datasync/sync/Acceptor.java | 319 ++++ .../datasync/sync/LocalAcceptorStore.java | 49 + .../server/data/datasync/sync/Scheduler.java | 87 ++ .../datasync/sync/StoreServiceFactory.java | 51 + .../datasync/sync/SyncDataServiceImpl.java | 63 + .../data/event/DataServerChangeEvent.java | 66 + .../server/data/event/EventCenter.java | 53 + .../event/LocalDataServerChangeEvent.java | 90 ++ .../data/event/MetaServerChangeEvent.java | 47 + .../server/data/event/StartTaskEvent.java | 39 + .../event/handler/AbstractEventHandler.java | 57 + .../handler/DataServerChangeEventHandler.java | 209 +++ .../LocalDataServerChangeEventHandler.java | 385 +++++ .../handler/MetaServerChangeEventHandler.java | 170 +++ .../event/handler/StartTaskEventHandler.java | 65 + .../server/data/executor/ExecutorFactory.java | 100 ++ .../server/data/node/DataNodeStatus.java | 41 + .../server/data/node/DataServerNode.java | 87 ++ .../data/remoting/DataNodeExchanger.java | 101 ++ .../data/remoting/MetaNodeExchanger.java | 113 ++ .../DataServerConnectionFactory.java | 65 + .../dataserver/DataServerNodeFactory.java | 219 +++ .../dataserver/GetSyncDataHandler.java | 85 ++ .../remoting/dataserver/SyncDataCallback.java | 177 +++ .../DataSyncServerConnectionHandler.java | 72 + .../dataserver/handler/FetchDataHandler.java | 68 + .../handler/NotifyDataSyncHandler.java | 131 ++ .../handler/NotifyFetchDatumHandler.java | 193 +++ .../handler/NotifyOnlineHandler.java | 71 + .../dataserver/handler/SyncDataHandler.java | 71 + .../dataserver/task/AbstractTask.java | 77 + .../task/ConnectionRefreshTask.java | 63 + .../dataserver/task/ReNewNodeTask.java | 53 + .../handler/AbstractClientHandler.java | 132 ++ .../handler/AbstractServerHandler.java | 142 ++ .../metaserver/DefaultMetaServiceImpl.java | 302 ++++ .../metaserver/IMetaServerService.java | 94 ++ .../MetaServerConnectionFactory.java | 136 ++ .../handler/ServerChangeHandler.java | 95 ++ .../handler/StatusConfirmHandler.java | 67 + .../task/ConnectionRefreshMetaTask.java | 59 + .../SessionServerConnectionFactory.java | 186 +++ .../disconnect/ClientDisconnectEvent.java | 51 + .../disconnect/DisconnectEvent.java | 132 ++ .../disconnect/DisconnectEventHandler.java | 124 ++ .../disconnect/DisconnectTypeEnum.java | 29 + .../SessionServerDisconnectEvent.java | 62 + .../sessionserver/forward/ForwardService.java | 47 + .../forward/ForwardServiceImpl.java | 116 ++ .../handler/ClientOffHandler.java | 80 + .../handler/DataServerConnectionHandler.java | 71 + .../sessionserver/handler/GetDataHandler.java | 116 ++ .../handler/GetDataVersionsHandler.java | 90 ++ .../handler/PublishDataHandler.java | 138 ++ .../handler/SessionServerRegisterHandler.java | 78 + .../handler/UnPublishDataHandler.java | 94 ++ .../data/resource/DataDigestResource.java | 117 ++ .../server/data/resource/HealthResource.java | 81 + .../registry/server/data/util/DelayItem.java | 90 ++ .../data/util/LocalServerStatusEnum.java | 29 + .../util/ThreadPoolExecutorDataServer.java | 62 + .../registry/server/data/util/TimeUtil.java | 46 + .../src/main/resources/application.properties | 17 + .../server/data/src/main/resources/banner.txt | 7 + .../src/main/resources/logback-spring.xml | 223 +++ .../registry/server/data/BackupTriadTest.java | 84 + .../registry/server/data/TestSyncData.java | 103 ++ .../registry/server/data/TimeUtilTest.java | 37 + .../data/src/test/resources/logback-test.xml | 75 + server/server/integration/pom.xml | 66 + .../integration/RegistryApplication.java | 152 ++ .../src/main/resources/application.properties | 53 + .../integration/src/main/resources/banner.txt | 9 + .../src/main/resources/logback-spring.xml | 538 +++++++ server/server/meta/pom.xml | 122 ++ .../registry/server/meta/MetaApplication.java | 44 + .../bootstrap/AbstractNodeConfigBean.java | 130 ++ .../meta/bootstrap/EnableMetaServer.java | 37 + .../meta/bootstrap/MetaServerBootstrap.java | 293 ++++ .../meta/bootstrap/MetaServerConfig.java | 90 ++ .../meta/bootstrap/MetaServerConfigBean.java | 602 ++++++++ .../bootstrap/MetaServerConfiguration.java | 436 ++++++ .../MetaServerInitializerConfiguration.java | 82 + .../server/meta/bootstrap/NodeConfig.java | 63 + .../bootstrap/NodeConfigBeanProperty.java | 52 + .../server/meta/bootstrap/ServiceFactory.java | 78 + .../server/meta/executor/ExecutorManager.java | 182 +++ .../DataNodeChangePushTaskListener.java | 87 ++ ...rsistenceDataChangeNotifyTaskListener.java | 64 + ...eceiveStatusConfirmNotifyTaskListener.java | 68 + .../SessionNodeChangePushTaskListener.java | 63 + .../server/meta/node/DataNodeService.java | 36 + .../server/meta/node/MetaNodeService.java | 30 + .../server/meta/node/NodeOperator.java | 81 + .../server/meta/node/NodeService.java | 29 + .../server/meta/node/SessionNodeService.java | 38 + .../meta/node/impl/DataNodeServiceImpl.java | 200 +++ .../meta/node/impl/MetaNodeServiceImpl.java | 82 + .../node/impl/SessionNodeServiceImpl.java | 230 +++ .../meta/registry/MetaServerRegistry.java | 106 ++ .../server/meta/registry/Registry.java | 91 ++ .../meta/remoting/DataNodeExchanger.java | 85 ++ .../meta/remoting/MetaClientExchanger.java | 204 +++ .../meta/remoting/MetaServerExchanger.java | 85 ++ .../server/meta/remoting/RaftExchanger.java | 377 +++++ .../meta/remoting/SessionNodeExchanger.java | 84 + .../connection/DataConnectionHandler.java | 80 + .../connection/MetaConnectionHandler.java | 117 ++ .../connection/NodeConnectManager.java | 39 + .../connection/SessionConnectionHandler.java | 79 + .../handler/AbstractServerHandler.java | 70 + .../remoting/handler/DataNodeHandler.java | 61 + .../FetchProvideDataRequestHandler.java | 90 ++ .../handler/GetChangeListRequestHandler.java | 63 + .../handler/GetNodesRequestHandler.java | 63 + .../handler/ReNewNodesRequestHandler.java | 61 + .../remoting/handler/SessionNodeHandler.java | 61 + .../repository/NodeConfirmStatusService.java | 53 + .../meta/repository/NodeRepository.java | 112 ++ .../meta/repository/RepositoryService.java | 55 + .../repository/VersionRepositoryService.java | 38 + .../RaftAnnotationBeanPostProcessor.java | 141 ++ .../service/DataConfirmStatusService.java | 205 +++ .../service/DataRepositoryService.java | 366 +++++ .../service/MetaRepositoryService.java | 350 +++++ .../service/SessionConfirmStatusService.java | 207 +++ .../service/SessionRepositoryService.java | 218 +++ .../SessionVersionRepositoryService.java | 107 ++ .../meta/resource/DecisionModeResource.java | 50 + .../server/meta/resource/HealthResource.java | 102 ++ .../meta/resource/MetaDigestResource.java | 118 ++ .../meta/resource/MetaStoreResource.java | 216 +++ .../meta/resource/PersistentDataResource.java | 134 ++ .../meta/resource/StopPushDataResource.java | 134 ++ .../server/meta/store/DataStoreService.java | 598 ++++++++ .../server/meta/store/MetaStoreService.java | 359 +++++ .../server/meta/store/RenewDecorate.java | 116 ++ .../meta/store/SessionStoreService.java | 450 ++++++ .../server/meta/store/StoreService.java | 118 ++ .../meta/task/AbstractMetaServerTask.java | 65 + .../registry/server/meta/task/Constant.java | 37 + .../meta/task/DataNodeChangePushTask.java | 105 ++ .../server/meta/task/MetaServerTask.java | 28 + .../task/PersistenceDataChangeNotifyTask.java | 70 + .../task/ReceiveStatusConfirmNotifyTask.java | 70 + .../meta/task/SessionNodeChangePushTask.java | 77 + .../DataNodeSingleTaskProcessor.java | 60 + .../MetaNodeSingleTaskProcessor.java | 60 + .../SessionNodeSingleTaskProcessor.java | 61 + .../src/main/resources/application.properties | 12 + .../server/meta/src/main/resources/banner.txt | 7 + .../src/main/resources/logback-spring.xml | 223 +++ .../registry/server/meta/test/BaseTest.java | 28 + .../server/meta/test/ConcurrentTestUtil.java | 71 + .../registry/server/meta/test/HttpTest.java | 94 ++ .../server/meta/test/ProcessResponseTest.java | 64 + .../DataNodeChangePushTaskListenerMock.java | 79 + .../test/confirm/DataServerConfirmTest.java | 177 +++ .../ReceiveStatusConfirmNotifyTaskMock.java | 52 + .../SessionNodeChangePushTaskMock.java | 72 + .../src/test/resources/application.properties | 9 + .../meta/src/test/resources/logback-test.xml | 27 + server/server/pom.xml | 26 + server/server/session/pom.xml | 102 ++ .../server/session/SessionApplication.java | 44 + .../session/bootstrap/CommonConfig.java | 88 ++ .../bootstrap/SessionServerBootstrap.java | 431 ++++++ .../bootstrap/SessionServerConfig.java | 143 ++ .../bootstrap/SessionServerConfigBean.java | 1351 +++++++++++++++++ .../bootstrap/SessionServerConfiguration.java | 605 ++++++++ .../bootstrap/SessionServerInitializer.java | 80 + .../server/session/cache/CacheGenerator.java | 34 + .../server/session/cache/CacheService.java | 42 + .../session/cache/DatumCacheGenerator.java | 64 + .../server/session/cache/DatumKey.java | 85 ++ .../server/session/cache/EntityType.java | 35 + .../registry/server/session/cache/Key.java | 108 ++ .../session/cache/SessionCacheService.java | 129 ++ .../session/cache/SubscriberResult.java | 81 + .../registry/server/session/cache/Value.java | 45 + .../server/session/converter/Converter.java | 30 + .../session/converter/PublisherConverter.java | 89 ++ .../converter/ReceivedDataConverter.java | 265 ++++ .../converter/SubscriberConverter.java | 104 ++ .../listener/CancelDataTaskListener.java | 94 ++ .../DataChangeFetchCloudTaskListener.java | 91 ++ .../listener/DataChangeFetchTaskListener.java | 92 ++ .../listener/DataPushTaskListener.java | 86 ++ .../ProvideDataChangeFetchTaskListener.java | 104 ++ .../session/listener/PushTaskSender.java | 41 + .../ReceivedConfigDataPushTaskListener.java | 80 + .../ReceivedDataMultiPushTaskListener.java | 133 ++ .../SessionRegisterDataTaskListener.java | 82 + .../SubscriberMultiFetchTaskListener.java | 90 ++ .../SubscriberRegisterFetchTaskListener.java | 97 ++ .../WatcherRegisterFetchTaskListener.java | 87 ++ .../session/node/AbstractNodeManager.java | 168 ++ .../server/session/node/DataNodeManager.java | 77 + .../server/session/node/MetaNodeManager.java | 49 + .../server/session/node/NodeManager.java | 48 + .../session/node/NodeManagerFactory.java | 47 + .../session/node/RaftClientManager.java | 144 ++ .../session/node/SessionNodeManager.java | 121 ++ .../node/SessionProcessIdGenerator.java | 122 ++ .../ClientNodeSingleTaskProcessor.java | 51 + .../ConsoleSyncSingleTaskProcessor.java | 60 + .../DataNodeSingleTaskProcessor.java | 60 + .../MetaNodeSingleTaskProcessor.java | 60 + .../node/service/ClientNodeService.java | 30 + .../node/service/ClientNodeServiceImpl.java | 64 + .../session/node/service/DataNodeService.java | 100 ++ .../node/service/DataNodeServiceImpl.java | 469 ++++++ .../session/node/service/MetaNodeService.java | 34 + .../node/service/MetaNodeServiceImpl.java | 85 ++ .../server/session/registry/Registry.java | 64 + .../session/registry/SessionRegistry.java | 284 ++++ .../session/remoting/ClientNodeExchanger.java | 93 ++ .../session/remoting/DataNodeExchanger.java | 146 ++ .../session/remoting/MetaNodeExchanger.java | 149 ++ .../handler/AbstractClientHandler.java | 74 + .../handler/AbstractServerHandler.java | 76 + .../handler/CancelAddressRequestHandler.java | 86 ++ .../handler/ClientNodeConnectionHandler.java | 106 ++ .../handler/DataChangeRequestHandler.java | 132 ++ .../handler/DataNodeConnectionHandler.java | 68 + .../handler/DataPushRequestHandler.java | 92 ++ .../handler/MetaNodeConnectionHandler.java | 37 + .../handler/NodeChangeResultHandler.java | 72 + .../NotifyProvideDataChangeHandler.java | 100 ++ .../remoting/handler/PublisherHandler.java | 65 + .../remoting/handler/SubscriberHandler.java | 65 + .../remoting/handler/SyncConfigHandler.java | 57 + .../remoting/handler/WatcherHandler.java | 52 + .../session/resource/ClientsOpenResource.java | 67 + .../session/resource/HealthResource.java | 84 + .../resource/SessionDigestResource.java | 193 +++ .../session/resource/SessionOpenResource.java | 89 ++ .../session/scheduler/ExecutorManager.java | 293 ++++ .../scheduler/SessionThreadPoolExecutor.java | 72 + .../scheduler/task/AbstractSessionTask.java | 65 + .../scheduler/task/CancelDataTask.java | 105 ++ .../session/scheduler/task/Constant.java | 31 + .../task/DataChangeFetchCloudTask.java | 306 ++++ .../scheduler/task/DataChangeFetchTask.java | 341 +++++ .../session/scheduler/task/DataPushTask.java | 280 ++++ .../task/ProvideDataChangeFetchTask.java | 261 ++++ .../scheduler/task/PushTaskClosure.java | 121 ++ .../task/ReceivedConfigDataPushTask.java | 132 ++ .../task/ReceivedDataMultiPushTask.java | 284 ++++ .../task/SessionRegisterDataTask.java | 106 ++ .../session/scheduler/task/SessionTask.java | 28 + .../task/SubscriberMultiFetchTask.java | 101 ++ .../task/SubscriberRegisterFetchTask.java | 94 ++ .../task/WatcherRegisterFetchTask.java | 123 ++ .../timertask/SyncClientsHeartbeatTask.java | 186 +++ .../server/session/store/DataManager.java | 72 + .../server/session/store/DataStore.java | 34 + .../server/session/store/Interests.java | 80 + .../server/session/store/ReSubscribers.java | 37 + .../session/store/SessionDataStore.java | 250 +++ .../session/store/SessionInterests.java | 433 ++++++ .../server/session/store/SessionWatchers.java | 229 +++ .../server/session/store/Watchers.java | 48 + .../DataChangeRequestHandlerStrategy.java | 27 + .../strategy/PublisherHandlerStrategy.java | 30 + .../ReceivedConfigDataPushTaskStrategy.java | 28 + .../ReceivedDataMultiPushTaskStrategy.java | 28 + .../strategy/SessionRegistryStrategy.java | 43 + .../strategy/SubscriberHandlerStrategy.java | 30 + .../SubscriberMultiFetchTaskStrategy.java | 35 + .../SubscriberRegisterFetchTaskStrategy.java | 34 + .../strategy/SyncConfigHandlerStrategy.java | 27 + .../strategy/TaskMergeProcessorStrategy.java | 41 + .../strategy/WatcherHandlerStrategy.java | 30 + ...faultDataChangeRequestHandlerStrategy.java | 46 + .../impl/DefaultPublisherHandlerStrategy.java | 85 ++ .../impl/DefaultPushTaskMergeProcessor.java | 65 + ...ultReceivedConfigDataPushTaskStrategy.java | 33 + ...aultReceivedDataMultiPushTaskStrategy.java | 32 + .../impl/DefaultSessionRegistryStrategy.java | 156 ++ .../DefaultSubscriberHandlerStrategy.java | 87 ++ ...faultSubscriberMultiFetchTaskStrategy.java | 244 +++ ...ltSubscriberRegisterFetchTaskStrategy.java | 169 +++ .../DefaultSyncConfigHandlerStrategy.java | 37 + .../impl/DefaultWatcherHandlerStrategy.java | 81 + .../server/session/utils/DatumUtils.java | 49 + .../src/main/resources/application.properties | 30 + .../session/src/main/resources/banner.txt | 7 + .../src/main/resources/logback-spring.xml | 301 ++++ .../server/session/DatumUtilsTest.java | 54 + .../server/session/store/BaseTest.java | 28 + .../server/session/store/DataCacheTest.java | 259 ++++ .../src/test/resources/logback-test.xml | 27 + server/store/api/pom.xml | 26 + .../sofa/registry/store/api/DBResponse.java | 160 ++ .../sofa/registry/store/api/DBService.java | 69 + .../registry/store/api/OperationStatus.java | 33 + .../store/api/annotation/RaftReference.java | 36 + .../store/api/annotation/RaftService.java | 36 + .../store/api/annotation/ReadOnLeader.java | 33 + server/store/jraft/pom.xml | 60 + .../registry/jraft/bootstrap/RaftClient.java | 252 +++ .../registry/jraft/bootstrap/RaftServer.java | 258 ++++ .../jraft/bootstrap/RaftServerConfig.java | 144 ++ .../jraft/bootstrap/ServiceStateMachine.java | 285 ++++ .../registry/jraft/command/CommandCodec.java | 56 + .../jraft/command/NotifyLeaderChange.java | 77 + .../jraft/command/ProcessRequest.java | 126 ++ .../jraft/command/ProcessResponse.java | 171 +++ .../handler/NotifyLeaderChangeHandler.java | 97 ++ .../handler/RaftClientConnectionHandler.java | 90 ++ .../handler/RaftServerConnectionHandler.java | 73 + .../jraft/handler/RaftServerHandler.java | 162 ++ .../processor/AbstractSnapshotProcess.java | 71 + .../processor/FollowerProcessListener.java | 31 + .../processor/LeaderProcessListener.java | 29 + .../jraft/processor/LeaderTaskClosure.java | 85 ++ .../registry/jraft/processor/Processor.java | 188 +++ .../jraft/processor/ProxyHandler.java | 114 ++ .../jraft/processor/SnapshotProcess.java | 35 + .../service/PersistenceDataDBService.java | 147 ++ server/store/pom.xml | 25 + test/pom.xml | 35 + .../server/test/TestRegistryMain.java | 75 + .../src/main/resources/application.properties | 43 + test/src/main/resources/logback-spring.xml | 38 + .../registry/test/BaseIntegrationTest.java | 241 +++ .../sofa/registry/test/pubsub/PubSubTest.java | 188 +++ .../test/pubsub/TempPublisherTest.java | 96 ++ .../test/resource/HealthCheckTest.java | 49 + .../resource/data/DataDigestResourceTest.java | 126 ++ .../resource/meta/MetaDigestResourceTest.java | 61 + .../resource/meta/MetaStoreResourceTest.java | 69 + .../meta/PersistentDataResourceTest.java | 59 + .../resource/meta/StopPushDataSwitchTest.java | 156 ++ .../session/ClientsOpenResourceTest.java | 54 + .../session/SessionDigestResourceTest.java | 177 +++ .../session/SessionOpenResourceTest.java | 61 + .../sofa/registry/test/sync/DataSyncTest.java | 110 ++ .../test/sync/MockSyncDataHandler.java | 124 ++ .../test/sync/SyncDataHandlerTest.java | 98 ++ tools/change_version.sh | 37 + tools/check_format.sh | 12 + tools/codestyle/HEADER | 14 + tools/codestyle/formatter.xml | 295 ++++ 669 files changed, 71701 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/Ask_Question.md create mode 100644 .github/ISSUE_TEMPLATE/Bug_Report.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 appveyor.yml create mode 100644 client/all/pom.xml create mode 100644 client/api/pom.xml create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/ConfigDataObserver.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/Configurator.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/EventBus.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/EventSubscriber.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/Publisher.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/Register.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClient.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClientConfig.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/Subscriber.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/SubscriberDataObserver.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/DuplicateException.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/RegistryClientException.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/model/ConfigData.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/model/Event.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/model/RegistryType.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/model/UserData.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/BaseRegistration.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistration.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistration.java create mode 100644 client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistration.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/DuplicateExceptionTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/RegistryClientExceptionTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/BaseRegistrationTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistrationTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistrationTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistrationTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedConfigDataTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedDataTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/core/model/ResultTest.java create mode 100644 client/api/src/test/java/com/alipay/sofa/registry/core/model/ScopeEnumTest.java create mode 100644 client/impl/pom.xml create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/auth/AuthManager.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/auth/NoopAuthManager.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/constants/ValueConstants.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/constants/VersionConstants.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/event/ConfiguratorProcessEvent.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/event/DefaultEventBus.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/event/LookoutSubscriber.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/event/SubscriberProcessEvent.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/factory/NamedThreadFactory.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/model/ConfiguratorData.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/model/SegmentData.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/AbstractInternalRegister.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigData.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigurator.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultObserverHandler.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultPublisher.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClient.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfig.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfigBuilder.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerManager.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerNode.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultSubscriber.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultUserData.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/provider/RegisterCache.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/Client.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnection.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionCloseEventProcessor.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionOpenEventProcessor.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessor.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessor.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerManager.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerNode.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/AbstractWorkerThread.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/ObserverHandler.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/SyncConfigThread.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskEvent.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskQueue.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/Worker.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/task/WorkerThread.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/util/CommonUtils.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/util/HttpClientUtils.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/util/ServerNodeParser.java create mode 100644 client/impl/src/main/java/com/alipay/sofa/registry/client/util/StringUtils.java create mode 100644 client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j/log-conf.xml create mode 100644 client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j2/log-conf.xml create mode 100644 client/impl/src/main/resources/com/alipay/sofa/registry/client/log/logback/log-conf.xml create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/MockServer.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/base/BaseTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/event/DefaultEventBusTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/event/LookoutSubscriberTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEvent.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEventSubscriber.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/model/ConfiguratorDataTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultServerManagerTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultSubscriberTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/provider/RegisterOrderTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessorTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessorTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/task/SyncConfigThreadTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/task/TaskEventTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/util/CommonUtilsTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/util/HttpClientUtilsTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/util/ServerNodeParserTest.java create mode 100644 client/impl/src/test/java/com/alipay/sofa/registry/client/util/StringUtilsTest.java create mode 100644 client/log/pom.xml create mode 100644 client/log/src/main/java/com/alipay/sofa/registry/client/log/LoggerFactory.java create mode 100644 client/log/src/test/java/com/alipay/sofa/registry/client/log/LoggerFactoryTest.java create mode 100644 client/pom.xml create mode 100644 core/pom.xml create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/constants/EventTypeConstants.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/BaseRegister.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/ConfiguratorRegister.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/DataBox.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/PublisherRegister.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedConfigData.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedData.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/RegisterResponse.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/Result.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/ScopeEnum.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/SubscriberRegister.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigRequest.java create mode 100644 core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigResponse.java create mode 100644 pom.xml create mode 100644 server/common/model/pom.xml create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/CommonResponse.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ElementType.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/GenericResponse.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/Node.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PublishType.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PushDataRetryRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBox.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBoxInputStream.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/console/PersistenceData.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/constants/ValueConstants.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/ClientOffRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/Datum.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataVersionRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyDataSyncRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyFetchDatumRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyOnlineRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/PublishDataRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SessionServerRegisterRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncData.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncDataRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/UnPublishDataRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataCenterNodes.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataNode.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataOperator.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/FetchProvideDataRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetChangeListRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetNodesRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/MetaNode.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NodeChangeResult.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NotifyProvideDataChange.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ProvideData.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ReNewNodesRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/SessionNode.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/StatusConfirmRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/CancelAddressRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataChangeRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataPushRequest.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/BaseInfo.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/DataInfo.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Publisher.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/StoreData.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Subscriber.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/URL.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Watcher.java create mode 100644 server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/WordCache.java create mode 100644 server/common/pom.xml create mode 100644 server/common/util/pom.xml create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/converter/ScopeEnumConverter.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/log/Logger.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/log/LoggerFactory.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/log/SLF4JLogger.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/metrics/ReporterUtils.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/metrics/TaskMetrics.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/net/NetUtil.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/Retryable.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/Task.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/TaskClosure.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/AcceptorExecutor.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatcher.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatchers.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskExecutors.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskHolder.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskProcessor.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TrafficShaper.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/DefaultTaskListenerManager.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskEvent.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListener.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListenerManager.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/task/scheduler/TimedSupervisorTask.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/timer/AsyncHashedWheelTimer.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/util/CollectionUtils.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/util/FileUtils.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/util/NamedThreadFactory.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/util/ParaCheckUtil.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/util/PropertySplitter.java create mode 100644 server/common/util/src/main/java/com/alipay/sofa/registry/util/VersionsMapUtils.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/converter/ScopeEnumConverterTest.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/log/LoggerTest.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/log/TestAppender.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/task/listener/TaskListenerTest.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/util/CollectionUtilsTest.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/util/FileUtilsTest.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/util/ParaCheckUtilTest.java create mode 100644 server/common/util/src/test/java/com/alipay/sofa/registry/util/PropertySplitterTest.java create mode 100644 server/common/util/src/test/resources/logback-test.xml create mode 100644 server/consistency/pom.xml create mode 100644 server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/ConsistentHash.java create mode 100644 server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashFunction.java create mode 100644 server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashNode.java create mode 100644 server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MD5HashFunction.java create mode 100644 server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MessageDigests.java create mode 100644 server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/BackupTest.java create mode 100644 server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/ConsistentHashTest.java create mode 100644 server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/MessageDigestsTest.java create mode 100644 server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/TestNode.java create mode 100755 server/distribution/data/bin/shutdown.bat create mode 100644 server/distribution/data/bin/shutdown.sh create mode 100755 server/distribution/data/bin/startup.bat create mode 100644 server/distribution/data/bin/startup.sh create mode 100644 server/distribution/data/conf/application.properties create mode 100644 server/distribution/data/conf/application.properties.example create mode 100644 server/distribution/data/distribution-data.xml create mode 100644 server/distribution/data/pom.xml create mode 100755 server/distribution/integration/bin/shutdown.bat create mode 100644 server/distribution/integration/bin/shutdown.sh create mode 100755 server/distribution/integration/bin/startup.bat create mode 100644 server/distribution/integration/bin/startup.sh create mode 100644 server/distribution/integration/conf/application.properties create mode 100644 server/distribution/integration/conf/application.properties.example create mode 100644 server/distribution/integration/distribution-integration.xml create mode 100644 server/distribution/integration/pom.xml create mode 100755 server/distribution/meta/bin/shutdown.bat create mode 100644 server/distribution/meta/bin/shutdown.sh create mode 100755 server/distribution/meta/bin/startup.bat create mode 100644 server/distribution/meta/bin/startup.sh create mode 100644 server/distribution/meta/conf/application.properties create mode 100644 server/distribution/meta/conf/application.properties.example create mode 100644 server/distribution/meta/distribution-meta.xml create mode 100644 server/distribution/meta/pom.xml create mode 100644 server/distribution/pom.xml create mode 100755 server/distribution/session/bin/shutdown.bat create mode 100644 server/distribution/session/bin/shutdown.sh create mode 100755 server/distribution/session/bin/startup.bat create mode 100644 server/distribution/session/bin/startup.sh create mode 100644 server/distribution/session/conf/application.properties create mode 100644 server/distribution/session/conf/application.properties.example create mode 100644 server/distribution/session/distribution-session.xml create mode 100644 server/distribution/session/pom.xml create mode 100644 server/distribution/version create mode 100644 server/pom.xml create mode 100644 server/remoting/api/pom.xml create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/CallbackHandler.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Channel.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/ChannelHandler.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Client.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Endpoint.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/RemotingException.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Server.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/Exchange.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/NodeExchanger.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/RequestException.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Request.java create mode 100644 server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Response.java create mode 100644 server/remoting/api/src/test/java/com/alipay/sofa/registry/remoting/RequestExceptionTest.java create mode 100644 server/remoting/bolt/pom.xml create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/AsyncUserProcessorAdapter.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannel.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannelUtil.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltClient.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltServer.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/ConnectionEventAdapter.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/SyncUserProcessorAdapter.java create mode 100644 server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/exchange/BoltExchange.java create mode 100644 server/remoting/bolt/src/test/java/com/alipay/sofa/registry/remoting/bolt/BoltServerTest.java create mode 100644 server/remoting/http/pom.xml create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyChannel.java create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyClient.java create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyJettyServer.java create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/exchange/JerseyExchange.java create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpChannelOverHttpCustom.java create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustom.java create mode 100644 server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustomFactory.java create mode 100644 server/remoting/pom.xml create mode 100644 server/server/data/pom.xml create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/DataApplication.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/CommonConfig.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBeanConfiguration.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBootstrap.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerConfig.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerInitializer.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/EnableDataServer.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/BackupTriad.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/CacheDigestTask.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerCache.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerChangeItem.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DatumCache.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/MergeResult.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/UnPublisher.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/ChangeData.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeTypeEnum.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataSourceTypeEnum.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/ClientChangeEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventCenter.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventQueue.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeScopeEnum.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/IDataChangeEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/BackUpNotifier.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/IDataChangeNotifier.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/SessionServerNotifier.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/TempPublisherNotifier.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/correction/LocalDataServerCleanHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/AcceptorStore.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/Operator.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/SyncDataService.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/AbstractAcceptorStore.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Acceptor.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/LocalAcceptorStore.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Scheduler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/StoreServiceFactory.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/SyncDataServiceImpl.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/DataServerChangeEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/EventCenter.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/LocalDataServerChangeEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/MetaServerChangeEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/StartTaskEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/AbstractEventHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/DataServerChangeEventHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/LocalDataServerChangeEventHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/MetaServerChangeEventHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/StartTaskEventHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/executor/ExecutorFactory.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataNodeStatus.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataServerNode.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/DataNodeExchanger.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/MetaNodeExchanger.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerConnectionFactory.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerNodeFactory.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/GetSyncDataHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/SyncDataCallback.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/DataSyncServerConnectionHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/FetchDataHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyDataSyncHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyFetchDatumHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyOnlineHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/SyncDataHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/AbstractTask.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ConnectionRefreshTask.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ReNewNodeTask.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractClientHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractServerHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/DefaultMetaServiceImpl.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/IMetaServerService.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/MetaServerConnectionFactory.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/ServerChangeHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/StatusConfirmHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/task/ConnectionRefreshMetaTask.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/SessionServerConnectionFactory.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/ClientDisconnectEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEventHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectTypeEnum.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/SessionServerDisconnectEvent.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardService.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardServiceImpl.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/ClientOffHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/DataServerConnectionHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataVersionsHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/PublishDataHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/SessionServerRegisterHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/UnPublishDataHandler.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/DataDigestResource.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/HealthResource.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/DelayItem.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/LocalServerStatusEnum.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/ThreadPoolExecutorDataServer.java create mode 100644 server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/TimeUtil.java create mode 100644 server/server/data/src/main/resources/application.properties create mode 100644 server/server/data/src/main/resources/banner.txt create mode 100644 server/server/data/src/main/resources/logback-spring.xml create mode 100644 server/server/data/src/test/java/com/alipay/sofa/registry/server/data/BackupTriadTest.java create mode 100644 server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TestSyncData.java create mode 100644 server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TimeUtilTest.java create mode 100644 server/server/data/src/test/resources/logback-test.xml create mode 100644 server/server/integration/pom.xml create mode 100644 server/server/integration/src/main/java/com/alipay/sofa/registry/server/integration/RegistryApplication.java create mode 100644 server/server/integration/src/main/resources/application.properties create mode 100644 server/server/integration/src/main/resources/banner.txt create mode 100644 server/server/integration/src/main/resources/logback-spring.xml create mode 100644 server/server/meta/pom.xml create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/MetaApplication.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/AbstractNodeConfigBean.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/EnableMetaServer.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerBootstrap.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfig.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfigBean.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfiguration.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerInitializerConfiguration.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfig.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfigBeanProperty.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/ServiceFactory.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/executor/ExecutorManager.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/DataNodeChangePushTaskListener.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/PersistenceDataChangeNotifyTaskListener.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/ReceiveStatusConfirmNotifyTaskListener.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/SessionNodeChangePushTaskListener.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/DataNodeService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/MetaNodeService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeOperator.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/SessionNodeService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/DataNodeServiceImpl.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/MetaNodeServiceImpl.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/SessionNodeServiceImpl.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/MetaServerRegistry.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/Registry.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/DataNodeExchanger.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaClientExchanger.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaServerExchanger.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/RaftExchanger.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/SessionNodeExchanger.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/DataConnectionHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/MetaConnectionHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/NodeConnectManager.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/SessionConnectionHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/AbstractServerHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/DataNodeHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/FetchProvideDataRequestHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetChangeListRequestHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetNodesRequestHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/ReNewNodesRequestHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/SessionNodeHandler.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeConfirmStatusService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeRepository.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/RepositoryService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/VersionRepositoryService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/annotation/RaftAnnotationBeanPostProcessor.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataConfirmStatusService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataRepositoryService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/MetaRepositoryService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionConfirmStatusService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionRepositoryService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionVersionRepositoryService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/DecisionModeResource.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/HealthResource.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaDigestResource.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaStoreResource.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/PersistentDataResource.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/StopPushDataResource.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/DataStoreService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/MetaStoreService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/RenewDecorate.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/SessionStoreService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/StoreService.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/AbstractMetaServerTask.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/Constant.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/DataNodeChangePushTask.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/MetaServerTask.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/PersistenceDataChangeNotifyTask.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/ReceiveStatusConfirmNotifyTask.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/SessionNodeChangePushTask.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/DataNodeSingleTaskProcessor.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/MetaNodeSingleTaskProcessor.java create mode 100644 server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/SessionNodeSingleTaskProcessor.java create mode 100644 server/server/meta/src/main/resources/application.properties create mode 100644 server/server/meta/src/main/resources/banner.txt create mode 100644 server/server/meta/src/main/resources/logback-spring.xml create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/BaseTest.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ConcurrentTestUtil.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/HttpTest.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ProcessResponseTest.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataNodeChangePushTaskListenerMock.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataServerConfirmTest.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/ReceiveStatusConfirmNotifyTaskMock.java create mode 100644 server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/SessionNodeChangePushTaskMock.java create mode 100644 server/server/meta/src/test/resources/application.properties create mode 100644 server/server/meta/src/test/resources/logback-test.xml create mode 100644 server/server/pom.xml create mode 100644 server/server/session/pom.xml create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/SessionApplication.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/CommonConfig.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerBootstrap.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfig.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfigBean.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfiguration.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerInitializer.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheGenerator.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheService.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumCacheGenerator.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumKey.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/EntityType.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Key.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SessionCacheService.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SubscriberResult.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Value.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/Converter.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/PublisherConverter.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/ReceivedDataConverter.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/SubscriberConverter.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/CancelDataTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchCloudTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataPushTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ProvideDataChangeFetchTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/PushTaskSender.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedConfigDataPushTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedDataMultiPushTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SessionRegisterDataTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberMultiFetchTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberRegisterFetchTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/WatcherRegisterFetchTaskListener.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/AbstractNodeManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/DataNodeManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/MetaNodeManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManagerFactory.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/RaftClientManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionNodeManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionProcessIdGenerator.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ClientNodeSingleTaskProcessor.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ConsoleSyncSingleTaskProcessor.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/DataNodeSingleTaskProcessor.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/MetaNodeSingleTaskProcessor.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeService.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeServiceImpl.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeService.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeServiceImpl.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeService.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeServiceImpl.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/Registry.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/SessionRegistry.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/ClientNodeExchanger.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/DataNodeExchanger.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/MetaNodeExchanger.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractClientHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractServerHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/CancelAddressRequestHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/ClientNodeConnectionHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataChangeRequestHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataNodeConnectionHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataPushRequestHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/MetaNodeConnectionHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NodeChangeResultHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NotifyProvideDataChangeHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/PublisherHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SubscriberHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SyncConfigHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/WatcherHandler.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/ClientsOpenResource.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/HealthResource.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionDigestResource.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionOpenResource.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/ExecutorManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/SessionThreadPoolExecutor.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/AbstractSessionTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/CancelDataTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/Constant.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchCloudTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataPushTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ProvideDataChangeFetchTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/PushTaskClosure.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedConfigDataPushTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedDataMultiPushTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionRegisterDataTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberMultiFetchTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberRegisterFetchTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/WatcherRegisterFetchTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/timertask/SyncClientsHeartbeatTask.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataManager.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataStore.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Interests.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/ReSubscribers.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionDataStore.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionInterests.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionWatchers.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Watchers.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/DataChangeRequestHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/PublisherHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedConfigDataPushTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedDataMultiPushTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SessionRegistryStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberMultiFetchTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberRegisterFetchTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SyncConfigHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/TaskMergeProcessorStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/WatcherHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultDataChangeRequestHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPublisherHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPushTaskMergeProcessor.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedConfigDataPushTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedDataMultiPushTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSessionRegistryStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberMultiFetchTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberRegisterFetchTaskStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSyncConfigHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultWatcherHandlerStrategy.java create mode 100644 server/server/session/src/main/java/com/alipay/sofa/registry/server/session/utils/DatumUtils.java create mode 100644 server/server/session/src/main/resources/application.properties create mode 100644 server/server/session/src/main/resources/banner.txt create mode 100644 server/server/session/src/main/resources/logback-spring.xml create mode 100644 server/server/session/src/test/java/com/alipay/sofa/registry/server/session/DatumUtilsTest.java create mode 100644 server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/BaseTest.java create mode 100644 server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/DataCacheTest.java create mode 100644 server/server/session/src/test/resources/logback-test.xml create mode 100644 server/store/api/pom.xml create mode 100644 server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBResponse.java create mode 100644 server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBService.java create mode 100644 server/store/api/src/main/java/com/alipay/sofa/registry/store/api/OperationStatus.java create mode 100644 server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftReference.java create mode 100644 server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftService.java create mode 100644 server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/ReadOnLeader.java create mode 100644 server/store/jraft/pom.xml create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftClient.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServer.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServerConfig.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/ServiceStateMachine.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/CommandCodec.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/NotifyLeaderChange.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessRequest.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessResponse.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/NotifyLeaderChangeHandler.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftClientConnectionHandler.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerConnectionHandler.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerHandler.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/AbstractSnapshotProcess.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/FollowerProcessListener.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderProcessListener.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderTaskClosure.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/Processor.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/ProxyHandler.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/SnapshotProcess.java create mode 100644 server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/service/PersistenceDataDBService.java create mode 100644 server/store/pom.xml create mode 100644 test/pom.xml create mode 100644 test/src/main/java/com/alipay/sofa/registry/server/test/TestRegistryMain.java create mode 100644 test/src/main/resources/application.properties create mode 100644 test/src/main/resources/logback-spring.xml create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/BaseIntegrationTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/pubsub/PubSubTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/pubsub/TempPublisherTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/HealthCheckTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/data/DataDigestResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaDigestResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaStoreResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/meta/PersistentDataResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/meta/StopPushDataSwitchTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/session/ClientsOpenResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionDigestResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionOpenResourceTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/sync/DataSyncTest.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/sync/MockSyncDataHandler.java create mode 100644 test/src/test/java/com/alipay/sofa/registry/test/sync/SyncDataHandlerTest.java create mode 100644 tools/change_version.sh create mode 100644 tools/check_format.sh create mode 100644 tools/codestyle/HEADER create mode 100644 tools/codestyle/formatter.xml diff --git a/.github/ISSUE_TEMPLATE/Ask_Question.md b/.github/ISSUE_TEMPLATE/Ask_Question.md new file mode 100644 index 000000000..ea5e819a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Ask_Question.md @@ -0,0 +1,27 @@ +--- +name: Ask Question +about: Ask a question about usage or feature + +--- + +### Your question + +describe your question clearly + +### Your scenes + +describe your use scenes (why need this feature) + +### Your advice + +describe the advice or solution you'd like + +### Environment + +- SOFARegistry version: +- JVM version (e.g. `java -version`): +- OS version (e.g. `uname -a`): +- Maven version: +- IDE version: + + diff --git a/.github/ISSUE_TEMPLATE/Bug_Report.md b/.github/ISSUE_TEMPLATE/Bug_Report.md new file mode 100644 index 000000000..05c0d48f0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_Report.md @@ -0,0 +1,25 @@ +--- +name: Bug Report +about: Create a report to help us improve + +--- + +### Describe the bug + +A clear and concise description of what the bug is. + +### Expected behavior + +### Actual behavior + +### Steps to reproduce + +### Minimal yet complete reproducer code (or GitHub URL to code) + +### Environment + +- SOFARegistry version: +- JVM version (e.g. `java -version`): +- OS version (e.g. `uname -a`): +- Maven version: +- IDE version: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..999fba75c --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +### Motivation: + +Explain the context, and why you're making that change. +To make others understand what is the problem you're trying to solve. + +### Modification: + +Describe the idea and modifications you've done. + +### Result: + +Fixes #. + +If there is no issue then describe the changes introduced by this PR. diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..16bfcdc69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Maven (examples) +target +dependency-reduced-pom.xml + +# IntelliJ IDEA +.idea +*.iml + +# Eclipse +.classpath +.project +.settings + +# OS X +.DS_Store + +# log +logs/ +*.log \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..cb53cacfe --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: java +sudo: false + +jdk: +- oraclejdk8 + +install: +- mvn clean install -DskipTests -B -V +- mvn test + +script: +- sh ./tools/check_format.sh + +after_success: +- bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..26c62dba8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 Ant Small and Micro Financial Services Group Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..ef73f19d2 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# SOFARegistry + +![license](https://img.shields.io/badge/license-Apache--2.0-green.svg) + +SOFARegistry 是蚂蚁金服开源的一个生产级、高时效、高可用的服务注册中心。SOFARegistry 最早源自于淘宝的 ConfigServer,十年来,随着蚂蚁金服的业务发展,注册中心架构已经演进至第五代。目前 SOFARegistry 不仅全面服务于蚂蚁金服的自有业务,还随着蚂蚁金融科技服务众多合作伙伴,同时也兼容开源生态。SOFARegistry 采用 AP 架构,支持秒级时效性推送,同时采用分层架构支持无限水平扩展。 + +## 功能特性 + +- 支持服务发布与服务订阅 +- 支持服务变更时的主动推送 +- 丰富的 REST 接口 +- 采用分层架构及数据分片,支持海量连接及海量数据 +- 支持多副本备份,保证数据高可用 +- 基于 [SOFABolt](https://github.com/alipay/sofa-bolt) 通信框架,服务上下线秒级通知 +- AP 架构,保证网络分区下的可用性 + + +## 需要 + +编译需要 JDK 8 及以上、Maven 3.2.5 及以上。 + +运行需要 JDK 6 及以上,服务端运行需要 JDK 8及以上。 + +## 文档 + +- [快速开始](https://www.sofastack.tech/sofa-registry/docs/Server-QuickStart) +- [开发手册](https://www.sofastack.tech/sofa-registry/docs/JAVA-SDK)  +- [运维手册](https://www.sofastack.tech/sofa-registry/docs/Deployment)  +- [发布历史](https://www.sofastack.tech/sofa-registry/docs/ReleaseNotes)  +- [发展路线](https://www.sofastack.tech/sofa-registry/docs/RoadMap)  + + +## 贡献 + +[如何参与 SOFARegistry 代码贡献](https://www.sofastack.tech/sofa-registry/docs/Contributing)  + + +## 致谢 + +SOFARegistry 最早源于阿里内部的 ConfigServer,感谢毕玄创造了 ConfigServer,使 SOFARegistry 的发展有了良好的基础。同时,部分代码参考了 Netflix 的 [Eureka](https://github.com/Netflix/eureka),感谢 Netflix 开源了如此优秀框架。 + +## 开源许可 + +SOFARPC 基于 [Apache License 2.0](https://github.com/alipay/sofa-rpc/blob/master/LICENSE) 协议,SOFARPC 依赖了一些三方组件,它们的开源协议参见[依赖组件版权说明](http://www.sofastack.tech/sofa-rpc/docs/NOTICE)。 diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..80a0937b8 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,30 @@ +# build version +version: '{build}' + +# environment settings +environment: + matrix: + - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 + +platform: x64 + +# install required tools (java, maven) +install: + - cmd: echo %JAVA_HOME% + - cmd: echo %M2_HOME% + +# Do not build on tags +skip_tags: true + +# build and install artifacts +build_script: + - mvn clean install -DskipTests + +# verify artifacts +test_script: + - mvn test + +# preserve dependencies between builds +cache: + - C:\maven\ + - C:\Users\appveyor\.m2 \ No newline at end of file diff --git a/client/all/pom.xml b/client/all/pom.xml new file mode 100644 index 000000000..6cf954072 --- /dev/null +++ b/client/all/pom.xml @@ -0,0 +1,273 @@ + + + 4.0.0 + + com.alipay.sofa + registry-client-all + 5.2.0-SNAPSHOT + + ${project.groupId}:${project.artifactId} + http://github.com/alipay/sofa-registry + A high-performance, high-extensibility, production-level Java Registry framework. + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + The Ant Financial + http://www.antfin.com/ + + + + + Hui Wang + shangyu.wh@alibaba-inc.com + Ant Financial + + + KeZhu Wu + kezhu.wukz@antfin.com + Ant Financial + + + Jie Cao + caojie.cj@antfin.com + Ant Financial + + + + + scm:git:git://github.com/alipay/sofa-registry.git + scm:git:ssh://github.com/alipay/sofa-registry.git + http://github.com/alipay/sofa-registry/tree/master + + + + + true + true + 1.6 + 1.6 + UTF-8 + 1.4.6 + 3.3.4 + 1.5.2 + 1.0.12 + 4.1.25.Final + 1.7.21 + ../../ + + + + + com.alipay.sofa + registry-core + ${project.version} + + + com.alipay.sofa + registry-client-api + ${project.version} + + + com.alipay.sofa + registry-client-log + ${project.version} + + + com.alipay.sofa + registry-client-impl + ${project.version} + + + com.alipay.sofa + bolt + ${bolt.version} + + + com.alipay.sofa + hessian + ${hessian.version} + + + com.alipay.sofa.common + sofa-common-tools + ${sofa.common.tools.version} + + + com.alipay.sofa.lookout + lookout-api + ${lookout.version} + + + io.netty + netty-all + ${netty.version} + + + org.slf4j + slf4j-api + ${slf4j.version} + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + false + true + + true + true + + + ${maven.build.timestamp} + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + package + + shade + + + true + false + false + true + + + com.alipay.sofa:registry-core + com.alipay.sofa:registry-client-api + com.alipay.sofa:registry-client-log + com.alipay.sofa:registry-client-impl + + + + + + + + META-INF/spring.handlers + + + META-INF/spring.schemas + + + + pom.xml + + + pom.properties + + + + + *:* + + META-INF/maven/** + + + + + + + + + + + + + release + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + ${project.build.sourceEncoding} + true + true + false + true + true + true + + com.alipay.sofa:registry-core + com.alipay.sofa:registry-client-api + com.alipay.sofa:registry-client-log + com.alipay.sofa:registry-client-impl + + + + + attach-javadocs + + jar + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + false + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + + diff --git a/client/api/pom.xml b/client/api/pom.xml new file mode 100644 index 000000000..de15a5de3 --- /dev/null +++ b/client/api/pom.xml @@ -0,0 +1,53 @@ + + + + com.alipay.sofa + registry-client-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-client-api + + + + 1.6 + 1.6 + UTF-8 + ../../ + + + + + com.alipay.sofa + registry-core + + + junit + junit + test + + + + + + + org.apache.maven.plugins + maven-install-plugin + + ${module.install.skip} + + + + org.apache.maven.plugins + maven-deploy-plugin + + ${module.deploy.skip} + + + + + diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/ConfigDataObserver.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/ConfigDataObserver.java new file mode 100644 index 000000000..97d92b794 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/ConfigDataObserver.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.ConfigData; + +/** + * The interface Persistence data observer. + * @author zhuoyu.sjw + * @version $Id : ConfigDataObserver.java, v 0.1 2018-04-17 17:02 zhuoyu.sjw Exp $$ + */ +public interface ConfigDataObserver { + + /** + * Handle data. + * + * @param dataId the data id + * @param configData the persistence data + */ + void handleData(String dataId, ConfigData configData); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/Configurator.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Configurator.java new file mode 100644 index 000000000..e9641f713 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Configurator.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.ConfigData; + +/** + * The interface Configurator. + * @author zhuoyu.sjw + * @version $Id : Configurator.java, v 0.1 2018-04-17 17:26 zhuoyu.sjw Exp $$ + */ +public interface Configurator extends Register { + + /** + * Gets data observer. + * + * @return the data observer + */ + ConfigDataObserver getDataObserver(); + + /** + * Sets config data observer. + * + * @param configDataObserver the config data observer + */ + void setDataObserver(ConfigDataObserver configDataObserver); + + /** + * Peek data config data. + * + * @return the config data + */ + ConfigData peekData(); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/EventBus.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/EventBus.java new file mode 100644 index 000000000..f9ded1234 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/EventBus.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.Event; + +/** + * The interface Event bus. + * @author zhuoyu.sjw + * @version $Id : EventBus.java, v 0.1 2018-07-12 21:11 zhuoyu.sjw Exp $$ + */ +public interface EventBus { + + /** + * Is enable boolean. + * + * @return the boolean + */ + boolean isEnable(); + + /** + * Is enable boolean. + * + * @param eventClass the event class + * @return the boolean + */ + boolean isEnable(Class eventClass); + + /** + * Register. + * + * @param eventClass the event class + * @param eventSubscriber the event subscriber + */ + void register(Class eventClass, EventSubscriber eventSubscriber); + + /** + * Un register. + * + * @param eventClass the event class + * @param eventSubscriber the event subscriber + */ + void unRegister(Class eventClass, EventSubscriber eventSubscriber); + + /** + * Post event. + * + * @param event the event + */ + void post(final Event event); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/EventSubscriber.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/EventSubscriber.java new file mode 100644 index 000000000..ead4f7ddf --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/EventSubscriber.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.Event; + +/** + * The interface Event subscriber. + * @author zhuoyu.sjw + * @version $Id : EventSubscriber.java, v 0.1 2018-07-12 21:12 zhuoyu.sjw Exp $$ + */ +public interface EventSubscriber { + + /** + * Is sync boolean. + * + * @return the boolean + */ + boolean isSync(); + + /** + * On event. + * + * @param event the event + */ + void onEvent(Event event); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/Publisher.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Publisher.java new file mode 100644 index 000000000..45330b543 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Publisher.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +/** + * The interface Publisher. + * + * @author zhuoyu.sjw + * @version $Id : Publisher.java, v 0.1 2017-11-22 16:09 zhuoyu.sjw Exp $$ + */ +public interface Publisher extends Register { + + /** + * Publish. + * + * @param data the data + */ + void republish(String... data); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/Register.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Register.java new file mode 100644 index 000000000..832fdcb77 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Register.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +/** + * The interface Register. + * @author zhuoyu.sjw + * @version $Id : Register.java, v 0.1 2017-11-22 16:00 zhuoyu.sjw Exp $$ + */ +public interface Register { + + /** + * Reset. + */ + void reset(); + + /** + * Is registered boolean. + * + * @return the boolean + */ + boolean isRegistered(); + + /** + * Unregister. + */ + void unregister(); + + /** + * Gets data id. + * + * @return String data id + */ + String getDataId(); + + /** + * Gets group. + * + * @return the group + */ + String getGroup(); + + /** + * Gets regist id. + * + * @return the regist id + */ + String getRegistId(); + + /** + * Is enabled boolean. + * + * @return boolean boolean + */ + boolean isEnabled(); + + /** + * Gets timestamp. + * + * @return the timestamp + */ + long getTimestamp(); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClient.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClient.java new file mode 100644 index 000000000..29d3ac8cc --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClient.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.ConfiguratorRegistration; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; + +/** + * The interface Registry client. + * @author zhuoyu.sjw + * @version $Id : RegistryClient.java, v 0.1 2017-11-20 18:16 zhuoyu.sjw Exp $$ + */ +public interface RegistryClient { + + /** + * Register publisher. + * + * @param registration the registration + * @param data the data + * @return the publisher + */ + Publisher register(PublisherRegistration registration, String... data); + + /** + * Register multi subscriber multi. + * + * @param registration the registration + * @return the subscriber multi + */ + Subscriber register(SubscriberRegistration registration); + + /** + * Register configurator. + * + * @param registration the registration + * @return the configurator + */ + Configurator register(ConfiguratorRegistration registration); + + /** + * Unregister all publishers or subscribers belong to dataId. + * + * @param dataId the data id + * @param group registration group, use default group if null + * @param registryType the registry type, publisher or subscriber + * @return unregister total registers + */ + int unregister(String dataId, String group, RegistryType registryType); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClientConfig.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClientConfig.java new file mode 100644 index 000000000..6097d53ac --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/RegistryClientConfig.java @@ -0,0 +1,172 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +/** + * The interface Registry client config. + * @author zhuoyu.sjw + * @version $Id : RegistryClientConfig.java, v 0.1 2017-11-23 19:52 zhuoyu.sjw Exp $$ + */ +public interface RegistryClientConfig { + + /** + * Gets env. + * + * @return the env + */ + String getEnv(); + + /** + * Gets instance id. + * + * @return the instance id + */ + String getInstanceId(); + + /** + * Gets cell. + * + * @return the cell + */ + String getZone(); + + /** + * Gets registry endpoint. + * + * @return the registry endpoint + */ + String getRegistryEndpoint(); + + /** + * Gets registry endpoint port. + * + * @return the registry endpoint port + */ + int getRegistryEndpointPort(); + + /** + * Gets data center. + * + * @return the data center + */ + String getDataCenter(); + + /** + * Gets app name. + * + * @return the app name + */ + String getAppName(); + + /** + * Gets connect timeout. + * + * @return the connect timeout + */ + int getConnectTimeout(); + + /** + * Gets socket timeout. + * + * @return the socket timeout + */ + int getSocketTimeout(); + + /** + * Gets invoke timeout. + * + * @return the invoke timeout + */ + int getInvokeTimeout(); + + /** + * Gets recheck interval. + * + * @return the recheck interval + */ + int getRecheckInterval(); + + /** + * Gets observer thread core size. + * + * @return the observer thread core size + */ + int getObserverThreadCoreSize(); + + /** + * Gets observer thread max size. + * + * @return the observer thread max size + */ + int getObserverThreadMaxSize(); + + /** + * Gets observer thread queue length. + * + * @return the observer thread queue length + */ + int getObserverThreadQueueLength(); + + /** + * Gets observer callback timeout. + * + * @return the observer callback timeout + */ + int getObserverCallbackTimeout(); + + /** + * Gets sync config retry interval. + * + * @return the sync config retry interval + */ + int getSyncConfigRetryInterval(); + + /** + * Gets access key. + * + * @return the access key + */ + String getAccessKey(); + + /** + * Gets secret key. + * + * @return the secret key + */ + String getSecretKey(); + + /** + * Gets algorithm. + * + * @return the algorithm + */ + String getAlgorithm(); + + /** + * Gets auth cache interval. + * + * @return the auth cache interval + */ + long getAuthCacheInterval(); + + /** + * Is event bus enable boolean. + * + * @return the boolean + */ + boolean isEventBusEnable(); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/Subscriber.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Subscriber.java new file mode 100644 index 000000000..fbcae869f --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/Subscriber.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.core.model.ScopeEnum; + +/** + * The interface Subscriber multi. + * + * @author zhuoyu.sjw + * @version $Id : Subscriber.java, v 0.1 2017-11-23 14:35 zhuoyu.sjw Exp $$ + */ +public interface Subscriber extends Register { + + /** + * Gets data observer. + * + * @return the data observer + */ + SubscriberDataObserver getDataObserver(); + + /** + * Sets data observer. + * + * @param observer the observer + */ + void setDataObserver(SubscriberDataObserver observer); + + /** + * Peek data user data multi. + * + * @return the user data multi + */ + UserData peekData(); + + /** + * Gets scope enum. + * + * @return the scope enum + */ + ScopeEnum getScopeEnum(); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/SubscriberDataObserver.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/SubscriberDataObserver.java new file mode 100644 index 000000000..d90c33995 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/SubscriberDataObserver.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api; + +import com.alipay.sofa.registry.client.api.model.UserData; + +/** + * The interface Subscriber data observer multi. + * + * @author zhuoyu.sjw + * @version $Id : SubscriberDataObserver.java, v 0.1 2017-11-23 15:16 zhuoyu.sjw Exp $$ + */ +public interface SubscriberDataObserver { + + /** + * Handle data. + * + * @param dataId the data id + * @param data the data + */ + void handleData(String dataId, UserData data); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/DuplicateException.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/DuplicateException.java new file mode 100644 index 000000000..3b77f4a10 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/DuplicateException.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.exception; + +/** + * The type Duplicate exception. + * @author zhuoyu.sjw + * @version $Id : DuplicateException.java, v 0.1 2017-11-30 19:46 zhuoyu.sjw Exp $$ + */ +public class DuplicateException extends IllegalArgumentException { + + /** UID */ + private static final long serialVersionUID = 167969795120169890L; + + /** + * Instantiates a new Duplicate exception. + */ + public DuplicateException() { + } + + /** + * Instantiates a new Duplicate exception. + * + * @param s the s + */ + public DuplicateException(String s) { + super(s); + } + + /** + * Instantiates a new Duplicate exception. + * + * @param message the message + * @param cause the cause + */ + public DuplicateException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Instantiates a new Duplicate exception. + * + * @param cause the cause + */ + public DuplicateException(Throwable cause) { + super(cause); + } +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/RegistryClientException.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/RegistryClientException.java new file mode 100644 index 000000000..5b4c85897 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/exception/RegistryClientException.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.exception; + +/** + * The type Registry client exception. + * @author zhuoyu.sjw + * @version $Id : RegistryClientException.java, v 0.1 2017-11-30 19:43 zhuoyu.sjw Exp $$ + */ +public class RegistryClientException extends RuntimeException { + + /** UID */ + private static final long serialVersionUID = -1068018180829676315L; + + /** + * Instantiates a new Registry client exception. + */ + public RegistryClientException() { + } + + /** + * Instantiates a new Registry client exception. + * + * @param message the message + */ + public RegistryClientException(String message) { + super(message); + } + + /** + * Instantiates a new Registry client exception. + * + * @param message the message + * @param cause the cause + */ + public RegistryClientException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Instantiates a new Registry client exception. + * + * @param cause the cause + */ + public RegistryClientException(Throwable cause) { + super(cause); + } +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/ConfigData.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/ConfigData.java new file mode 100644 index 000000000..cf4306044 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/ConfigData.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.model; + +/** + * The interface Persistence data. + * @author zhuoyu.sjw + * @version $Id : ConfigData.java, v 0.1 2018-04-17 17:15 zhuoyu.sjw Exp $$ + */ +public interface ConfigData { + + /** + * Gets data. + * + * @return the data + */ + String getData(); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/Event.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/Event.java new file mode 100644 index 000000000..3c8cdbf2b --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/Event.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.model; + +/** + * The interface Event. + * @author zhuoyu.sjw + * @version $Id : Event.java, v 0.1 2018-07-12 21:10 zhuoyu.sjw Exp $$ + */ +public interface Event { +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/RegistryType.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/RegistryType.java new file mode 100644 index 000000000..057ba3be8 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/RegistryType.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.model; + +/** + * + * @author zhuoyu.sjw + * @version $Id: RegistryType.java, v 0.1 2018-03-13 15:22 zhuoyu.sjw Exp $$ + */ +public enum RegistryType { + + PUBLISHER, SUBSCRIBER, CONFIGURATOR +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/UserData.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/UserData.java new file mode 100644 index 000000000..46cc2eabd --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/model/UserData.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.model; + +import java.util.List; +import java.util.Map; + +/** + * The type User data. + * + * @author zhuoyu.sjw + * @version $Id : UserData.java, v 0.1 2017-11-23 14:37 zhuoyu.sjw Exp $$ + */ +public interface UserData { + + /** + * Getter method for property zoneData. + * + * @return property value of zoneData + */ + Map> getZoneData(); + + /** + * Gets local zone. + * + * @return the local zone + */ + String getLocalZone(); +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/BaseRegistration.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/BaseRegistration.java new file mode 100644 index 000000000..c7e10bf7f --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/BaseRegistration.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +/** + * Base registration. + * @author yeqing.yq + * @version $Id : BaseRegistration.java, v 0.1 2018-09-04 11:36 yeqing.yq Exp $$ + */ +public class BaseRegistration { + + protected String dataId; + + protected String group; + + protected String appName; + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = dataId; + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Getter method for property appName. + * + * @return property value of appName + */ + public String getAppName() { + return appName; + } + + /** + * Setter method for property appName. + * + * @param appName value to be assigned to property appName + */ + public void setAppName(String appName) { + this.appName = appName; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "BaseRegistration{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + + ", appName='" + appName + '\'' + '}'; + } +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistration.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistration.java new file mode 100644 index 000000000..7e44be10b --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistration.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +import com.alipay.sofa.registry.client.api.ConfigDataObserver; + +/** + * The type Configurator registration. + * @author zhuoyu.sjw + * @version $Id : ConfiguratorRegistration.java, v 0.1 2018-04-20 11:36 zhuoyu.sjw Exp $$ + */ +public class ConfiguratorRegistration extends BaseRegistration { + + private ConfigDataObserver configDataObserver; + + /** + * Instantiates a new Configurator registration. + * + * @param dataId the data id + * @param configDataObserver the config data observer + */ + public ConfiguratorRegistration(String dataId, ConfigDataObserver configDataObserver) { + this.dataId = dataId; + this.configDataObserver = configDataObserver; + } + + /** + * Getter method for property configDataObserver. + * + * @return property value of configDataObserver + */ + public ConfigDataObserver getConfigDataObserver() { + return configDataObserver; + } + + /** + * Setter method for property configDataObserver. + * + * @param configDataObserver value to be assigned to property configDataObserver + */ + public void setConfigDataObserver(ConfigDataObserver configDataObserver) { + this.configDataObserver = configDataObserver; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "ConfiguratorRegistration{" + "dataId='" + dataId + '\'' + ", group='" + group + + '\'' + ", appName='" + appName + '\'' + '}'; + } +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistration.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistration.java new file mode 100644 index 000000000..8194b77c5 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistration.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +/** + * The type Publisher registration. + * + * @author zhuoyu.sjw + * @version $Id : PublisherRegistration.java, v 0.1 2017-11-23 15:39 zhuoyu.sjw Exp $$ + */ +public class PublisherRegistration extends BaseRegistration { + + /** + * Instantiates a new Publisher registration. + * + * @param dataId the data id + */ + public PublisherRegistration(String dataId) { + this.dataId = dataId; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "PublisherRegistration{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + + ", appName='" + appName + '\'' + '}'; + } +} diff --git a/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistration.java b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistration.java new file mode 100644 index 000000000..83037d3c9 --- /dev/null +++ b/client/api/src/main/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistration.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.core.model.ScopeEnum; + +/** + * The type Subscriber registration. + * + * @author zhuoyu.sjw + * @version $Id : SubscriberRegistration.java, v 0.1 2017-11-23 17:05 zhuoyu.sjw Exp $$ + */ +public class SubscriberRegistration extends BaseRegistration { + + private ScopeEnum scopeEnum; + + private SubscriberDataObserver subscriberDataObserver; + + /** + * Instantiates a new Subscriber registration. + * + * @param dataId the data id + * @param subscriberDataObserver the subscriber data observer + */ + public SubscriberRegistration(String dataId, SubscriberDataObserver subscriberDataObserver) { + this.dataId = dataId; + this.subscriberDataObserver = subscriberDataObserver; + } + + /** + * Getter method for property scopeEnum. + * + * @return property value of scopeEnum + */ + public ScopeEnum getScopeEnum() { + return scopeEnum; + } + + /** + * Setter method for property scopeEnum. + * + * @param scopeEnum value to be assigned to property scopeEnum + */ + public void setScopeEnum(ScopeEnum scopeEnum) { + this.scopeEnum = scopeEnum; + } + + /** + * Getter method for property subscriberDataObserver. + * + * @return property value of subscriberDataObserver + */ + public SubscriberDataObserver getSubscriberDataObserver() { + return subscriberDataObserver; + } + + /** + * Setter method for property subscriberDataObserver. + * + * @param subscriberDataObserver value to be assigned to property subscriberDataObserver + */ + public void setSubscriberDataObserver(SubscriberDataObserver subscriberDataObserver) { + this.subscriberDataObserver = subscriberDataObserver; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "SubscriberRegistration{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + + ", appName='" + appName + '\'' + ", scopeEnum=" + scopeEnum + + ", subscriberDataObserver=" + subscriberDataObserver + '}'; + } +} diff --git a/client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/DuplicateExceptionTest.java b/client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/DuplicateExceptionTest.java new file mode 100644 index 000000000..6fc2e74a9 --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/DuplicateExceptionTest.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.exception; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class DuplicateExceptionTest { + + @Test + public void testConstruct() { + DuplicateException exception = new DuplicateException(); + Assert.assertNull(exception.getMessage()); + + exception = new DuplicateException("1"); + Assert.assertEquals("1", exception.getMessage()); + + RuntimeException runtimeException = new RuntimeException("xxx"); + exception = new DuplicateException(runtimeException); + Assert.assertEquals("java.lang.RuntimeException: xxx", exception.getMessage()); + Assert.assertEquals(runtimeException, exception.getCause()); + + exception = new DuplicateException("1", runtimeException); + Assert.assertEquals("1", exception.getMessage()); + Assert.assertEquals(runtimeException, exception.getCause()); + } + +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/RegistryClientExceptionTest.java b/client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/RegistryClientExceptionTest.java new file mode 100644 index 000000000..7d45f61f9 --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/client/api/exception/RegistryClientExceptionTest.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.exception; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class RegistryClientExceptionTest { + + @Test + public void testConstruct() { + RegistryClientException exception = new RegistryClientException(); + Assert.assertNull(exception.getMessage()); + + exception = new RegistryClientException("1"); + Assert.assertEquals("1", exception.getMessage()); + + RuntimeException runtimeException = new RuntimeException("xxx"); + exception = new RegistryClientException(runtimeException); + Assert.assertEquals("java.lang.RuntimeException: xxx", exception.getMessage()); + Assert.assertEquals(runtimeException, exception.getCause()); + + exception = new RegistryClientException("1", runtimeException); + Assert.assertEquals("1", exception.getMessage()); + Assert.assertEquals(runtimeException, exception.getCause()); + } +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/BaseRegistrationTest.java b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/BaseRegistrationTest.java new file mode 100644 index 000000000..dcca6ba6e --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/BaseRegistrationTest.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class BaseRegistrationTest { + + @Test + public void testAll() { + BaseRegistration registration = new BaseRegistration(); + registration.setAppName("app"); + registration.setDataId("dataId"); + registration.setGroup("group"); + Assert.assertEquals("app", registration.getAppName()); + Assert.assertEquals("dataId", registration.getDataId()); + Assert.assertEquals("group", registration.getGroup()); + Assert.assertEquals("BaseRegistration{dataId='dataId', group='group', appName='app'}", + registration.toString()); + } + +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistrationTest.java b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistrationTest.java new file mode 100644 index 000000000..74f7889bc --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/ConfiguratorRegistrationTest.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +import com.alipay.sofa.registry.client.api.ConfigDataObserver; +import com.alipay.sofa.registry.client.api.model.ConfigData; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class ConfiguratorRegistrationTest { + + @Test + public void testAll() { + ConfiguratorRegistration registration = new ConfiguratorRegistration("xxx", null); + Assert.assertEquals("xxx", registration.getDataId()); + Assert.assertNull(registration.getConfigDataObserver()); + registration.setConfigDataObserver(new ConfigDataObserver() { + @Override + public void handleData(String dataId, ConfigData configData) { + + } + }); + Assert.assertNotNull(registration.getConfigDataObserver()); + Assert.assertTrue(registration.toString().contains("xxx")); + } +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistrationTest.java b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistrationTest.java new file mode 100644 index 000000000..bf37f97db --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/PublisherRegistrationTest.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class PublisherRegistrationTest { + + @Test + public void testAll() { + PublisherRegistration registration = new PublisherRegistration("xxx"); + Assert.assertEquals("xxx", registration.getDataId()); + Assert.assertTrue(registration.toString().contains("xxx")); + } +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistrationTest.java b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistrationTest.java new file mode 100644 index 000000000..2cfb98e35 --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/client/api/registration/SubscriberRegistrationTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.api.registration; + +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class SubscriberRegistrationTest { + + @Test + public void testAll() { + SubscriberRegistration registration = new SubscriberRegistration("xxx", null); + Assert.assertEquals("xxx", registration.getDataId()); + Assert.assertNull(registration.getSubscriberDataObserver()); + registration.setSubscriberDataObserver(new SubscriberDataObserver() { + @Override + public void handleData(String dataId, UserData data) { + + } + }); + Assert.assertNotNull(registration.getSubscriberDataObserver()); + registration.setScopeEnum(ScopeEnum.dataCenter); + Assert.assertEquals(ScopeEnum.dataCenter, registration.getScopeEnum()); + Assert.assertTrue(registration.toString().contains("xxx")); + } +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedConfigDataTest.java b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedConfigDataTest.java new file mode 100644 index 000000000..72bf3a01f --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedConfigDataTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; + +/** + * @author GengZhang + */ +public class ReceivedConfigDataTest { + + @Test + public void testAll() { + ReceivedConfigData data = new ReceivedConfigData(); + data.setDataId("dataIdd"); + data.setGroup("groupp"); + data.setInstanceId("instanceIdd"); + data.setConfiguratorRegistIds(Arrays.asList("id1", "id2")); + data.setDataBox(new DataBox()); + data.setVersion(1234L); + Assert.assertEquals("dataIdd", data.getDataId()); + Assert.assertEquals("groupp", data.getGroup()); + Assert.assertEquals("instanceIdd", data.getInstanceId()); + Assert.assertEquals(2, data.getConfiguratorRegistIds().size()); + Assert.assertNotNull(data.getDataBox()); + Assert.assertEquals(1234L, (long) data.getVersion()); + Assert.assertTrue(data.toString().contains("instanceIdd")); + } + +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedDataTest.java b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedDataTest.java new file mode 100644 index 000000000..1fe5e45e1 --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ReceivedDataTest.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +/** + * @author GengZhang + */ +public class ReceivedDataTest { + + @Test + public void testAll() { + + ReceivedData data = new ReceivedData(); + data.setDataId("dataIdd"); + data.setGroup("groupp"); + data.setInstanceId("instanceIdd"); + data.setSubscriberRegistIds(Arrays.asList("id1", "id2")); + data.setLocalZone("local"); + data.setScope("zone"); + data.setData(new HashMap>()); + data.setSegment("seg1"); + data.setVersion(1234L); + Assert.assertEquals("dataIdd", data.getDataId()); + Assert.assertEquals("groupp", data.getGroup()); + Assert.assertEquals("instanceIdd", data.getInstanceId()); + Assert.assertEquals(2, data.getSubscriberRegistIds().size()); + Assert.assertEquals("zone", data.getScope()); + Assert.assertEquals("seg1", data.getSegment()); + Assert.assertEquals("local", data.getLocalZone()); + Assert.assertEquals(1234L, (long) data.getVersion()); + Assert.assertEquals(0, data.getData().size()); + Assert.assertTrue(data.toString().contains("instanceIdd")); + + ReceivedData data1 = new ReceivedData(null, null, null, null, null, null, null); + Assert.assertNull(data1.getVersion()); + } +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/core/model/ResultTest.java b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ResultTest.java new file mode 100644 index 000000000..af5fc00f0 --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ResultTest.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class ResultTest { + + @Test + public void testAll() { + Result result = new Result(); + result.setSuccess(false); + result.setMessage("xxx"); + Assert.assertFalse(result.isSuccess()); + Assert.assertEquals("xxx", result.getMessage()); + Assert.assertTrue(result.toString().contains("xxx")); + } +} \ No newline at end of file diff --git a/client/api/src/test/java/com/alipay/sofa/registry/core/model/ScopeEnumTest.java b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ScopeEnumTest.java new file mode 100644 index 000000000..a0d600872 --- /dev/null +++ b/client/api/src/test/java/com/alipay/sofa/registry/core/model/ScopeEnumTest.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class ScopeEnumTest { + + @Test + public void contains() { + Assert.assertTrue(ScopeEnum.contains("zone")); + Assert.assertFalse(ScopeEnum.contains("xxxx")); + } +} \ No newline at end of file diff --git a/client/impl/pom.xml b/client/impl/pom.xml new file mode 100644 index 000000000..c742945b8 --- /dev/null +++ b/client/impl/pom.xml @@ -0,0 +1,102 @@ + + + + com.alipay.sofa + registry-client-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-client-impl + + + ../../ + + + + + com.alipay.sofa + registry-core + + + com.alipay.sofa + registry-client-api + + + com.alipay.sofa + registry-client-log + + + com.alipay.sofa + bolt + + + com.alipay.sofa + hessian + + + io.netty + netty-all + + + org.slf4j + slf4j-api + + + com.alipay.sofa.common + sofa-common-tools + + + com.alipay.sofa.lookout + lookout-api + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + org.mockito + mockito-core + test + + + org.powermock + powermock-module-junit4 + test + + + org.powermock + powermock-api-mockito + test + + + + + + + + org.apache.maven.plugins + maven-install-plugin + + ${module.install.skip} + + + + org.apache.maven.plugins + maven-deploy-plugin + + ${module.deploy.skip} + + + + + diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/auth/AuthManager.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/auth/AuthManager.java new file mode 100644 index 000000000..ed346bd3f --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/auth/AuthManager.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.auth; + +import com.alipay.sofa.registry.core.model.BaseRegister; + +import java.util.Map; + +/** + * The interface Auth manager. + * @author zhuoyu.sjw + * @version $Id : AuthManager.java, v 0.1 2018-04-18 12:12 zhuoyu.sjw Exp $$ + */ +public interface AuthManager { + + /** + * Gets auth content. + * + * @param register the register + * @return the auth content + */ + Map getAuthContent(BaseRegister register); +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/auth/NoopAuthManager.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/auth/NoopAuthManager.java new file mode 100644 index 000000000..3f03e5de0 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/auth/NoopAuthManager.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.auth; + +import com.alipay.sofa.registry.core.model.BaseRegister; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author zhuoyu.sjw + * @version $Id: NoopAuthManager.java, v 0.1 2018-04-18 12:13 zhuoyu.sjw Exp $$ + */ +public final class NoopAuthManager implements AuthManager { + + public static final AuthManager INSTANCE = new NoopAuthManager(); + + private NoopAuthManager() { + } + + /** + * Gets auth content. + * + * @param register the register + * @return the auth content + */ + @Override + public Map getAuthContent(BaseRegister register) { + return new HashMap(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/constants/ValueConstants.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/constants/ValueConstants.java new file mode 100644 index 000000000..4ca2605d8 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/constants/ValueConstants.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.constants; + +/** + * The type Value constants. + * @author zhuoyu.sjw + * @version $Id : ValueConstants.java, v 0.1 2017-11-30 20:03 zhuoyu.sjw Exp $$ + */ +public class ValueConstants { + + /** + * The constant DEFAULT_GROUP. + */ + public static final String DEFAULT_GROUP = "DEFAULT_GROUP"; + + /** + * The constant DEFAULT_ZONE. + */ + public static final String DEFAULT_ZONE = "DEFAULT_ZONE"; + + /** + * The constant DEFAULT_DATA_CENTER. + */ + public static final String DEFAULT_DATA_CENTER = "DefaultDataCenter"; +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/constants/VersionConstants.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/constants/VersionConstants.java new file mode 100644 index 000000000..8c8ff2040 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/constants/VersionConstants.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.constants; + +/** + * + * @author zhuoyu.sjw + * @version $Id: VersionConstants.java, v 0.1 2017-11-23 22:36 zhuoyu.sjw Exp $$ + */ +public class VersionConstants { + + public static final long UNINITIALIZED_VERSION = 0; +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/event/ConfiguratorProcessEvent.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/ConfiguratorProcessEvent.java new file mode 100644 index 000000000..c5ba46c17 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/ConfiguratorProcessEvent.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.model.Event; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ConfiguratorProcessEvent.java, v 0.1 2018-07-13 18:44 zhuoyu.sjw Exp $$ + */ +public class ConfiguratorProcessEvent implements Event { + + private Configurator configurator; + + private RegistryClientConfig config; + + private long start; + + private long end; + + private Throwable throwable; + + /** + * Getter method for property configurator. + * + * @return property value of configurator + */ + public Configurator getConfigurator() { + return configurator; + } + + /** + * Setter method for property configurator. + * + * @param configurator value to be assigned to property configurator + */ + public void setConfigurator(Configurator configurator) { + this.configurator = configurator; + } + + /** + * Getter method for property config. + * + * @return property value of config + */ + public RegistryClientConfig getConfig() { + return config; + } + + /** + * Setter method for property config. + * + * @param config value to be assigned to property config + */ + public void setConfig(RegistryClientConfig config) { + this.config = config; + } + + /** + * Getter method for property start. + * + * @return property value of start + */ + public long getStart() { + return start; + } + + /** + * Setter method for property start. + * + * @param start value to be assigned to property start + */ + public void setStart(long start) { + this.start = start; + } + + /** + * Getter method for property end. + * + * @return property value of end + */ + public long getEnd() { + return end; + } + + /** + * Setter method for property end. + * + * @param end value to be assigned to property end + */ + public void setEnd(long end) { + this.end = end; + } + + /** + * Getter method for property throwable. + * + * @return property value of throwable + */ + public Throwable getThrowable() { + return throwable; + } + + /** + * Setter method for property throwable. + * + * @param throwable value to be assigned to property throwable + */ + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "ConfiguratorProcessEvent{" + "configurator=" + configurator + ", start=" + start + + ", end=" + end + ", throwable=" + throwable + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/event/DefaultEventBus.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/DefaultEventBus.java new file mode 100644 index 000000000..410469c1f --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/DefaultEventBus.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.EventBus; +import com.alipay.sofa.registry.client.api.EventSubscriber; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.model.Event; +import com.alipay.sofa.registry.client.factory.NamedThreadFactory; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.util.CommonUtils; +import org.slf4j.Logger; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * The type Default event bus. + * @author zhanggeng.zg + * @author zhuoyu.sjw + * @version $Id : DefaultEventBus.java, v 0.1 2018-07-13 10:56 zhuoyu.sjw Exp $$ + */ +public class DefaultEventBus implements EventBus { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultEventBus.class); + + private RegistryClientConfig config; + + private ConcurrentMap, CopyOnWriteArraySet> eventSubscriberMap = new ConcurrentHashMap, CopyOnWriteArraySet>(); + + private Executor executor; + + /** + * Instantiates a new Default event bus. + * + * @param config the config + */ + public DefaultEventBus(RegistryClientConfig config) { + this.config = config; + this.executor = new ThreadPoolExecutor(config.getObserverThreadCoreSize(), + config.getObserverThreadMaxSize(), 0, TimeUnit.SECONDS, + new LinkedBlockingDeque(config.getObserverThreadQueueLength()), + new NamedThreadFactory("DefaultEventBusThread")); + } + + /** + * @see EventBus#register(Class, EventSubscriber) + */ + @Override + public void register(Class eventClass, EventSubscriber eventSubscriber) { + CopyOnWriteArraySet set = eventSubscriberMap.get(eventClass); + if (set == null) { + set = new CopyOnWriteArraySet(); + CopyOnWriteArraySet old = eventSubscriberMap.putIfAbsent(eventClass, + set); + if (old != null) { + set = old; + } + } + set.add(eventSubscriber); + LOGGER.debug("Register subscriber: {} of event: {}.", eventSubscriber, eventClass); + } + + /** + * @see EventBus#unRegister(Class, EventSubscriber) + */ + @Override + public void unRegister(Class eventClass, EventSubscriber eventSubscriber) { + CopyOnWriteArraySet set = eventSubscriberMap.get(eventClass); + if (set != null) { + set.remove(eventSubscriber); + LOGGER.debug("UnRegister subscriber: {} of event: {}.", eventSubscriber, eventClass); + } + } + + /** + * Post. + * + * @param event the event + */ + @Override + public void post(final Event event) { + if (!isEnable()) { + return; + } + CopyOnWriteArraySet subscribers = eventSubscriberMap.get(event.getClass()); + if (null != subscribers && !subscribers.isEmpty()) { + for (final EventSubscriber subscriber : subscribers) { + if (subscriber.isSync()) { + handleEvent(subscriber, event); + } else { // 异步 + executor.execute(new Runnable() { + @Override + public void run() { + handleEvent(subscriber, event); + } + }); + } + } + } + } + + /** + * Is enable boolean. + * + * @return the boolean + */ + @Override + public boolean isEnable() { + return null != config && config.isEventBusEnable(); + } + + /** + * Is enable boolean. + * + * @param eventClass the event class + * @return the boolean + */ + @Override + public boolean isEnable(Class eventClass) { + return isEnable() && CommonUtils.isNotEmpty(eventSubscriberMap.get(eventClass)); + } + + private void handleEvent(final EventSubscriber subscriber, final Event event) { + try { + subscriber.onEvent(event); + } catch (Throwable e) { + LOGGER.warn("Handle {} error", event.getClass(), e); + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/event/LookoutSubscriber.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/LookoutSubscriber.java new file mode 100644 index 000000000..6bb6fcc62 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/LookoutSubscriber.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.lookout.api.Id; +import com.alipay.lookout.api.Lookout; +import com.alipay.lookout.api.composite.MixinMetric; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.EventSubscriber; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.model.Event; +import com.alipay.sofa.registry.client.util.StringUtils; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author zhuoyu.sjw + * @version $Id: LookoutSubscriber.java, v 0.1 2018-07-13 20:31 zhuoyu.sjw Exp $$ + */ +public class LookoutSubscriber implements EventSubscriber { + + /** */ + private static final String METRIC_DATA_ID_NAME = "data_id"; + + /** */ + private static final String METRIC_INSTANCE_ID_NAME = "instance_id"; + + /** */ + private static final String METRIC_COUNT_NAME = "count"; + + /** */ + private static final String METRIC_TIME_NAME = "time"; + + /** */ + private static final String METRIC_SUCCESS_NAME = "success"; + + /** */ + private static final String REGISTRY_PROCESS_SUBSCRIBER = "registry.process.subscriber"; + + /** */ + private static final String REGISTRY_PROCESS_CONFIGURATOR = "registry.process.configurator"; + + /** + * @see EventSubscriber#isSync() + */ + @Override + public boolean isSync() { + return false; + } + + /** + * @see EventSubscriber#onEvent(Event) + */ + @Override + public void onEvent(Event event) { + if (null == event) { + return; + } + Class eventClass = event.getClass(); + + if (eventClass == SubscriberProcessEvent.class) { + SubscriberProcessEvent subscriberProcessEvent = (SubscriberProcessEvent) event; + Subscriber subscriber = subscriberProcessEvent.getSubscriber(); + if (null == subscriber) { + return; + } + + RegistryClientConfig config = subscriberProcessEvent.getConfig(); + if (null == config) { + return; + } + + Id id = Lookout + .registry() + .createId(REGISTRY_PROCESS_SUBSCRIBER) + .withTag(METRIC_DATA_ID_NAME, StringUtils.defaultString(subscriber.getDataId())) + .withTag(METRIC_INSTANCE_ID_NAME, StringUtils.defaultString(config.getInstanceId())); + MixinMetric mixin = Lookout.registry().mixinMetric(id); + + mixin.counter(METRIC_COUNT_NAME).inc(); + mixin.timer(METRIC_TIME_NAME).record( + subscriberProcessEvent.getEnd() - subscriberProcessEvent.getStart(), + TimeUnit.MILLISECONDS); + + if (null == subscriberProcessEvent.getThrowable()) { + mixin.counter(METRIC_SUCCESS_NAME).inc(); + } + } else if (eventClass == ConfiguratorProcessEvent.class) { + ConfiguratorProcessEvent configuratorProcessEvent = (ConfiguratorProcessEvent) event; + Configurator configurator = configuratorProcessEvent.getConfigurator(); + if (null == configurator) { + return; + } + + RegistryClientConfig config = configuratorProcessEvent.getConfig(); + + Id id = Lookout + .registry() + .createId(REGISTRY_PROCESS_CONFIGURATOR) + .withTag(METRIC_DATA_ID_NAME, StringUtils.defaultString(configurator.getDataId())) + .withTag(METRIC_INSTANCE_ID_NAME, StringUtils.defaultString(config.getInstanceId())); + MixinMetric mixin = Lookout.registry().mixinMetric(id); + + mixin.counter(METRIC_COUNT_NAME).inc(); + mixin.timer(METRIC_TIME_NAME).record( + configuratorProcessEvent.getEnd() - configuratorProcessEvent.getStart(), + TimeUnit.MILLISECONDS); + + if (null == configuratorProcessEvent.getThrowable()) { + mixin.counter(METRIC_SUCCESS_NAME).inc(); + } + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/event/SubscriberProcessEvent.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/SubscriberProcessEvent.java new file mode 100644 index 000000000..d8c6b2a2b --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/event/SubscriberProcessEvent.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.model.Event; + +/** + * The type Subscriber process event. + * @author zhuoyu.sjw + * @version $Id : SubscriberProcessEvent.java, v 0.1 2018-07-13 18:40 zhuoyu.sjw Exp $$ + */ +public class SubscriberProcessEvent implements Event { + + private Subscriber subscriber; + + private RegistryClientConfig config; + + private long start; + + private long end; + + private Throwable throwable; + + /** + * Getter method for property subscriber. + * + * @return property value of subscriber + */ + public Subscriber getSubscriber() { + return subscriber; + } + + /** + * Setter method for property subscriber. + * + * @param subscriber value to be assigned to property subscriber + */ + public void setSubscriber(Subscriber subscriber) { + this.subscriber = subscriber; + } + + /** + * Getter method for property config. + * + * @return property value of config + */ + public RegistryClientConfig getConfig() { + return config; + } + + /** + * Setter method for property config. + * + * @param config value to be assigned to property config + */ + public void setConfig(RegistryClientConfig config) { + this.config = config; + } + + /** + * Getter method for property start. + * + * @return property value of start + */ + public long getStart() { + return start; + } + + /** + * Setter method for property start. + * + * @param start value to be assigned to property start + */ + public void setStart(long start) { + this.start = start; + } + + /** + * Getter method for property end. + * + * @return property value of end + */ + public long getEnd() { + return end; + } + + /** + * Setter method for property end. + * + * @param end value to be assigned to property end + */ + public void setEnd(long end) { + this.end = end; + } + + /** + * Getter method for property throwable. + * + * @return property value of throwable + */ + public Throwable getThrowable() { + return throwable; + } + + /** + * Setter method for property throwable. + * + * @param throwable value to be assigned to property throwable + */ + public void setThrowable(Throwable throwable) { + this.throwable = throwable; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "SubscriberProcessEvent{" + "subscriber=" + subscriber + ", start=" + start + + ", end=" + end + ", throwable=" + throwable + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/factory/NamedThreadFactory.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/factory/NamedThreadFactory.java new file mode 100644 index 000000000..f58a9a312 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/factory/NamedThreadFactory.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.factory; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * The type Named thread factory. + * @author zhuoyu.sjw + * @version $Id : NamedThreadFactory.java, v 0.1 2018-03-02 21:23 zhuoyu.sjw Exp $$ + */ +public class NamedThreadFactory implements ThreadFactory { + + private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final String namePrefix; + private final boolean isDaemon; + + /** + * Instantiates a new Named thread factory. + * + * @param name the name + */ + public NamedThreadFactory(String name) { + this(name, false); + } + + /** + * Instantiates a new Named thread factory. + * + * @param prefix the prefix + * @param daemon the daemon + */ + public NamedThreadFactory(String prefix, boolean daemon) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + namePrefix = prefix + "-" + POOL_NUMBER.getAndIncrement() + "-thread-"; + isDaemon = daemon; + } + + /** + * Create a thread. + * + * @see ThreadFactory#newThread(Runnable) + */ + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); + t.setDaemon(isDaemon); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/model/ConfiguratorData.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/model/ConfiguratorData.java new file mode 100644 index 000000000..ab3efa0e5 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/model/ConfiguratorData.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.model; + +import com.alipay.sofa.registry.core.model.DataBox; + +import java.io.Serializable; + +/** + * The type Configurator data. + * @author zhuoyu.sjw + * @version $Id : ConfiguratorData.java, v 0.1 2018-04-18 15:17 zhuoyu.sjw Exp $$ + */ +public class ConfiguratorData implements Serializable { + + private static final long serialVersionUID = 3667107975967019132L; + + private DataBox dataBox; + + private Long version; + + /** + * Getter method for property dataBox. + * + * @return property value of dataBox + */ + public DataBox getDataBox() { + return dataBox; + } + + /** + * Setter method for property dataBox. + * + * @param dataBox value to be assigned to property dataBox + */ + public void setDataBox(DataBox dataBox) { + this.dataBox = dataBox; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/model/SegmentData.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/model/SegmentData.java new file mode 100644 index 000000000..7215a42ed --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/model/SegmentData.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.model; + +import com.alipay.sofa.registry.core.model.DataBox; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SegmentData.java, v 0.1 2018-03-12 22:13 zhuoyu.sjw Exp $$ + */ +public class SegmentData implements Serializable { + + private static final long serialVersionUID = 3066687802211879826L; + + private String segment; + + private Map> data; + + private Long version; + + /** + * Getter method for property segment. + * + * @return property value of segment + */ + public String getSegment() { + return segment; + } + + /** + * Setter method for property segment. + * + * @param segment value to be assigned to property segment + */ + public void setSegment(String segment) { + this.segment = segment; + } + + /** + * Getter method for property data. + * + * @return property value of data + */ + public Map> getData() { + return data; + } + + /** + * Setter method for property data. + * + * @param data value to be assigned to property data + */ + public void setData(Map> data) { + this.data = data; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/AbstractInternalRegister.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/AbstractInternalRegister.java new file mode 100644 index 000000000..928e1825e --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/AbstractInternalRegister.java @@ -0,0 +1,407 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.Register; +import com.alipay.sofa.registry.client.auth.AuthManager; +import com.alipay.sofa.registry.client.constants.VersionConstants; +import com.alipay.sofa.registry.core.model.BaseRegister; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * The type Internal register. + * + * @author zhuoyu.sjw + * @version $Id : AbstractInternalRegister.java, v 0.1 2017-11-23 20:52 zhuoyu.sjw Exp $$ + */ +public abstract class AbstractInternalRegister implements Register { + + /** */ + private final AtomicLong initialVersion = new AtomicLong(VersionConstants.UNINITIALIZED_VERSION); + /** */ + private AuthManager authManager; + /** */ + private volatile boolean registered = false; + /** */ + private volatile boolean enabled = true; + /** */ + private volatile boolean refused = false; + /** */ + private AtomicLong pubVersion = new AtomicLong(VersionConstants.UNINITIALIZED_VERSION); + /** */ + private AtomicLong ackVersion = new AtomicLong(VersionConstants.UNINITIALIZED_VERSION); + /** */ + private volatile long timestamp = System.currentTimeMillis(); + /** */ + private volatile int registerCount = 0; + /** */ + private volatile String requestId = UUID.randomUUID().toString(); + + private ReadWriteLock lock = new ReentrantReadWriteLock(); + + /** + * The Read lock. + */ + protected Lock readLock = lock.readLock(); + + /** + * The Write lock. + */ + protected Lock writeLock = lock.writeLock(); + + /** + * Assembly object. + * + * @return the object + */ + public abstract Object assembly(); + + /** + * Is registered boolean. + * + * @return boolean boolean + */ + @Override + public boolean isRegistered() { + readLock.lock(); + try { + return registered; + } finally { + readLock.unlock(); + } + } + + /** + * Wait to sync. + */ + void waitToSync() { + writeLock.lock(); + try { + this.registered = false; + this.requestId = UUID.randomUUID().toString(); + } finally { + writeLock.unlock(); + } + } + + /** + * Sync ok. + * + * @param requestId the request id + * @param version the version + * @param refused the refused + * @return the boolean + */ + public boolean syncOK(String requestId, long version, boolean refused) { + writeLock.lock(); + try { + if (this.requestId.equals(requestId)) { + this.registered = true; + this.refused = refused; + this.setAckVersion(version); + return true; + } + return false; + } finally { + writeLock.unlock(); + } + } + + /** + * @see Register#isEnabled() + */ + @Override + public boolean isEnabled() { + readLock.lock(); + try { + return enabled; + } finally { + readLock.unlock(); + } + } + + /** + * Sets enabled. + * + * @param requestId the request id + */ + public void refused(String requestId) { + writeLock.lock(); + try { + if (this.requestId.equals(requestId)) { + this.enabled = false; + this.refused = true; + } + } finally { + writeLock.unlock(); + } + } + + /** + * Is done boolean. + * + * @return boolean boolean + */ + public boolean isDone() { + readLock.lock(); + try { + return (this.isRegistered() && this.pubVersion.get() == this.ackVersion.get()) + || this.isRefused(); + } finally { + readLock.unlock(); + } + } + + /** + * Assembly sync task sync task. + * + * @return the sync task + */ + public SyncTask assemblySyncTask() { + readLock.lock(); + try { + SyncTask syncTask = new SyncTask(); + syncTask.setRequestId(requestId); + syncTask.setRequest(assembly()); + syncTask.setDone(isDone()); + return syncTask; + } finally { + readLock.unlock(); + } + } + + /** + * Gets pub version. + * + * @return AtomicLong pub version + */ + public AtomicLong getPubVersion() { + return this.pubVersion; + } + + /** + * Sets ack version. + * + * @param version the ack version + */ + public void setAckVersion(Long version) { + if (null == version) { + return; + } + + long current = ackVersion.get(); + if (version <= current) { + return; + } + + boolean result = this.ackVersion.compareAndSet(current, version); + if (result) { + return; + } + + setAckVersion(version); + } + + /** + * @see Register#reset() + */ + @Override + public void reset() { + writeLock.lock(); + try { + this.registered = false; + this.registerCount = 0; + this.timestamp = System.currentTimeMillis(); + this.ackVersion = new AtomicLong(initialVersion.longValue()); + this.requestId = UUID.randomUUID().toString(); + } finally { + writeLock.unlock(); + } + } + + /** + * @see Register#unregister() + */ + @Override + public void unregister() { + writeLock.lock(); + try { + this.enabled = false; + this.pubVersion.incrementAndGet(); + this.requestId = UUID.randomUUID().toString(); + this.registerCount = 0; + } finally { + writeLock.unlock(); + } + } + + /** + * Getter method for property refused. + * + * @return property value of refused + */ + boolean isRefused() { + readLock.lock(); + try { + return refused; + } finally { + readLock.unlock(); + } + } + + /** + * Getter method for property timestamp. + * + * @return property value of timestamp + */ + @Override + public long getTimestamp() { + readLock.lock(); + try { + return timestamp; + } finally { + readLock.unlock(); + } + } + + /** + * Setter method for property timestamp. + * + * @param timestamp value to be assigned to property timestamp + */ + void setTimestamp(long timestamp) { + writeLock.lock(); + try { + this.timestamp = timestamp; + } finally { + writeLock.unlock(); + } + } + + /** + * Sets auth signature. + * + * @param register the register + */ + void setAuthSignature(BaseRegister register) { + // auth signature + if (null != authManager) { + Map authAttributes = authManager.getAuthContent(register); + + // merge auth attributes with exists register attributes + Map registerAttributes = register.getAttributes(); + if (null == registerAttributes) { + registerAttributes = new HashMap(); + } + registerAttributes.putAll(authAttributes); + register.setAttributes(registerAttributes); + } + } + + /** + * Setter method for property authManager. + * + * @param authManager value to be assigned to property authManager + */ + public void setAuthManager(AuthManager authManager) { + this.authManager = authManager; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "AbstractInternalRegister{" + "initialVersion=" + initialVersion + ", registered=" + + registered + ", enabled=" + enabled + ", refused=" + refused + ", pubVersion=" + + pubVersion + ", ackVersion=" + ackVersion + ", timestamp=" + timestamp + + ", registerCount=" + registerCount + ", requestId='" + requestId + '}'; + } + + /** + * The type Sync task. + */ + public static class SyncTask { + + private String requestId; + + private Object request; + + private boolean done; + + /** + * Getter method for property requestId. + * + * @return property value of requestId + */ + public String getRequestId() { + return requestId; + } + + /** + * Setter method for property requestId. + * + * @param requestId value to be assigned to property requestId + */ + void setRequestId(String requestId) { + this.requestId = requestId; + } + + /** + * Getter method for property request. + * + * @return property value of request + */ + public Object getRequest() { + return request; + } + + /** + * Setter method for property request. + * + * @param request value to be assigned to property request + */ + void setRequest(Object request) { + this.request = request; + } + + /** + * Getter method for property done. + * + * @return property value of done + */ + public boolean isDone() { + return done; + } + + /** + * Setter method for property done. + * + * @param done value to be assigned to property done + */ + public void setDone(boolean done) { + this.done = done; + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigData.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigData.java new file mode 100644 index 000000000..61be0795d --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigData.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.model.ConfigData; + +/** + * The type Default config data. + * @author zhuoyu.sjw + * @version $Id : DefaultConfigData.java, v 0.1 2018-04-18 15:29 zhuoyu.sjw Exp $$ + */ +public class DefaultConfigData implements ConfigData { + + private String data; + + /** + * Instantiates a new Default config data. + * + * @param data the data + */ + public DefaultConfigData(String data) { + this.data = data; + } + + /** + * @see ConfigData#getData() + */ + @Override + public String getData() { + return data; + } + + @Override + public String toString() { + return "DefaultConfigData{" + "data='" + data + '\'' + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigurator.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigurator.java new file mode 100644 index 000000000..7fce34e63 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultConfigurator.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.ConfigDataObserver; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.model.ConfigData; +import com.alipay.sofa.registry.client.api.registration.ConfiguratorRegistration; +import com.alipay.sofa.registry.client.constants.ValueConstants; +import com.alipay.sofa.registry.client.model.ConfiguratorData; +import com.alipay.sofa.registry.client.task.TaskEvent; +import com.alipay.sofa.registry.client.task.Worker; +import com.alipay.sofa.registry.client.util.StringUtils; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.ConfiguratorRegister; +import com.alipay.sofa.registry.core.model.DataBox; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The type Default configurator. + * @author zhuoyu.sjw + * @version $Id : DefaultConfigurator.java, v 0.1 2018-04-18 14:41 zhuoyu.sjw Exp $$ + */ +public class DefaultConfigurator extends AbstractInternalRegister implements Configurator { + private final String REGIST_ID; + + private ConfiguratorRegistration registration; + + private ConfigDataObserver configDataObserver; + + private RegistryClientConfig config; + + private ConfiguratorData configuratorData; + + private Worker worker; + + private AtomicBoolean init = new AtomicBoolean(false); + + /** + * Instantiates a new Default configurator. + * + * @param config the config + * @param worker the worker + */ + public DefaultConfigurator(ConfiguratorRegistration registration, RegistryClientConfig config, + Worker worker) { + if (null != registration) { + this.configDataObserver = registration.getConfigDataObserver(); + } + this.registration = registration; + this.config = config; + this.worker = worker; + this.REGIST_ID = UUID.randomUUID().toString(); + } + + /** + * Gets data observer. + * + * @return the data observer + */ + @Override + public ConfigDataObserver getDataObserver() { + return configDataObserver; + } + + /** + * Setter method for property configDataObserver. + * + * @param configDataObserver value to be assigned to property configDataObserver + */ + @Override + public void setDataObserver(ConfigDataObserver configDataObserver) { + this.configDataObserver = configDataObserver; + } + + /** + * Peek data config data. + * + * @return the config data + */ + @Override + public ConfigData peekData() { + if (!init.get()) { + throw new IllegalStateException("Config data is not ready yet."); + } + if (null != configuratorData) { + DataBox dataBox = configuratorData.getDataBox(); + if (null != dataBox) { + return new DefaultConfigData(dataBox.getData()); + } + } + return new DefaultConfigData(null); + } + + /** + * Assembly object. + * + * @return the object + */ + @Override + public Object assembly() { + readLock.lock(); + ConfiguratorRegister register = new ConfiguratorRegister(); + try { + register.setInstanceId(config.getInstanceId()); + if (StringUtils.isNotEmpty(config.getZone())) { + register.setZone(config.getZone()); + } else { + register.setZone(ValueConstants.DEFAULT_ZONE); + } + if (StringUtils.isNotEmpty(registration.getAppName())) { + register.setAppName(registration.getAppName()); + } else { + register.setAppName(config.getAppName()); + } + register.setDataId(registration.getDataId()); + register.setGroup(registration.getGroup()); + register.setRegistId(REGIST_ID); + register.setVersion(this.getPubVersion().get()); + register.setTimestamp(this.getTimestamp()); + + // auth signature + setAuthSignature(register); + + if (isEnabled()) { + register.setEventType(EventTypeConstants.REGISTER); + } else { + register.setEventType(EventTypeConstants.UNREGISTER); + } + } finally { + readLock.unlock(); + } + return register; + } + + /** + * Put configurator data. + * + * @param receivedConfigData the received config data + */ + public void putConfiguratorData(ConfiguratorData receivedConfigData) { + writeLock.lock(); + try { + if (null == receivedConfigData) { + return; + } + + // default version set to zero + if (null == receivedConfigData.getVersion()) { + receivedConfigData.setVersion(0L); + } + + if (null == configuratorData + || receivedConfigData.getVersion() > configuratorData.getVersion()) { + configuratorData = receivedConfigData; + init.compareAndSet(false, true); + } + + } finally { + writeLock.unlock(); + } + } + + /** + * Gets data id. + * + * @return the data id + */ + @Override + public String getDataId() { + return registration.getDataId(); + } + + /** + * Gets group. + * + * @return the group + */ + @Override + public String getGroup() { + return registration.getGroup(); + } + + /** + * Gets regist id. + * + * @return the regist id + */ + @Override + public String getRegistId() { + return REGIST_ID; + } + + /** + * Unregister. + */ + @Override + public void unregister() { + if (isEnabled()) { + super.unregister(); + this.worker.schedule(new TaskEvent(this)); + } + } + + @Override + public String toString() { + return "DefaultConfigurator{" + "registration=" + registration + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultObserverHandler.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultObserverHandler.java new file mode 100644 index 000000000..2cde5978f --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultObserverHandler.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.ConfigDataObserver; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.EventBus; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.client.event.ConfiguratorProcessEvent; +import com.alipay.sofa.registry.client.event.SubscriberProcessEvent; +import com.alipay.sofa.registry.client.factory.NamedThreadFactory; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.task.ObserverHandler; +import org.slf4j.Logger; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * The type Default observer handler. + * @author zhuoyu.sjw + * @version $Id : DefaultObserverHandler.java, v 0.1 2018-03-15 12:02 zhuoyu.sjw Exp $$ + */ +public class DefaultObserverHandler implements ObserverHandler { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultObserverHandler.class); + + private static final int KEEP_ALIVE_TIME = 60; + + private ExecutorService executor; + + private EventBus eventBus; + + private RegistryClientConfig config; + + /** + * Constructor. + * + * @param config the config + */ + public DefaultObserverHandler(RegistryClientConfig config, EventBus eventBus) { + this.config = config; + this.executor = new ThreadPoolExecutor(config.getObserverThreadCoreSize(), + config.getObserverThreadMaxSize(), KEEP_ALIVE_TIME, TimeUnit.SECONDS, + new LinkedBlockingDeque(config.getObserverThreadQueueLength()), + new NamedThreadFactory("ObserverNotifyThread")); + this.eventBus = eventBus; + } + + /** + * @see ObserverHandler#notify(Subscriber) + */ + @Override + public void notify(Subscriber subscriber) { + executor.submit(new SubscriberNotifyTask(subscriber)); + } + + /** + * @see ObserverHandler#notify(Configurator) + */ + @Override + public void notify(Configurator configurator) { + executor.submit(new ConfiguratorNotifyTask(configurator)); + } + + /** + * The type Observer notify task. + */ + public class SubscriberNotifyTask implements Runnable { + + private Subscriber subscriber; + + /** + * Constructor. + * + * @param subscriber the subscriber + */ + public SubscriberNotifyTask(Subscriber subscriber) { + this.subscriber = subscriber; + } + + /** + * @see Runnable#run() + */ + @Override + public void run() { + // ignore empty task + if (null == subscriber) { + return; + } + + SubscriberProcessEvent event = new SubscriberProcessEvent(); + long start = System.currentTimeMillis(); + event.setStart(start); + event.setConfig(config); + event.setSubscriber(subscriber); + try { + SubscriberDataObserver dataObserver = subscriber.getDataObserver(); + if (null != dataObserver) { + dataObserver.handleData(subscriber.getDataId(), subscriber.peekData()); + } + LOGGER.info( + "[notify] notify subscriber success, dataId: {}, registId:{}, cost: {}ms", + subscriber.getDataId(), subscriber.getRegistId(), + (System.currentTimeMillis() - start)); + } catch (Exception e) { + LOGGER.error("[notify] SubscriberNotifyTask execute error, dataId: {}", + subscriber.getDataId(), e); + event.setThrowable(e); + } finally { + event.setEnd(System.currentTimeMillis()); + if (null != eventBus) { + eventBus.post(event); + } + } + } + + } + + /** + * The type Configurator notify task. + */ + public class ConfiguratorNotifyTask implements Runnable { + + private Configurator configurator; + + /** + * Instantiates a new Configurator notify task. + * + * @param configurator the configurator + */ + public ConfiguratorNotifyTask(Configurator configurator) { + this.configurator = configurator; + } + + /** + * @see Runnable#run() + */ + @Override + public void run() { + if (null == configurator) { + return; + } + + ConfiguratorProcessEvent event = new ConfiguratorProcessEvent(); + long start = System.currentTimeMillis(); + event.setStart(start); + event.setConfig(config); + event.setConfigurator(configurator); + try { + ConfigDataObserver dataObserver = configurator.getDataObserver(); + if (null != dataObserver) { + dataObserver.handleData(configurator.getDataId(), configurator.peekData()); + } + + LOGGER.info( + "[notify] notify configurator success, dataId: {}, registId:{}, cost: {}ms", + configurator.getDataId(), configurator.getRegistId(), + (System.currentTimeMillis() - start)); + } catch (Exception e) { + LOGGER.error("[notify] ConfiguratorNotifyTask execute error, dataId: {}", + configurator.getDataId(), e); + event.setThrowable(e); + } finally { + event.setEnd(System.currentTimeMillis()); + if (null != eventBus) { + eventBus.post(event); + } + } + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultPublisher.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultPublisher.java new file mode 100644 index 000000000..14dd00884 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultPublisher.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.Publisher; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.constants.ValueConstants; +import com.alipay.sofa.registry.client.task.TaskEvent; +import com.alipay.sofa.registry.client.task.Worker; +import com.alipay.sofa.registry.client.util.StringUtils; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.PublisherRegister; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +/** + * The type Default publisher. + * + * @author zhuoyu.sjw + * @version $Id : DefaultPublisher.java, v 0.1 2017-11-23 20:45 zhuoyu.sjw Exp $$ + */ +public class DefaultPublisher extends AbstractInternalRegister implements Publisher { + + private final String REGIST_ID; + private PublisherRegistration registration; + private Worker worker; + private Collection dataList; + private RegistryClientConfig config; + + /** + * Instantiates a new Default publisher. + * + * @param registration the publisher registration + * @param worker the worker + */ + DefaultPublisher(PublisherRegistration registration, Worker worker, RegistryClientConfig config) { + this.registration = registration; + this.worker = worker; + this.config = config; + this.REGIST_ID = UUID.randomUUID().toString(); + } + + /** + * @see Publisher#republish(String...) + */ + @Override + public void republish(String... data) { + if (isRefused()) { + throw new IllegalStateException( + "Publisher is refused by server. Try to check your configuration."); + } + + if (!isEnabled()) { + throw new IllegalStateException("Unregistered publisher can not be reused."); + } + + writeLock.lock(); + try { + if (null != data) { + this.dataList = Arrays.asList(data); + } + + this.getPubVersion().incrementAndGet(); + this.setTimestamp(System.currentTimeMillis()); + this.waitToSync(); + } finally { + writeLock.unlock(); + } + this.worker.schedule(new TaskEvent(this)); + } + + /** + * Unregister. + */ + @Override + public void unregister() { + if (isEnabled()) { + super.unregister(); + this.worker.schedule(new TaskEvent(this)); + } + } + + /** + * Assembly publisher register. + * + * @return the publisher register + */ + @Override + public PublisherRegister assembly() { + readLock.lock(); + PublisherRegister register; + try { + register = new PublisherRegister(); + register.setInstanceId(config.getInstanceId()); + if (StringUtils.isNotEmpty(config.getZone())) { + register.setZone(config.getZone()); + } else { + register.setZone(ValueConstants.DEFAULT_ZONE); + } + if (StringUtils.isNotEmpty(registration.getAppName())) { + register.setAppName(registration.getAppName()); + } else { + register.setAppName(config.getAppName()); + } + register.setDataId(registration.getDataId()); + register.setGroup(registration.getGroup()); + register.setRegistId(REGIST_ID); + register.setVersion(this.getPubVersion().get()); + register.setTimestamp(this.getTimestamp()); + + // auth signature + setAuthSignature(register); + + if (isEnabled()) { + register.setEventType(EventTypeConstants.REGISTER); + if (null != dataList) { + List dataBoxes = new ArrayList(); + for (String data : dataList) { + dataBoxes.add(new DataBox(data)); + } + register.setDataList(dataBoxes); + } + } else { + register.setEventType(EventTypeConstants.UNREGISTER); + } + } finally { + readLock.unlock(); + } + return register; + } + + /** + * @see Publisher#getDataId() + */ + @Override + public String getDataId() { + return registration.getDataId(); + } + + @Override + public String getGroup() { + return registration.getGroup(); + } + + /** + * @see Publisher#getRegistId() + */ + @Override + public String getRegistId() { + return REGIST_ID; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "DefaultPublisher{" + "registration=" + registration + '}' + super.toString(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClient.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClient.java new file mode 100644 index 000000000..b58568d80 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClient.java @@ -0,0 +1,609 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.remoting.ConnectionEventProcessor; +import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.rpc.protocol.UserProcessor; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.EventBus; +import com.alipay.sofa.registry.client.api.Publisher; +import com.alipay.sofa.registry.client.api.Register; +import com.alipay.sofa.registry.client.api.RegistryClient; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.exception.DuplicateException; +import com.alipay.sofa.registry.client.api.exception.RegistryClientException; +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.ConfiguratorRegistration; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.client.auth.AuthManager; +import com.alipay.sofa.registry.client.auth.NoopAuthManager; +import com.alipay.sofa.registry.client.event.ConfiguratorProcessEvent; +import com.alipay.sofa.registry.client.event.DefaultEventBus; +import com.alipay.sofa.registry.client.event.LookoutSubscriber; +import com.alipay.sofa.registry.client.event.SubscriberProcessEvent; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.remoting.ClientConnection; +import com.alipay.sofa.registry.client.remoting.ClientConnectionCloseEventProcessor; +import com.alipay.sofa.registry.client.remoting.ClientConnectionOpenEventProcessor; +import com.alipay.sofa.registry.client.remoting.ReceivedConfigDataProcessor; +import com.alipay.sofa.registry.client.remoting.ReceivedDataProcessor; +import com.alipay.sofa.registry.client.remoting.ServerManager; +import com.alipay.sofa.registry.client.task.ObserverHandler; +import com.alipay.sofa.registry.client.task.SyncConfigThread; +import com.alipay.sofa.registry.client.task.TaskEvent; +import com.alipay.sofa.registry.client.task.WorkerThread; +import com.alipay.sofa.registry.client.util.StringUtils; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.core.model.ReceivedData; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; + +/** + * The type Default registry client. + * @author zhuoyu.sjw + * @version $Id : DefaultRegistryClient.java, v 0.1 2017-11-23 20:07 zhuoyu.sjw Exp $$ + */ +public class DefaultRegistryClient implements RegistryClient { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultRegistryClient.class); + + private RegistryClientConfig registryClientConfig; + + private RegisterCache registerCache; + + private ServerManager serverManager; + + private WorkerThread workerThread; + + private ClientConnection client; + + private Map, UserProcessor> userProcessorMap; + + private Map connectionEventProcessorMap; + + private ConcurrentMap registrationPublisherMap; + + private ConcurrentMap registrationSubscriberMap; + + private ConcurrentMap registrationConfiguratorMap; + + private ObserverHandler observerHandler; + + private AuthManager authManager; + + private EventBus eventBus; + + private LookoutSubscriber lookoutSubscriber; + + private AtomicBoolean init = new AtomicBoolean(false); + + /** + * Instantiates a new Default registry client. + * + * @param registryClientConfig the registry client config + */ + public DefaultRegistryClient(RegistryClientConfig registryClientConfig) { + // clone config to avoid configuration changes at runtime + this.registryClientConfig = cloneConfig(registryClientConfig); + this.registerCache = new RegisterCache(); + this.registrationPublisherMap = new ConcurrentHashMap(); + this.registrationSubscriberMap = new ConcurrentHashMap(); + this.registrationConfiguratorMap = new ConcurrentHashMap(); + } + + private DefaultRegistryClientConfig cloneConfig(RegistryClientConfig registryClientConfig) { + DefaultRegistryClientConfig cloneConfig = null; + DefaultRegistryClientConfigBuilder builder = DefaultRegistryClientConfigBuilder.start(); + if (null != registryClientConfig) { + cloneConfig = builder.setEnv(registryClientConfig.getEnv()) + .setAppName(registryClientConfig.getAppName()) + .setInstanceId(registryClientConfig.getInstanceId()) + .setDataCenter(registryClientConfig.getDataCenter()) + .setZone(registryClientConfig.getZone()) + .setRegistryEndpoint(registryClientConfig.getRegistryEndpoint()) + .setRegistryEndpointPort(registryClientConfig.getRegistryEndpointPort()) + .setConnectTimeout(registryClientConfig.getConnectTimeout()) + .setSocketTimeout(registryClientConfig.getSocketTimeout()) + .setInvokeTimeout(registryClientConfig.getInvokeTimeout()) + .setRecheckInterval(registryClientConfig.getRecheckInterval()) + .setObserverThreadCoreSize(registryClientConfig.getObserverThreadCoreSize()) + .setObserverThreadMaxSize(registryClientConfig.getObserverThreadMaxSize()) + .setObserverThreadQueueLength(registryClientConfig.getObserverThreadQueueLength()) + .setObserverCallbackTimeout(registryClientConfig.getObserverCallbackTimeout()) + .setSyncConfigRetryInterval(registryClientConfig.getSyncConfigRetryInterval()) + .setAccessKey(registryClientConfig.getAccessKey()) + .setSecretKey(registryClientConfig.getSecretKey()).build(); + } + return cloneConfig; + } + + /** + * Init. + */ + public void init() { + if (!init.compareAndSet(false, true)) { + return; + } + + // init lookout subscriber + if (null == lookoutSubscriber) { + this.lookoutSubscriber = new LookoutSubscriber(); + } + + // init event bus + if (null == eventBus) { + this.eventBus = new DefaultEventBus(registryClientConfig); + this.eventBus.register(SubscriberProcessEvent.class, lookoutSubscriber); + this.eventBus.register(ConfiguratorProcessEvent.class, lookoutSubscriber); + } + + // init server manager + if (null == serverManager) { + this.serverManager = new DefaultServerManager(registryClientConfig); + } + + // init observer handler + if (null == observerHandler) { + observerHandler = new DefaultObserverHandler(registryClientConfig, eventBus); + } + + // init auth manager + if (null == authManager) { + authManager = NoopAuthManager.INSTANCE; + } + + // init user processor + List userProcessorList = new ArrayList(); + if (null == userProcessorMap) { + userProcessorList.add(new ReceivedDataProcessor(registerCache, observerHandler)); + userProcessorList.add(new ReceivedConfigDataProcessor(registerCache, observerHandler)); + } else { + UserProcessor userProcessor = userProcessorMap.get(ReceivedData.class); + if (null == userProcessor) { + userProcessorList.add(new ReceivedDataProcessor(registerCache, observerHandler)); + } + userProcessor = userProcessorMap.get(ReceivedConfigData.class); + if (null == userProcessor) { + userProcessorList.add(new ReceivedConfigDataProcessor(registerCache, + observerHandler)); + } + userProcessorList.addAll(userProcessorMap.values()); + } + + // init connection event processor + if (null == connectionEventProcessorMap) { + connectionEventProcessorMap = new HashMap( + ConnectionEventType.values().length); + } + if (null == connectionEventProcessorMap.get(ConnectionEventType.CLOSE)) { + ClientConnectionCloseEventProcessor connectionCloseEventProcessor = new ClientConnectionCloseEventProcessor(); + connectionEventProcessorMap.put(ConnectionEventType.CLOSE, + connectionCloseEventProcessor); + } + if (null == connectionEventProcessorMap.get(ConnectionEventType.CONNECT)) { + ClientConnectionOpenEventProcessor connectionOpenEventProcessor = new ClientConnectionOpenEventProcessor(); + connectionEventProcessorMap.put(ConnectionEventType.CONNECT, + connectionOpenEventProcessor); + } + + // init client connection and register worker + client = new ClientConnection(serverManager, userProcessorList, + connectionEventProcessorMap, registerCache, registryClientConfig); + + workerThread = new WorkerThread(client, registryClientConfig, registerCache); + client.setWorker(workerThread); + + client.init(); + + // init registry check thread + new RegistryCheckThread().start(); + + // init sync config thread + new SyncConfigThread(client, registerCache, registryClientConfig, observerHandler).start(); + } + + /** + * @see RegistryClient#register(PublisherRegistration, String...) + */ + @Override + public Publisher register(PublisherRegistration registration, String... data) { + if (!init.get()) { + throw new IllegalStateException("Client needs to be initialized before using."); + } + + if (null == registration) { + throw new IllegalArgumentException("Registration can not be null."); + } + + if (StringUtils.isBlank(registration.getDataId())) { + throw new IllegalArgumentException("DataId can not be null"); + } + + if (StringUtils.isBlank(registration.getGroup())) { + registration.setGroup(DEFAULT_GROUP); + } + + Publisher publisher = registrationPublisherMap.get(registration); + + if (null != publisher) { + throwDuplicateException(registration, publisher); + } + + publisher = new DefaultPublisher(registration, workerThread, registryClientConfig); + ((DefaultPublisher) publisher).setAuthManager(authManager); + + Publisher oldPublisher = registrationPublisherMap.putIfAbsent(registration, publisher); + if (null != oldPublisher) { + throwDuplicateException(registration, oldPublisher); + } + + registerCache.addRegister(publisher); + + publisher.republish(data); + + LOGGER.info("[api] Regist publisher success, dataId: {}, group: {}, registerId: {}", + publisher.getDataId(), publisher.getGroup(), publisher.getRegistId()); + + return publisher; + } + + private void throwDuplicateException(PublisherRegistration registration, Publisher publisher) { + LOGGER.info("[api] Publisher already exists, dataId: {}, group: {}, registerId: {}", + publisher.getDataId(), publisher.getGroup(), publisher.getRegistId()); + + throw new DuplicateException("Duplicate Publisher registration. (dataId: " + + registration.getDataId() + ", group: " + + registration.getGroup() + ")"); + } + + /** + * @see RegistryClient#register(SubscriberRegistration) + */ + @Override + public Subscriber register(SubscriberRegistration registration) { + if (!init.get()) { + throw new IllegalStateException("Client needs to be initialized before using."); + } + + if (null == registration) { + throw new IllegalArgumentException("Registration can not be null."); + } + + if (StringUtils.isBlank(registration.getDataId())) { + throw new IllegalArgumentException("DataId can not be null."); + } + + if (null == registration.getSubscriberDataObserver()) { + throw new IllegalArgumentException("Subscriber data observer can not be null."); + } + + if (StringUtils.isBlank(registration.getGroup())) { + registration.setGroup(DEFAULT_GROUP); + } + + Subscriber subscriber = registrationSubscriberMap.get(registration); + + if (null != subscriber) { + throwDuplicateException(registration, subscriber); + } + + subscriber = new DefaultSubscriber(registration, workerThread, registryClientConfig); + ((DefaultSubscriber) subscriber).setAuthManager(authManager); + + Subscriber oldSubscriber = registrationSubscriberMap.putIfAbsent(registration, subscriber); + if (null != oldSubscriber) { + throwDuplicateException(registration, oldSubscriber); + } + + registerCache.addRegister(subscriber); + addRegisterTask(subscriber); + + LOGGER.info( + "[api] Regist subscriber success, dataId: {}, group: {}, scope: {}, registerId: {}", + subscriber.getDataId(), subscriber.getGroup(), subscriber.getScopeEnum(), + subscriber.getRegistId()); + + return subscriber; + } + + /** + * @see RegistryClient#register(ConfiguratorRegistration) + */ + @Override + public Configurator register(ConfiguratorRegistration registration) { + if (!init.get()) { + throw new IllegalStateException("Client needs to be initialized before using."); + } + + if (null == registration) { + throw new IllegalArgumentException("Registration can not be null."); + } + + if (StringUtils.isBlank(registration.getDataId())) { + throw new IllegalArgumentException("DataId can not be null."); + } + + if (null == registration.getConfigDataObserver()) { + throw new IllegalArgumentException("Config data observer can not be null"); + } + + if (StringUtils.isBlank(registration.getGroup())) { + registration.setGroup(DEFAULT_GROUP); + } + + Configurator configurator = registrationConfiguratorMap.get(registration); + + if (null != configurator) { + throwDuplicateException(configurator); + } + + configurator = new DefaultConfigurator(registration, registryClientConfig, workerThread); + ((DefaultConfigurator) configurator).setAuthManager(authManager); + + Configurator oldConfigurator = registrationConfiguratorMap.putIfAbsent(registration, + configurator); + if (null != oldConfigurator) { + throwDuplicateException(configurator); + } + + registerCache.addRegister(configurator); + addRegisterTask(configurator); + + LOGGER.info("[api] Regist configurator success, dataId: {}, registerId: {}", + configurator.getDataId(), configurator.getRegistId()); + + return configurator; + } + + private void throwDuplicateException(Configurator configurator) { + LOGGER.info("[api] Configurator already exists, dataId: {}, registerId: {}", + configurator.getDataObserver(), configurator.getRegistId()); + throw new DuplicateException("Duplicate configurator registration. (dataId: " + + configurator.getDataId() + " )"); + } + + /** + * @see RegistryClient#unregister(String, String, RegistryType) + */ + @Override + public int unregister(String dataId, String group, RegistryType registryType) { + if (StringUtils.isBlank(dataId)) { + throw new IllegalArgumentException("dataId can not be empty"); + } + + if (null == registryType) { + throw new IllegalArgumentException("registry type can not be null"); + } + + if (null == group) { + group = DEFAULT_GROUP; + } + + List registers = new ArrayList(); + + if (RegistryType.PUBLISHER == registryType) { + Collection publishers = registerCache.getAllPublishers(); + for (Publisher publisher : publishers) { + if (dataId.equals(publisher.getDataId()) && group.equals(publisher.getGroup())) { + registers.add(publisher); + } + } + } else if (RegistryType.SUBSCRIBER == registryType) { + Collection subscribers = registerCache.getAllSubscribers(); + for (Subscriber subscriber : subscribers) { + if (dataId.equals(subscriber.getDataId()) && group.equals(subscriber.getGroup())) { + registers.add(subscriber); + } + } + } else if (RegistryType.CONFIGURATOR == registryType) { + Collection configurators = registerCache.getAllConfigurator(); + for (Configurator configurator : configurators) { + if (dataId.equals(configurator.getDataId())) { + registers.add(configurator); + } + } + } + + for (Register register : registers) { + register.unregister(); + } + return registers.size(); + } + + private void throwDuplicateException(SubscriberRegistration registration, Subscriber subscriber) { + LOGGER.info( + "[api] Subscriber already exists, dataId: {}, group: {}, scope: {}, registerId: {}", + subscriber.getDataId(), subscriber.getGroup(), subscriber.getScopeEnum(), + subscriber.getRegistId()); + throw new DuplicateException("Duplicate subscriber registration. (dataId: " + + registration.getDataId() + ", group: " + + registration.getGroup() + ")"); + } + + /** + * Add register task. + * + * @param register the register + * @throws RegistryClientException the registry client exception + */ + private void addRegisterTask(Register register) throws RegistryClientException { + try { + TaskEvent event = new TaskEvent(register); + workerThread.schedule(event); + } catch (Exception e) { + LOGGER.error("Register task schedule error, {}", register, e); + throw new RegistryClientException("Register task schedule error", e); + } + } + + /** + * Getter method for property registerCache. + * + * @return property value of registerCache + */ + public RegisterCache getRegisterCache() { + return registerCache; + } + + /** + * Setter method for property userProcessorMap. + * + * @param userProcessorMap value to be assigned to property userProcessorMap + */ + public void setUserProcessorMap(Map, UserProcessor> userProcessorMap) { + this.userProcessorMap = userProcessorMap; + } + + /** + * Setter method for property connectionEventProcessorMap. + * + * @param connectionEventProcessorMap value to be assigned to property connectionEventProcessorMap + */ + public void setConnectionEventProcessorMap(Map connectionEventProcessorMap) { + this.connectionEventProcessorMap = connectionEventProcessorMap; + } + + /** + * Setter method for property observerHandler. + * + * @param observerHandler value to be assigned to property observerHandler + */ + public void setObserverHandler(ObserverHandler observerHandler) { + this.observerHandler = observerHandler; + } + + /** + * Setter method for property serverManager. + * + * @param serverManager value to be assigned to property serverManager + */ + public void setServerManager(ServerManager serverManager) { + this.serverManager = serverManager; + } + + /** + * Setter method for property authManager. + * + * @param authManager value to be assigned to property authManager + */ + public void setAuthManager(AuthManager authManager) { + this.authManager = authManager; + } + + /** + * Setter method for property lookoutSubscriber. + * + * @param lookoutSubscriber value to be assigned to property lookoutSubscriber + */ + public void setLookoutSubscriber(LookoutSubscriber lookoutSubscriber) { + this.lookoutSubscriber = lookoutSubscriber; + } + + /** + * Setter method for property eventBus. + * + * @param eventBus value to be assigned to property eventBus + */ + public void setEventBus(EventBus eventBus) { + this.eventBus = eventBus; + } + + /** + * The type Registry check thread. + */ + class RegistryCheckThread extends Thread { + + /** + * Instantiates a new Registry check thread. + */ + public RegistryCheckThread() { + super("RegistryClientCheckThread"); + setDaemon(true); + } + + /** + * @see Thread#run() + */ + @Override + public void run() { + + //noinspection InfiniteLoopStatement + while (true) { + try { + Thread.sleep(registryClientConfig.getRecheckInterval()); + + Collection allPublishers = registerCache.getAllPublishers(); + + for (Publisher publisher : allPublishers) { + try { + if (null != publisher + && !((AbstractInternalRegister) publisher).isDone()) { + addRegisterTask(publisher); + } + } catch (Exception e) { + LOGGER.error("Sync publisher error, {}", publisher, e); + } + } + + Collection allSubscribers = registerCache.getAllSubscribers(); + + for (Subscriber subscriber : allSubscribers) { + try { + if (null != subscriber + && !((AbstractInternalRegister) subscriber).isDone()) { + addRegisterTask(subscriber); + } + } catch (Exception e) { + LOGGER.error("Sync subscriber error, {}", subscriber, e); + } + } + + Collection allConfigurators = registerCache.getAllConfigurator(); + + for (Configurator configurator : allConfigurators) { + try { + if (null != configurator + && !((AbstractInternalRegister) configurator).isDone()) { + addRegisterTask(configurator); + } + } catch (Exception e) { + LOGGER.error("Sync configurator error, {}", configurator, e); + } + } + } catch (Throwable e) { + LOGGER.error("Execute error", e); + } + } + } + + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfig.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfig.java new file mode 100644 index 000000000..ee8c4caca --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfig.java @@ -0,0 +1,462 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; + +/** + * The type Default registry client config. + * + * @author zhuoyu.sjw + * @version $Id : DefaultRegistryClientConfig.java, v 0.1 2017-11-23 20:11 zhuoyu.sjw Exp $$ + */ +public class DefaultRegistryClientConfig implements RegistryClientConfig { + + /** */ + private String env; + + /** */ + private String instanceId; + + /** */ + private String zone; + + /** */ + private String registryEndpoint; + + /** */ + private int registryEndpointPort; + + /** */ + private String dataCenter; + + /** */ + private String appName; + + /** */ + private int connectTimeout; + + /** */ + private int socketTimeout; + + /** */ + private int invokeTimeout; + + /** */ + private int recheckInterval; + + /** */ + private int observerThreadCoreSize; + + /** */ + private int observerThreadMaxSize; + + /** */ + private int observerThreadQueueLength; + + /** */ + private int observerCallbackTimeout; + + /** */ + private int syncConfigRetryInterval; + + /** */ + private String accessKey; + + /** */ + private String secretKey; + + /** */ + private String algorithm; + + /** */ + private long authCacheInterval; + + /** */ + private boolean eventBusEnable; + + /** + * Instantiates a new Default registry client config. + * + * @param env the env + * @param instanceId the instance id + * @param zone the zone + * @param registryEndpoint the registry endpoint + * @param registryEndpointPort the registry endpoint port + * @param dataCenter the data center + * @param appName the app name + * @param connectTimeout the connect timeout + * @param socketTimeout the socket timeout + * @param invokeTimeout the invoke timeout + * @param recheckInterval the recheck interval + * @param observerThreadCoreSize the observer thread core size + * @param observerThreadMaxSize the observer thread max size + * @param observerThreadQueueLength the observer thread queue length + * @param observerCallbackTimeout the observer callback timeout + * @param syncConfigRetryInterval the sync config retry interval + * @param accessKey the access key + * @param secretKey the secret key + * @param algorithm the algorithm + * @param authCacheInterval the auth cache interval + */ + public DefaultRegistryClientConfig(String env, String instanceId, String zone, + String registryEndpoint, int registryEndpointPort, + String dataCenter, String appName, int connectTimeout, + int socketTimeout, int invokeTimeout, int recheckInterval, + int observerThreadCoreSize, int observerThreadMaxSize, + int observerThreadQueueLength, int observerCallbackTimeout, + int syncConfigRetryInterval, String accessKey, + String secretKey, String algorithm, long authCacheInterval, + boolean eventBusEnable) { + this.env = env; + this.instanceId = instanceId; + this.zone = zone; + this.registryEndpoint = registryEndpoint; + this.registryEndpointPort = registryEndpointPort; + this.dataCenter = dataCenter; + this.appName = appName; + this.connectTimeout = connectTimeout; + this.socketTimeout = socketTimeout; + this.invokeTimeout = invokeTimeout; + this.recheckInterval = recheckInterval; + this.observerThreadCoreSize = observerThreadCoreSize; + this.observerThreadMaxSize = observerThreadMaxSize; + this.observerThreadQueueLength = observerThreadQueueLength; + this.observerCallbackTimeout = observerCallbackTimeout; + this.syncConfigRetryInterval = syncConfigRetryInterval; + this.accessKey = accessKey; + this.secretKey = secretKey; + this.algorithm = algorithm; + this.authCacheInterval = authCacheInterval; + this.eventBusEnable = eventBusEnable; + } + + /** + * Getter method for property env. + * + * @return property value of env + */ + @Override + public String getEnv() { + return env; + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + @Override + public String getInstanceId() { + return instanceId; + } + + /** + * Getter method for property zone. + * + * @return property value of zone + */ + @Override + public String getZone() { + return zone; + } + + /** + * Getter method for property registryEndpoint. + * + * @return property value of registryEndpoint + */ + @Override + public String getRegistryEndpoint() { + return registryEndpoint; + } + + /** + * Getter method for property registryEndpointPort. + * + * @return property value of registryEndpointPort + */ + @Override + public int getRegistryEndpointPort() { + return registryEndpointPort; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + @Override + public String getDataCenter() { + return dataCenter; + } + + /** + * Getter method for property appName. + * + * @return property value of appName + */ + @Override + public String getAppName() { + return appName; + } + + /** + * Getter method for property connectTimeout. + * + * @return property value of connectTimeout + */ + @Override + public int getConnectTimeout() { + return connectTimeout; + } + + /** + * Getter method for property socketTimeout. + * + * @return property value of socketTimeout + */ + @Override + public int getSocketTimeout() { + return socketTimeout; + } + + /** + * Getter method for property invokeTimeout. + * + * @return property value of invokeTimeout + */ + @Override + public int getInvokeTimeout() { + return invokeTimeout; + } + + /** + * Getter method for property recheckInterval. + * + * @return property value of recheckInterval + */ + @Override + public int getRecheckInterval() { + return recheckInterval; + } + + /** + * Getter method for property observerThreadCoreSize. + * + * @return property value of observerThreadCoreSize + */ + @Override + public int getObserverThreadCoreSize() { + return observerThreadCoreSize; + } + + /** + * Getter method for property observerThreadMaxSize. + * + * @return property value of observerThreadMaxSize + */ + @Override + public int getObserverThreadMaxSize() { + return observerThreadMaxSize; + } + + /** + * Getter method for property observerThreadQueueLength. + * + * @return property value of observerThreadQueueLength + */ + @Override + public int getObserverThreadQueueLength() { + return observerThreadQueueLength; + } + + /** + * Getter method for property observerCallbackTimeout. + * + * @return property value of observerCallbackTimeout + */ + @Override + public int getObserverCallbackTimeout() { + return observerCallbackTimeout; + } + + /** + * Getter method for property syncConfigRetryInterval. + * + * @return property value of syncConfigRetryInterval + */ + @Override + public int getSyncConfigRetryInterval() { + return syncConfigRetryInterval; + } + + /** + * Getter method for property accessKey. + * + * @return property value of accessKey + */ + @Override + public String getAccessKey() { + return accessKey; + } + + /** + * Getter method for property secretKey. + * + * @return property value of secretKey + */ + @Override + public String getSecretKey() { + return secretKey; + } + + /** + * Getter method for property algorithm. + * + * @return property value of algorithm + */ + @Override + public String getAlgorithm() { + return algorithm; + } + + /** + * Setter method for property algorithm. + * + * @param algorithm value to be assigned to property algorithm + */ + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + /** + * Getter method for property authCacheInterval. + * + * @return property value of authCacheInterval + */ + @Override + public long getAuthCacheInterval() { + return authCacheInterval; + } + + /** + * Setter method for property authCacheInterval. + * + * @param authCacheInterval value to be assigned to property authCacheInterval + */ + public void setAuthCacheInterval(long authCacheInterval) { + this.authCacheInterval = authCacheInterval; + } + + /** + * Getter method for property eventBusEnable. + * + * @return property value of eventBusEnable + */ + @Override + public boolean isEventBusEnable() { + return eventBusEnable; + } + + /** + * Setter method for property eventBusEnable. + * + * @param eventBusEnable value to be assigned to property eventBusEnable + */ + public void setEventBusEnable(boolean eventBusEnable) { + this.eventBusEnable = eventBusEnable; + } + + /** + * Equals boolean. + * + * @param o the o + * @return the boolean + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DefaultRegistryClientConfig)) { + return false; + } + + DefaultRegistryClientConfig that = (DefaultRegistryClientConfig) o; + + if (registryEndpointPort != that.registryEndpointPort) { + return false; + } + if (env != null ? !env.equals(that.env) : that.env != null) { + return false; + } + if (instanceId != null ? !instanceId.equals(that.instanceId) : that.instanceId != null) { + return false; + } + if (zone != null ? !zone.equals(that.zone) : that.zone != null) { + return false; + } + if (registryEndpoint != null ? !registryEndpoint.equals(that.registryEndpoint) + : that.registryEndpoint != null) { + return false; + } + if (dataCenter != null ? !dataCenter.equals(that.dataCenter) : that.dataCenter != null) { + return false; + } + return appName != null ? appName.equals(that.appName) : that.appName == null; + } + + /** + * Hash code int. + * + * @return the int + */ + @Override + public int hashCode() { + int result = env != null ? env.hashCode() : 0; + result = 31 * result + (instanceId != null ? instanceId.hashCode() : 0); + result = 31 * result + (zone != null ? zone.hashCode() : 0); + result = 31 * result + (registryEndpoint != null ? registryEndpoint.hashCode() : 0); + result = 31 * result + registryEndpointPort; + result = 31 * result + (dataCenter != null ? dataCenter.hashCode() : 0); + result = 31 * result + (appName != null ? appName.hashCode() : 0); + return result; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "DefaultRegistryClientConfig{" + "env='" + env + '\'' + ", instanceId='" + + instanceId + '\'' + ", zone='" + zone + '\'' + ", registryEndpoint='" + + registryEndpoint + '\'' + ", registryEndpointPort=" + registryEndpointPort + + ", dataCenter='" + dataCenter + '\'' + ", appName='" + appName + '\'' + + ", connectTimeout=" + connectTimeout + ", socketTimeout=" + socketTimeout + + ", invokeTimeout=" + invokeTimeout + ", recheckInterval=" + recheckInterval + + ", observerThreadCoreSize=" + observerThreadCoreSize + ", observerThreadMaxSize=" + + observerThreadMaxSize + ", observerThreadQueueLength=" + observerThreadQueueLength + + ", observerCallbackTimeout=" + observerCallbackTimeout + + ", syncConfigRetryInterval=" + syncConfigRetryInterval + ", accessKey='" + + accessKey + '\'' + ", secretKey='" + secretKey + '\'' + ", algorithm='" + + algorithm + '\'' + ", authCacheInterval=" + authCacheInterval + + ", eventBusEnable=" + eventBusEnable + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfigBuilder.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfigBuilder.java new file mode 100644 index 000000000..542cda238 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientConfigBuilder.java @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_DATA_CENTER; +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_ZONE; + +/** + * The type Default registry client config builder. + * + * @author zhuoyu.sjw + * @version $Id : DefaultRegistryClientConfig.java, v 0.1 2017-11-23 20:12 zhuoyu.sjw Exp $$ + */ +public class DefaultRegistryClientConfigBuilder { + private String env; + private String instanceId; + private String zone = DEFAULT_ZONE; + private String registryEndpoint; + private int registryEndpointPort = 9603; + private String dataCenter = DEFAULT_DATA_CENTER; + private String appName; + private int connectTimeout = 3000; + private int socketTimeout = 3000; + private int invokeTimeout = 1000; + private int recheckInterval = 500; + private int observerThreadCoreSize = 5; + private int observerThreadMaxSize = 10; + private int observerThreadQueueLength = 1000; + private int observerCallbackTimeout = 5000; + private int syncConfigRetryInterval = 30000; + private String accessKey; + private String secretKey; + private String algorithm = "HmacSHA256"; + private long authCacheInterval = 5 * 60 * 1000; + private boolean eventBusEnable = true; + + /** + * Start default registry client config builder. + * + * @return the default registry client config builder + */ + public static DefaultRegistryClientConfigBuilder start() { + return new DefaultRegistryClientConfigBuilder(); + } + + /** + * Sets env. + * + * @param env the env + * @return the env + */ + public DefaultRegistryClientConfigBuilder setEnv(String env) { + this.env = env; + return this; + } + + /** + * Sets instance id. + * + * @param instanceId the instance id + * @return the instance id + */ + public DefaultRegistryClientConfigBuilder setInstanceId(String instanceId) { + this.instanceId = instanceId; + return this; + } + + /** + * Sets zone. + * + * @param zone the zone + * @return the zone + */ + public DefaultRegistryClientConfigBuilder setZone(String zone) { + this.zone = zone; + return this; + } + + /** + * Sets registry endpoint. + * + * @param registryEndpoint the registry endpoint + * @return the registry endpoint + */ + public DefaultRegistryClientConfigBuilder setRegistryEndpoint(String registryEndpoint) { + this.registryEndpoint = registryEndpoint; + return this; + } + + /** + * Sets registry endpoint port. + * + * @param registryEndpointPort the registry endpoint port + * @return the registry endpoint port + */ + public DefaultRegistryClientConfigBuilder setRegistryEndpointPort(int registryEndpointPort) { + this.registryEndpointPort = registryEndpointPort; + return this; + } + + /** + * Sets data center. + * + * @param dataCenter the data center + * @return the data center + */ + public DefaultRegistryClientConfigBuilder setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + return this; + } + + /** + * Sets app name. + * + * @param appName the app name + * @return the app name + */ + public DefaultRegistryClientConfigBuilder setAppName(String appName) { + this.appName = appName; + return this; + } + + /** + * Setter method for property observerThreadCoreSize. + * + * @param observerThreadCoreSize value to be assigned to property observerThreadCoreSize + */ + public DefaultRegistryClientConfigBuilder setObserverThreadCoreSize(int observerThreadCoreSize) { + this.observerThreadCoreSize = observerThreadCoreSize; + return this; + } + + /** + * Setter method for property observerThreadMaxSize. + * + * @param observerThreadMaxSize value to be assigned to property observerThreadMaxSize + */ + public DefaultRegistryClientConfigBuilder setObserverThreadMaxSize(int observerThreadMaxSize) { + this.observerThreadMaxSize = observerThreadMaxSize; + return this; + } + + /** + * Setter method for property observerThreadQueueLength. + * + * @param observerThreadQueueLength value to be assigned to property observerThreadQueueLength + */ + public DefaultRegistryClientConfigBuilder setObserverThreadQueueLength(int observerThreadQueueLength) { + this.observerThreadQueueLength = observerThreadQueueLength; + return this; + } + + /** + * Setter method for property observerCallbackTimeout. + * + * @param observerCallbackTimeout value to be assigned to property observerCallbackTimeout + */ + public DefaultRegistryClientConfigBuilder setObserverCallbackTimeout(int observerCallbackTimeout) { + this.observerCallbackTimeout = observerCallbackTimeout; + return this; + } + + /** + * Sets connect timeout. + * + * @param connectTimeout the connect timeout + * @return the connect timeout + */ + public DefaultRegistryClientConfigBuilder setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + return this; + } + + /** + * Sets socket timeout. + * + * @param socketTimeout the socket timeout + * @return the socket timeout + */ + public DefaultRegistryClientConfigBuilder setSocketTimeout(int socketTimeout) { + this.socketTimeout = socketTimeout; + return this; + } + + /** + * Sets invoke timeout. + * + * @param invokeTimeout the invoke timeout + * @return the invoke timeout + */ + public DefaultRegistryClientConfigBuilder setInvokeTimeout(int invokeTimeout) { + this.invokeTimeout = invokeTimeout; + return this; + } + + /** + * Sets recheck interval. + * + * @param recheckInterval the recheck interval + * @return the recheck interval + */ + public DefaultRegistryClientConfigBuilder setRecheckInterval(int recheckInterval) { + this.recheckInterval = recheckInterval; + return this; + } + + /** + * Setter method for property syncConfigRetryInterval. + * + * @param syncConfigRetryInterval value to be assigned to property syncConfigRetryInterval + */ + public DefaultRegistryClientConfigBuilder setSyncConfigRetryInterval(int syncConfigRetryInterval) { + this.syncConfigRetryInterval = syncConfigRetryInterval; + return this; + } + + /** + * Setter method for property accessKey. + * + * @param accessKey value to be assigned to property accessKey + */ + public DefaultRegistryClientConfigBuilder setAccessKey(String accessKey) { + this.accessKey = accessKey; + return this; + } + + /** + * Setter method for property secretKey. + * + * @param secretKey value to be assigned to property secretKey + */ + public DefaultRegistryClientConfigBuilder setSecretKey(String secretKey) { + this.secretKey = secretKey; + return this; + } + + /** + * Setter method for property algorithm. + * + * @param algorithm value to be assigned to property algorithm + */ + public DefaultRegistryClientConfigBuilder setAlgorithm(String algorithm) { + this.algorithm = algorithm; + return this; + } + + /** + * Setter method for property authCacheInterval. + * + * @param authCacheInterval value to be assigned to property authCacheInterval + */ + public DefaultRegistryClientConfigBuilder setAuthCacheInterval(long authCacheInterval) { + this.authCacheInterval = authCacheInterval; + return this; + } + + /** + * Setter method for property eventBusEnable. + * + * @param eventBusEnable value to be assigned to property eventBusEnable + */ + public DefaultRegistryClientConfigBuilder setEventBusEnable(boolean eventBusEnable) { + this.eventBusEnable = eventBusEnable; + return this; + } + + /** + * Create default registry client config default registry client config. + * + * @return the default registry client config + */ + public DefaultRegistryClientConfig build() { + return new DefaultRegistryClientConfig(env, instanceId, zone, registryEndpoint, + registryEndpointPort, dataCenter, appName, connectTimeout, socketTimeout, + invokeTimeout, recheckInterval, observerThreadCoreSize, observerThreadMaxSize, + observerThreadQueueLength, observerCallbackTimeout, syncConfigRetryInterval, accessKey, + secretKey, algorithm, authCacheInterval, eventBusEnable); + } +} \ No newline at end of file diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerManager.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerManager.java new file mode 100644 index 000000000..281cd1d7d --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerManager.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.remoting.ServerManager; +import com.alipay.sofa.registry.client.remoting.ServerNode; +import com.alipay.sofa.registry.client.util.HttpClientUtils; +import com.alipay.sofa.registry.client.util.ServerNodeParser; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The type Default server manager. + * @author zhuoyu.sjw + * @version $Id : DefaultServerManager.java, v 0.1 2017-12-25 11:48 zhuoyu.sjw Exp $$ + */ +public class DefaultServerManager implements ServerManager { + + /** + * The constant MIN_RETRY_INTERVAL. + */ + public static final int MIN_RETRY_INTERVAL = 10000; + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultServerManager.class); + private RegistryClientConfig config; + private Set serverNodes; + private SyncServerListThread syncServerListTask; + + private AtomicBoolean inited = new AtomicBoolean(false); + + /** + * Instantiates a new Default server manager. + * + * @param config the config + */ + public DefaultServerManager(RegistryClientConfig config) { + this.config = config; + this.serverNodes = new HashSet(); + this.syncServerListTask = new SyncServerListThread(config); + } + + /** + * @see ServerManager#getServerList() + */ + @Override + public List getServerList() { + // init once + if (inited.compareAndSet(false, true)) { + this.syncServerListTask.start(); + } + // sync query when server list is empty + if (serverNodes.isEmpty()) { + syncServerList(); + } + return new ArrayList(serverNodes); + } + + /** + * @see ServerManager#random() + */ + @Override + public ServerNode random() { + List urls = getServerList(); + if (null == urls || urls.size() == 0) { + return null; + } + Random random = new Random(); + return urls.get(random.nextInt(urls.size())); + } + + private void syncServerList() { + String url = String.format("http://%s:%d/api/servers/query", config.getRegistryEndpoint(), + config.getRegistryEndpointPort()); + Map params = new HashMap(); + params.put("env", config.getEnv()); + params.put("zone", config.getZone()); + params.put("dataCenter", config.getDataCenter()); + params.put("appName", config.getAppName()); + params.put("instanceId", config.getInstanceId()); + try { + String result = HttpClientUtils.get(url, params, config); + if (null != result) { + String[] servers = result.split(";"); + Set tempNodes = new HashSet(); + for (String server : servers) { + try { + ServerNode serverNode = ServerNodeParser.parse(server); + tempNodes.add(serverNode); + } catch (Exception e) { + LOGGER.error("[serverManager] parse server node error, {}", server, e); + } + } + if (!tempNodes.equals(serverNodes)) { + serverNodes = tempNodes; + LOGGER.info("[serverManager] update nodes success, {}", tempNodes); + } + } + } catch (Exception e) { + LOGGER.error("[serverManager] get server list error", e); + } + } + + /** + * The type Sync server list task. + */ + class SyncServerListThread extends Thread { + + private RegistryClientConfig config; + + /** + * Instantiates a new Sync server list task. + * + * @param config the config + */ + public SyncServerListThread(RegistryClientConfig config) { + this.setName("SyncServerListThread"); + this.setDaemon(true); + this.config = config; + } + + /** + * @see Thread#run() + */ + @SuppressWarnings("InfiniteLoopStatement") + @Override + public void run() { + int retryInterval; + while (true) { + try { + retryInterval = Math.max(MIN_RETRY_INTERVAL, + config.getSyncConfigRetryInterval()); + Thread.sleep(retryInterval); + + syncServerList(); + } catch (Throwable e) { + LOGGER.error("[serverManager] sync server list task error", e); + } + } + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerNode.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerNode.java new file mode 100644 index 000000000..3e5a067c5 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultServerNode.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.remoting.ServerNode; + +import java.util.Properties; + +/** + * The type Default server node. + * @author zhuoyu.sjw + * @version $Id : DefaultServerNode.java, v 0.1 2018-03-01 17:13 zhuoyu.sjw Exp $$ + */ +public class DefaultServerNode implements ServerNode { + + private String url; + + private String host; + + private int port; + + private Properties properties; + + /** + * Instantiates a new Default server node. + * + * @param url the url + * @param host the host + * @param port the port + * @param properties the properties + */ + public DefaultServerNode(String url, String host, int port, Properties properties) { + this.url = url; + this.host = host; + this.port = port; + this.properties = properties; + } + + /** + * Gets host. + * + * @return the host + */ + @Override + public String getHost() { + return host; + } + + /** + * Gets port. + * + * @return the port + */ + @Override + public int getPort() { + return port; + } + + /** + * Gets url. + * + * @return the url + */ + @Override + public String getUrl() { + return url; + } + + /** + * Gets properties. + * + * @return the properties + */ + @Override + public Properties getProperties() { + return properties; + } + + /** + * Setter method for property url. + * + * @param url value to be assigned to property url + */ + public void setUrl(String url) { + this.url = url; + } + + /** + * Setter method for property host. + * + * @param host value to be assigned to property host + */ + public void setHost(String host) { + this.host = host; + } + + /** + * Setter method for property port. + * + * @param port value to be assigned to property port + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Setter method for property properties. + * + * @param properties value to be assigned to property properties + */ + public void setProperties(Properties properties) { + this.properties = properties; + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DefaultServerNode)) { + return false; + } + + DefaultServerNode that = (DefaultServerNode) o; + + if (port != that.port) { + return false; + } + if (url != null ? !url.equals(that.url) : that.url != null) { + return false; + } + if (host != null ? !host.equals(that.host) : that.host != null) { + return false; + } + return properties != null ? properties.equals(that.properties) : that.properties == null; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + int result = url != null ? url.hashCode() : 0; + result = 31 * result + (host != null ? host.hashCode() : 0); + result = 31 * result + port; + result = 31 * result + (properties != null ? properties.hashCode() : 0); + return result; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "DefaultServerNode{" + "url='" + url + '\'' + ", host='" + host + '\'' + ", port=" + + port + ", properties=" + properties + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultSubscriber.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultSubscriber.java new file mode 100644 index 000000000..f3edf8f4a --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultSubscriber.java @@ -0,0 +1,315 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.client.constants.ValueConstants; +import com.alipay.sofa.registry.client.model.SegmentData; +import com.alipay.sofa.registry.client.task.TaskEvent; +import com.alipay.sofa.registry.client.task.Worker; +import com.alipay.sofa.registry.client.util.CommonUtils; +import com.alipay.sofa.registry.client.util.StringUtils; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.core.model.SubscriberRegister; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The type Default subscriber multi. + * + * @author zhuoyu.sjw + * @version $Id : DefaultSubscriber.java, v 0.1 2017-11-23 22:13 zhuoyu.sjw Exp $$ + */ +public class DefaultSubscriber extends AbstractInternalRegister implements Subscriber { + + private final String REGIST_ID; + private SubscriberDataObserver dataObserver; + private ConcurrentHashMap data = new ConcurrentHashMap(); + private AtomicBoolean init = new AtomicBoolean(false); + private RegistryClientConfig config; + private SubscriberRegistration registration; + private Worker worker; + private volatile String localZone; + private List availableSegments = new ArrayList(); + + /** + * Instantiates a new Default subscriber multi. + * + * @param registration the registration + */ + DefaultSubscriber(SubscriberRegistration registration, Worker worker, + RegistryClientConfig config) { + if (null != registration) { + this.dataObserver = registration.getSubscriberDataObserver(); + } + this.registration = registration; + this.worker = worker; + this.config = config; + this.REGIST_ID = UUID.randomUUID().toString(); + this.localZone = config.getZone(); + this.getPubVersion().incrementAndGet(); + } + + /** + * @see Subscriber#getDataObserver() + */ + @Override + public SubscriberDataObserver getDataObserver() { + return dataObserver; + } + + /** + * @see Subscriber#setDataObserver(SubscriberDataObserver) + */ + @Override + public void setDataObserver(SubscriberDataObserver dataObserver) { + this.dataObserver = dataObserver; + } + + /** + * @see Subscriber#peekData() + */ + @Override + public UserData peekData() { + readLock.lock(); + try { + if (!init.get()) { + //todo sync read from server + return new DefaultUserData(); + } + Set> values = data.entrySet(); + DefaultUserData userData = new DefaultUserData(); + if (null == localZone) { + userData.setLocalZone(config.getZone()); + } else { + userData.setLocalZone(localZone); + } + Map> zoneMap = new HashMap>(); + for (Entry segmentDataEntry : values) { + String segment = segmentDataEntry.getKey(); + + // only accept available segments, when available segments is empty accept all + if (CommonUtils.isNotEmpty(availableSegments) + && !availableSegments.contains(segment)) { + continue; + } + + SegmentData segmentData = segmentDataEntry.getValue(); + + if (null == segmentData) { + continue; + } + + Map> data = segmentData.getData(); + for (Entry> entry : data.entrySet()) { + String zone = entry.getKey(); + List resultList = zoneMap.get(zone); + if (null == resultList) { + resultList = new ArrayList(); + zoneMap.put(zone, resultList); + } + List dataList = entry.getValue(); + for (DataBox dataBox : dataList) { + resultList.add(dataBox.getData()); + } + } + } + userData.setZoneData(zoneMap); + return userData; + } finally { + readLock.unlock(); + } + } + + /** + * Gets scope enum. + * + * @return the scope enum + */ + @Override + public ScopeEnum getScopeEnum() { + return registration.getScopeEnum(); + } + + /** + * Unregister. + */ + @Override + public void unregister() { + if (isEnabled()) { + super.unregister(); + worker.schedule(new TaskEvent(this)); + } + } + + /** + * Assembly subscriber register. + * + * @return the subscriber register + */ + @Override + public SubscriberRegister assembly() { + readLock.lock(); + SubscriberRegister register; + try { + if (null == registration.getScopeEnum()) { + registration.setScopeEnum(ScopeEnum.zone); + } + + register = new SubscriberRegister(); + register.setInstanceId(config.getInstanceId()); + if (StringUtils.isNotEmpty(config.getZone())) { + register.setZone(config.getZone()); + } else { + register.setZone(ValueConstants.DEFAULT_ZONE); + } + if (StringUtils.isNotEmpty(registration.getAppName())) { + register.setAppName(registration.getAppName()); + } else { + register.setAppName(config.getAppName()); + } + register.setDataId(registration.getDataId()); + register.setGroup(registration.getGroup()); + register.setRegistId(REGIST_ID); + register.setVersion(this.getPubVersion().get()); + register.setTimestamp(this.getTimestamp()); + register.setScope(registration.getScopeEnum().name()); + + // auth signature + setAuthSignature(register); + + if (isEnabled()) { + register.setEventType(EventTypeConstants.REGISTER); + } else { + register.setEventType(EventTypeConstants.UNREGISTER); + } + } finally { + readLock.unlock(); + } + return register; + } + + public void putReceivedData(SegmentData segmentData, String localZone) { + writeLock.lock(); + try { + putSegmentData(segmentData); + this.localZone = localZone; + } finally { + writeLock.unlock(); + } + } + + private void putSegmentData(SegmentData segmentData) { + if (null != segmentData) { + + SegmentData existsData = data.putIfAbsent(segmentData.getSegment(), segmentData); + if (null == existsData) { + init.compareAndSet(false, true); + return; + } + + if (existsData.getVersion() < segmentData.getVersion()) { + boolean result = data.replace(segmentData.getSegment(), existsData, segmentData); + if (!result) { + putSegmentData(segmentData); + } + init.compareAndSet(false, true); + } + } + } + + /** + * Gets data id. + * + * @return the data id + */ + @Override + public String getDataId() { + return registration.getDataId(); + } + + /** + * Gets group. + * + * @return the group + */ + @Override + public String getGroup() { + return registration.getGroup(); + } + + /** + * Gets regist id. + * + * @return the regist id + */ + @Override + public String getRegistId() { + return REGIST_ID; + } + + /** + * Getter method for property availableSegments. + * + * @return property value of availableSegments + */ + public List getAvailableSegments() { + readLock.lock(); + try { + return new ArrayList(availableSegments); + } finally { + readLock.unlock(); + } + } + + /** + * Setter method for property availableSegments. + * + * @param availableSegments value to be assigned to property availableSegments + */ + public void setAvailableSegments(List availableSegments) { + writeLock.lock(); + try { + if (null == availableSegments) { + this.availableSegments = new ArrayList(); + } else { + this.availableSegments = new ArrayList(availableSegments); + } + } finally { + writeLock.unlock(); + } + } + + @Override + public String toString() { + return "DefaultSubscriber{" + "registration=" + registration + '}' + super.toString(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultUserData.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultUserData.java new file mode 100644 index 000000000..a47d52b28 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/DefaultUserData.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.model.UserData; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author zhuoyu.sjw + * @version $Id: DefaultUserData.java, v 0.1 2017-11-30 21:01 zhuoyu.sjw Exp $$ + */ +public class DefaultUserData implements UserData { + + /** zone, List */ + private Map> zoneData = new ConcurrentHashMap>(); + + /** The current client`s zone */ + private String localZone; + + /** + * Getter method for property zoneData. + * + * @return property value of zoneData + */ + @Override + public Map> getZoneData() { + return zoneData; + } + + /** + * Setter method for property zoneData. + * + * @param zoneData value to be assigned to property zoneData + */ + public void setZoneData(Map> zoneData) { + this.zoneData = zoneData; + } + + /** + * Getter method for property localZone. + * + * @return property value of localZone + */ + @Override + public String getLocalZone() { + return localZone; + } + + /** + * Setter method for property localZone. + * + * @param localZone value to be assigned to property localZone + */ + public void setLocalZone(String localZone) { + this.localZone = localZone; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "DefaultUserData{" + "zoneData=" + zoneData + ", localZone='" + localZone + '\'' + + '}'; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/RegisterCache.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/RegisterCache.java new file mode 100644 index 000000000..ee35272a8 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/provider/RegisterCache.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.Publisher; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.util.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * The type Register cache. + * @author zhuoyu.sjw + * @version $Id : RegisterCache.java, v 0.1 2017-11-30 18:18 zhuoyu.sjw Exp $$ + */ +public class RegisterCache { + + /** + * publisher register cache Map + */ + private Map publisherMap = new ConcurrentHashMap(); + /** + * subscriber register cache Map + */ + private Map subscriberMap = new ConcurrentHashMap(); + /** + * configurator register cache Map + */ + private Map configuratorMap = new ConcurrentHashMap(); + + /** + * Add register. + * + * @param publisher the publisher + */ + public void addRegister(Publisher publisher) { + if (null == publisher || StringUtils.isEmpty(publisher.getDataId())) { + return; + } + + publisherMap.put(publisher.getRegistId(), publisher); + } + + /** + * Add register. + * + * @param subscriber the subscriber + */ + public void addRegister(Subscriber subscriber) { + if (null == subscriber || StringUtils.isEmpty(subscriber.getDataId())) { + return; + } + + subscriberMap.put(subscriber.getRegistId(), subscriber); + } + + /** + * Add register. + * + * @param configurator the configurator + */ + public void addRegister(Configurator configurator) { + if (null == configurator || StringUtils.isEmpty(configurator.getDataId())) { + return; + } + + configuratorMap.put(configurator.getRegistId(), configurator); + } + + /** + * Remove. + * + * @param registId the regist id + */ + public void remove(String registId) { + if (publisherMap.remove(registId) == null) { + if (subscriberMap.remove(registId) == null) { + configuratorMap.remove(registId); + } + } + } + + /** + * Gets publisher by regist id. + * + * @param registId the regist id + * @return the publisher by regist id + */ + public Publisher getPublisherByRegistId(String registId) { + return publisherMap.get(registId); + } + + /** + * Gets subscriber by regist id. + * + * @param registId the regist id + * @return the subscriber by regist id + */ + public Subscriber getSubscriberByRegistId(String registId) { + return subscriberMap.get(registId); + } + + /** + * Gets configurator by data id. + * + * @param registId the regist id + * @return the configurator by data id + */ + public Configurator getConfiguratorByRegistId(String registId) { + return configuratorMap.get(registId); + } + + /** + * Gets all publishers. + * + * @return the all publishers + */ + public Collection getAllPublishers() { + return new ArrayList(publisherMap.values()); + } + + /** + * Gets all subscribers. + * + * @return the all subscribers + */ + public Collection getAllSubscribers() { + return new ArrayList(subscriberMap.values()); + } + + /** + * Gets all configurator. + * + * @return the all configurator + */ + public Collection getAllConfigurator() { + return new ArrayList(configuratorMap.values()); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/Client.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/Client.java new file mode 100644 index 000000000..888a31d07 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/Client.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.remoting.exception.RemotingException; + +/** + * The interface Client. + * @author zhuoyu.sjw + * @version $Id : Client.java, v 0.1 2018-03-06 20:43 zhuoyu.sjw Exp $$ + */ +public interface Client { + + /** + * Init. + */ + void init(); + + /** + * Is connected boolean. + * + * @return the boolean + */ + boolean isConnected(); + + /** + * Ensure connected. + * + * @throws InterruptedException the interrupted exception + */ + void ensureConnected() throws InterruptedException; + + /** + * Invoke sync object. + * + * @param request the request + * @return the object + * @throws RemotingException the remoting exception + * @throws InterruptedException the interrupted exception + */ + Object invokeSync(Object request) throws RemotingException, InterruptedException; +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnection.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnection.java new file mode 100644 index 000000000..320b565ff --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnection.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventProcessor; +import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.exception.RemotingException; +import com.alipay.remoting.rpc.RpcClient; +import com.alipay.remoting.rpc.protocol.UserProcessor; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.Publisher; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.task.TaskEvent; +import com.alipay.sofa.registry.client.task.Worker; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Random; + +/** + * The type Client connection. + * @author zhuoyu.sjw + * @version $Id : ClientConnection.java, v 0.1 2018-03-01 16:44 zhuoyu.sjw Exp $$ + */ +public class ClientConnection implements Client { + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(ClientConnection.class); + /** + * The Reconnecting delay. + */ + private final static int RECONNECTING_DELAY = 5000; + private RpcClient client; + private ServerManager serverManager; + private List userProcessorList; + private Map connectionEventProcessorMap; + private RegistryClientConfig config; + private Connection clientConnection; + private RegisterCache registerCache; + private Worker worker; + + /** + * Instantiates a new Client connection. + * + * @param serverManager the server manager + * @param userProcessorList the user processor list + * @param connectionEventProcessorMap the connection event processor map + * @param config the config + */ + public ClientConnection(ServerManager serverManager, + List userProcessorList, + Map connectionEventProcessorMap, + RegisterCache registerCache, RegistryClientConfig config) { + this.client = new RpcClient(); + this.serverManager = serverManager; + this.userProcessorList = userProcessorList; + this.connectionEventProcessorMap = connectionEventProcessorMap; + this.registerCache = registerCache; + this.config = config; + } + + /** + * Init. + */ + @Override + public void init() { + for (UserProcessor userProcessor : userProcessorList) { + client.registerUserProcessor(userProcessor); + } + + if (null != connectionEventProcessorMap) { + for (Entry entry : connectionEventProcessorMap + .entrySet()) { + client.addConnectionEventProcessor(entry.getKey(), entry.getValue()); + } + } + + client.init(); + } + + /** + * Ensure connected. + * + * @throws InterruptedException the interrupted exception + */ + @Override + public void ensureConnected() throws InterruptedException { + if (isConnected()) { + return; + } + while (!connect()) { + Thread.sleep(ClientConnection.RECONNECTING_DELAY); + } + } + + /** + * Connect boolean. + * + * @return the boolean + */ + private boolean connect() { + Random random = new Random(); + Connection connection = null; + List serverNodes = new ArrayList(serverManager.getServerList()); + // shuffle server list to make server connections as discrete as possible + Collections.shuffle(serverNodes); + for (ServerNode serverNode : serverNodes) { + try { + connection = connect(serverNode); + if (null != connection && connection.isFine()) { + resetRegister(); + LOGGER.info("[Connect] Successfully connected to server: {}", serverNode); + break; + } else { + recycle(connection); + } + + Thread.sleep(random.nextInt(RECONNECTING_DELAY)); + } catch (Exception e) { + LOGGER.error("[Connect] Failed trying connect to {}", serverNode, e); + } + } + + if (null != connection && connection.isFine()) { + clientConnection = connection; + return true; + } + return false; + } + + /** + * Invoke sync object. + * + * @param request the request + * @return the object + * @throws RemotingException the remoting exception + * @throws InterruptedException the interrupted exception + */ + @Override + public Object invokeSync(Object request) throws RemotingException, InterruptedException { + if (!isConnected()) { + throw new IllegalStateException("Not connected"); + } + + return client.invokeSync(clientConnection, request, config.getInvokeTimeout()); + } + + private void recycle(Connection connection) { + if (null == connection) { + return; + } + + client.closeConnection(connection.getUrl()); + } + + private Connection connect(ServerNode serverNode) { + Connection connection = null; + try { + connection = client.getConnection(serverNode.getUrl(), config.getConnectTimeout()); + } catch (Exception e) { + LOGGER.error("[connection] Create connection error, {}", serverNode, e); + } + return connection; + } + + private void resetRegister() { + try { + List eventList = new ArrayList(); + + Collection publishers = registerCache.getAllPublishers(); + for (Publisher publisher : publishers) { + try { + publisher.reset(); + eventList.add(new TaskEvent(publisher)); + } catch (Exception e) { + LOGGER.error("[connection] Publisher reset error, {}", publisher, e); + } + } + + Collection subscribers = registerCache.getAllSubscribers(); + for (Subscriber subscriber : subscribers) { + try { + subscriber.reset(); + eventList.add(new TaskEvent(subscriber)); + } catch (Exception e) { + LOGGER.error("[connection] Subscriber reset error, {}", subscriber, e); + } + } + + Collection configurators = registerCache.getAllConfigurator(); + for (Configurator configurator : configurators) { + try { + configurator.reset(); + eventList.add(new TaskEvent(configurator)); + } catch (Exception e) { + LOGGER.error("[connection] Configurator reset error, {}", configurator, e); + } + } + + worker.schedule(eventList); + LOGGER.info("[reset] {} publishers and {} subscribers has been reset", + publishers.size(), subscribers.size()); + } catch (Exception e) { + LOGGER.error("[reset] Reset register after reconnect error", e); + } + } + + /** + * Gets remote address. + * + * @return the remote address + */ + public String getRemoteAddress() { + if (null != clientConnection) { + return clientConnection.getRemoteIP(); + } + return null; + } + + /** + * Is connected boolean. + * + * @return boolean boolean + */ + @Override + public boolean isConnected() { + return clientConnection != null && clientConnection.isFine(); + } + + /** + * Destroy. + */ + public void destroy() { + if (null != clientConnection) { + clientConnection.close(); + } + if (null != client) { + client.shutdown(); + } + } + + /** + * Setter method for property serverManager. + * + * @param serverManager value to be assigned to property serverManager + */ + public void setServerManager(ServerManager serverManager) { + this.serverManager = serverManager; + } + + /** + * Setter method for property userProcessorList. + * + * @param userProcessorList value to be assigned to property userProcessorList + */ + public void setUserProcessorList(List userProcessorList) { + this.userProcessorList = userProcessorList; + } + + /** + * Setter method for property connectionEventProcessorMap. + * + * @param connectionEventProcessorMap value to be assigned to property connectionEventProcessorMap + */ + public void setConnectionEventProcessorMap(Map connectionEventProcessorMap) { + this.connectionEventProcessorMap = connectionEventProcessorMap; + } + + /** + * Setter method for property worker. + * + * @param worker value to be assigned to property worker + */ + public void setWorker(Worker worker) { + this.worker = worker; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionCloseEventProcessor.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionCloseEventProcessor.java new file mode 100644 index 000000000..b8b112368 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionCloseEventProcessor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventProcessor; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import org.slf4j.Logger; + +/** + * The type Client connection close event processor. + * @author zhuoyu.sjw + * @version $Id : ClientConnectionCloseEventProcessor.java, v 0.1 2018-02-26 20:28 zhuoyu.sjw Exp $$ + */ +public class ClientConnectionCloseEventProcessor implements ConnectionEventProcessor { + private static final Logger LOGGER = LoggerFactory + .getLogger(ClientConnectionCloseEventProcessor.class); + + /** + * On event. + * + * @param remoteAddr the remote addr + * @param conn the conn + */ + @Override + public void onEvent(String remoteAddr, Connection conn) { + if (null != conn) { + LOGGER.info("[connection] Client disconnected, remote address: {}, localAddress: {}", + remoteAddr, conn.getLocalAddress()); + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionOpenEventProcessor.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionOpenEventProcessor.java new file mode 100644 index 000000000..7ee2ee987 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ClientConnectionOpenEventProcessor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventProcessor; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import org.slf4j.Logger; + +/** + * The type Client connection close event processor. + * @author zhuoyu.sjw + * @version $Id : ClientConnectionCloseEventProcessor.java, v 0.1 2018-02-26 20:28 zhuoyu.sjw Exp $$ + */ +public class ClientConnectionOpenEventProcessor implements ConnectionEventProcessor { + private static final Logger LOGGER = LoggerFactory + .getLogger(ClientConnectionOpenEventProcessor.class); + + /** + * On event. + * + * @param remoteAddr the remote addr + * @param conn the conn + */ + @Override + public void onEvent(String remoteAddr, Connection conn) { + if (null != conn) { + LOGGER.info("[connection] Client connected, remote address: {}, localAddress: {}", + remoteAddr, conn.getLocalAddress()); + } + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessor.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessor.java new file mode 100644 index 000000000..108598ca4 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessor.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.remoting.BizContext; +import com.alipay.remoting.rpc.protocol.SyncUserProcessor; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.model.ConfiguratorData; +import com.alipay.sofa.registry.client.provider.DefaultConfigurator; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.task.ObserverHandler; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.core.model.Result; +import org.slf4j.Logger; + +import java.util.List; + +/** + * The type Received config data processor. + * @author zhuoyu.sjw + * @version $Id : ReceivedConfigDataProcessor.java, v 0.1 2018-04-18 15:40 zhuoyu.sjw Exp $$ + */ +public class ReceivedConfigDataProcessor extends SyncUserProcessor { + private static final Logger LOGGER = LoggerFactory.getLogger(ReceivedConfigDataProcessor.class); + + private RegisterCache registerCache; + + private ObserverHandler observerHandler; + + /** + * Instantiates a new Received config data processor. + * + * @param registerCache the register cache + * @param observerHandler the observer handler + */ + public ReceivedConfigDataProcessor(RegisterCache registerCache, ObserverHandler observerHandler) { + this.registerCache = registerCache; + this.observerHandler = observerHandler; + } + + /** + * @see com.alipay.remoting.rpc.protocol.UserProcessor#handleRequest(BizContext, Object) + */ + @Override + public Object handleRequest(BizContext bizCtx, ReceivedConfigData request) { + Result result = new Result(); + result.setSuccess(true); + if (null == request) { + return result; + } + + List registIds = request.getConfiguratorRegistIds(); + try { + + ConfiguratorData configuratorData = new ConfiguratorData(); + configuratorData.setDataBox(request.getDataBox()); + configuratorData.setVersion(request.getVersion()); + for (String registId : registIds) { + Configurator configurator = registerCache.getConfiguratorByRegistId(registId); + if (null == configurator) { + continue; + } + + if (configurator instanceof DefaultConfigurator) { + ((DefaultConfigurator) configurator).putConfiguratorData(configuratorData); + try { + observerHandler.notify(configurator); + } catch (Exception e) { + LOGGER + .error( + "[received] add configurator notify task error, dataId: {}, registId: {}", + configurator.getDataId(), configurator.getRegistId(), e); + } + } else { + LOGGER.warn("[received] ignore unknown configurator type: {}", configurator + .getClass().getName()); + } + } + LOGGER + .info( + "[received] receive configurator data save success, dataId: {} version: {} data:{} registIds:{}", + request.getDataId(), request.getVersion(), request.getDataBox(), registIds); + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(""); + LOGGER.info( + "[received] receive configurator data save failed, dataId: {} version: {} data:{}", + request.getDataId(), request.getVersion(), request.getDataBox(), e); + } + return result; + } + + /** + * @see com.alipay.remoting.rpc.protocol.UserProcessor#interest() + */ + @Override + public String interest() { + return ReceivedConfigData.class.getName(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessor.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessor.java new file mode 100644 index 000000000..bf128b396 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessor.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.remoting.BizContext; +import com.alipay.remoting.rpc.protocol.SyncUserProcessor; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.model.SegmentData; +import com.alipay.sofa.registry.client.provider.DefaultSubscriber; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.task.ObserverHandler; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.Result; +import org.slf4j.Logger; + +import java.util.List; + +/** + * The type Received data multi processor. + * @author zhuoyu.sjw + * @version $Id : ReceivedDataProcessor.java, v 0.1 2018-02-27 14:54 zhuoyu.sjw Exp $$ + */ +public class ReceivedDataProcessor extends SyncUserProcessor { + private static final Logger LOGGER = LoggerFactory.getLogger(ReceivedDataProcessor.class); + + private RegisterCache registerCache; + + private ObserverHandler observerHandler; + + /** + * Instantiates a new Received data multi processor. + * + * @param registerCache the register cache + */ + public ReceivedDataProcessor(RegisterCache registerCache, ObserverHandler observerHandler) { + this.registerCache = registerCache; + this.observerHandler = observerHandler; + } + + /** + * Handle request object. + * + * @param bizCtx the biz ctx + * @param request the request + * @return the object + */ + @Override + public Object handleRequest(BizContext bizCtx, ReceivedData request) { + Result result = new Result(); + result.setSuccess(true); + if (null == request || null == request.getData()) { + return result; + } + try { + List registIds = request.getSubscriberRegistIds(); + + SegmentData segmentData = new SegmentData(); + segmentData.setData(request.getData()); + segmentData.setVersion(request.getVersion()); + segmentData.setSegment(request.getSegment()); + + for (String registId : registIds) { + Subscriber subscriber = registerCache.getSubscriberByRegistId(registId); + if (null == subscriber) { + continue; + } + + if (subscriber instanceof DefaultSubscriber) { + DefaultSubscriber defaultSubscriber = (DefaultSubscriber) subscriber; + defaultSubscriber.putReceivedData(segmentData, request.getLocalZone()); + try { + observerHandler.notify(subscriber); + } catch (Exception e) { + LOGGER.error("[received] add notify task error, dataId: {}, registId: {}", + subscriber.getDataId(), subscriber.getRegistId(), e); + } + } else { + LOGGER.warn("[received] ignore unknown subscriber type: {}", subscriber + .getClass().getName()); + } + } + + LOGGER + .info( + "[received] receive subscriber data save success, dataId: {} group: {} version: {} data:{} registIds:{}", + request.getDataId(), request.getGroup(), request.getVersion(), + request.getData(), registIds); + } catch (Exception e) { + result.setSuccess(false); + result.setMessage(""); + LOGGER + .info( + "[received] receive subscriber data save failed, dataId: {} group: {} version: {} data:{}", + request.getDataId(), request.getGroup(), request.getVersion(), + request.getData(), e); + } + return result; + } + + /** + * Interest string. + * + * @return the string + */ + @Override + public String interest() { + return ReceivedData.class.getName(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerManager.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerManager.java new file mode 100644 index 000000000..cc92a1ef8 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerManager.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import java.util.List; + +/** + * The interface Server manager. + * @author zhuoyu.sjw + * @version $Id : ServerManager.java, v 0.1 2017-12-25 11:42 zhuoyu.sjw Exp $$ + */ +public interface ServerManager { + + /** + * Gets server list. + * + * @return the server list + */ + List getServerList(); + + /** + * Random url. + * + * @return the url + */ + ServerNode random(); +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerNode.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerNode.java new file mode 100644 index 000000000..c9210d1c0 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/remoting/ServerNode.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import java.util.Properties; + +/** + * The interface Server node. + * @author zhuoyu.sjw + * @version $Id : ServerNode.java, v 0.1 2018-03-01 17:07 zhuoyu.sjw Exp $$ + */ +public interface ServerNode { + + /** + * Gets host. + * + * @return the host + */ + String getHost(); + + /** + * Gets port. + * + * @return the port + */ + int getPort(); + + /** + * Gets properties. + * + * @return the properties + */ + Properties getProperties(); + + /** + * Gets url. + * + * @return the url + */ + String getUrl(); +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/AbstractWorkerThread.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/AbstractWorkerThread.java new file mode 100644 index 000000000..c4d6d2673 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/AbstractWorkerThread.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.remoting.Client; + +/** + * The type Abstract worker thread. + * @author zhuoyu.sjw + * @version $Id : AbstractWorkerThread.java, v 0.1 2018-03-01 11:54 zhuoyu.sjw Exp $$ + */ +public abstract class AbstractWorkerThread extends Thread implements Worker { + + /** */ + private final Object bell = new Object(); + + /** + * The Client. + */ + protected Client client; + + /** + * Instantiates a new Abstract worker thread. + * + * @param client the client + */ + public AbstractWorkerThread(Client client) { + this.client = client; + } + + /** + * Notify execute signal for task thread. + */ + void signal() { + synchronized (bell) { + bell.notifyAll(); + } + } + + /** + * Await for next task. + * @param timeout wait timeout + * @throws InterruptedException thread interrupted + */ + void await(long timeout) throws InterruptedException { + synchronized (bell) { + bell.wait(timeout); + } + } + + /** + * @see Runnable#run() + */ + @Override + public void run() { + handle(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/ObserverHandler.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/ObserverHandler.java new file mode 100644 index 000000000..115086d6c --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/ObserverHandler.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.Subscriber; + +/** + * The interface Observer handler. + * @author zhuoyu.sjw + * @version $Id : ObserverHandler.java, v 0.1 2018-03-15 12:15 zhuoyu.sjw Exp $$ + */ +public interface ObserverHandler { + + /** + * Notify. + * + * @param subscriber the subscriber + */ + void notify(Subscriber subscriber); + + /** + * Notify. + * + * @param configurator the configurator + */ + void notify(Configurator configurator); +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/SyncConfigThread.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/SyncConfigThread.java new file mode 100644 index 000000000..646e9615c --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/SyncConfigThread.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.provider.DefaultSubscriber; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.remoting.Client; +import com.alipay.sofa.registry.core.model.SyncConfigRequest; +import com.alipay.sofa.registry.core.model.SyncConfigResponse; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SyncConfigThread.java, v 0.1 2018-03-14 23:36 zhuoyu.sjw Exp $$ + */ +public class SyncConfigThread extends Thread { + private static final Logger LOGGER = LoggerFactory.getLogger(SyncConfigThread.class); + + private Client client; + + private RegisterCache registerCache; + + private RegistryClientConfig config; + + private ObserverHandler observerHandler; + + public SyncConfigThread(Client client, RegisterCache registerCache, + RegistryClientConfig config, ObserverHandler observerHandler) { + super("SyncConfigThread"); + this.setDaemon(true); + this.client = client; + this.registerCache = registerCache; + this.config = config; + this.observerHandler = observerHandler; + } + + @Override + public void run() { + int retryInterval = config.getSyncConfigRetryInterval(); + //noinspection InfiniteLoopStatement + while (true) { + try { + Thread.sleep(retryInterval); + + if (!client.isConnected()) { + continue; + } + + SyncConfigRequest request = new SyncConfigRequest(); + request.setDataCenter(config.getDataCenter()); + request.setZone(config.getZone()); + Object result = client.invokeSync(request); + + if (!(result instanceof SyncConfigResponse)) { + LOGGER.warn("[syncConfig] unknown response type, {}", result); + continue; + } + + SyncConfigResponse response = (SyncConfigResponse) result; + if (!response.isSuccess()) { + LOGGER.warn("[syncConfig] request failed, {}", response); + continue; + } + + int interval = response.getRetryInterval(); + retryInterval = Math.max(retryInterval, interval); + + List availableSegments = response.getAvailableSegments(); + + Collection allSubscribers = registerCache.getAllSubscribers(); + for (Subscriber subscriber : allSubscribers) { + try { + if (!(subscriber instanceof DefaultSubscriber)) { + continue; + } + + DefaultSubscriber defaultSubscriber = (DefaultSubscriber) subscriber; + + List nowAvailableSegments = defaultSubscriber + .getAvailableSegments(); + + if (isEqualCollections(availableSegments, nowAvailableSegments)) { + continue; + } + + defaultSubscriber.setAvailableSegments(availableSegments); + + observerHandler.notify(defaultSubscriber); + } catch (Exception e) { + LOGGER + .error( + "[syncConfig] try notify subscriber error, registId: {}, availableSegments: {}", + subscriber.getRegistId(), availableSegments, e); + } + } + } catch (Throwable e) { + LOGGER.error("[syncConfig] sync config error, retryInterval: {}", retryInterval, e); + } + } + } + + private boolean isEqualCollections(Collection a, Collection b) { + if (null == a) { + a = new ArrayList(); + } + + if (null == b) { + b = new ArrayList(); + } + + return a.size() == b.size() && a.equals(b); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskEvent.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskEvent.java new file mode 100644 index 000000000..ce62554e4 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskEvent.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.api.Register; + +/** + * The type Task event. + * @author zhuoyu.sjw + * @version $Id : TaskEvent.java, v 0.1 2018-02-28 20:33 zhuoyu.sjw Exp $$ + */ +public class TaskEvent implements Comparable { + private static final int MAX_DELAY_TIME = 1000; + + private Register source; + + private int sendCount; + + private long triggerTime; + + /** + * Constructor. + * + * @param source the source + */ + public TaskEvent(Register source) { + this.source = source; + this.triggerTime = System.currentTimeMillis(); + this.sendCount = 0; + } + + /** + * Getter method for property source. + * + * @return property value of source + */ + public Register getSource() { + return source; + } + + /** + * Setter method for property triggerTime. + * + * @param triggerTime value to be assigned to property triggerTime + */ + public void setTriggerTime(long triggerTime) { + this.triggerTime = triggerTime; + } + + /** + * Delay time long. + * + * @return long long + */ + public long delayTime() { + int time = sendCount * 200; + if (time > MAX_DELAY_TIME) { + time = MAX_DELAY_TIME; + } + return time - (System.currentTimeMillis() - this.triggerTime); + } + + /** + * Compare to int. + * + * @param event the event + * @return the int + */ + @Override + public int compareTo(TaskEvent event) { + if (this.sendCount > event.sendCount) { + return 1; + } else if (this.sendCount < event.sendCount) { + return -1; + } + Register register1 = source; + Register register2 = event.getSource(); + + if (register1 == null) { + return register2 != null ? -1 : 0; + } else { + if (register2 == null) { + return 1; + } + } + + long t1 = register1.getTimestamp(); + long t2 = register2.getTimestamp(); + if (t1 > t2) { + return 1; + } else if (t1 < t2) { + return -1; + } + return 0; + } + + /** + * @see Object#equals(Object) + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TaskEvent)) { + return false; + } + + TaskEvent taskEvent = (TaskEvent) o; + + if (sendCount != taskEvent.sendCount) { + return false; + } + if (triggerTime != taskEvent.triggerTime) { + return false; + } + return source != null ? source.equals(taskEvent.source) : taskEvent.source == null; + } + + /** + * @see Object#hashCode() + */ + @Override + public int hashCode() { + int result = source != null ? source.hashCode() : 0; + result = 31 * result + sendCount; + result = 31 * result + (int) (triggerTime ^ (triggerTime >>> 32)); + return result; + } + + /** + * Inc send count int. + * + * @return the int + */ + public int incSendCount() { + return this.sendCount++; + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskQueue.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskQueue.java new file mode 100644 index 000000000..8bc33eb60 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/TaskQueue.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.api.Register; +import com.alipay.sofa.registry.client.provider.AbstractInternalRegister; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * The type Task queue. + * @author zhuoyu.sjw + * @version $Id : TaskQueue.java, v 0.1 2018-02-28 20:44 zhuoyu.sjw Exp $$ + */ +public class TaskQueue implements Iterable { + + private final ConcurrentMap taskMap = new ConcurrentHashMap(); + + /** + * Iterator iterator. + * + * @return the iterator + */ + @Override + public Iterator iterator() { + List taskList = new ArrayList(taskMap.values()); + Collections.sort(taskList); + return taskList.iterator(); + } + + /** + * Delete the completed task, return task queue size. + */ + public void cleanCompletedTasks() { + List taskList = new ArrayList(taskMap.keySet()); + for (String key : taskList) { + TaskEvent event = taskMap.get(key); + AbstractInternalRegister r = (AbstractInternalRegister) event.getSource(); + if (r.isDone()) { + taskMap.remove(key, event); + } + } + taskMap.size(); + } + + /** + * Add task event to task queue. + * @param event task event + */ + public void put(TaskEvent event) { + Register register = event.getSource(); + String key = register.getRegistId(); + taskMap.put(key, event); + } + + /** + * Put all. + * + * @param taskEvents the task events + */ + public void putAll(List taskEvents) { + for (TaskEvent event : taskEvents) { + put(event); + } + } + + /** + * Is empty boolean. + * + * @return the boolean + */ + public boolean isEmpty() { + return taskMap.isEmpty(); + } + +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/Worker.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/Worker.java new file mode 100644 index 000000000..f3a89916e --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/Worker.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import java.util.List; + +/** + * The interface Worker. + * @author zhuoyu.sjw + * @version $Id : Worker.java, v 0.1 2018-02-28 22:45 zhuoyu.sjw Exp $$ + */ +public interface Worker { + + /** + * Schedule. + * + * @param event the event + */ + void schedule(TaskEvent event); + + /** + * Schedule. + * + * @param events the events + */ + void schedule(List events); + + /** + * Handle. + */ + void handle(); +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/task/WorkerThread.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/WorkerThread.java new file mode 100644 index 000000000..285c656d3 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/task/WorkerThread.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.api.Register; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.log.LoggerFactory; +import com.alipay.sofa.registry.client.provider.AbstractInternalRegister; +import com.alipay.sofa.registry.client.provider.AbstractInternalRegister.SyncTask; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.remoting.Client; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import org.slf4j.Logger; + +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The type Worker thread. + * @author zhuoyu.sjw + * @version $Id : WorkerThread.java, v 0.1 2018-03-01 11:51 zhuoyu.sjw Exp $$ + */ +public class WorkerThread extends AbstractWorkerThread { + private static final Logger LOGGER = LoggerFactory.getLogger(WorkerThread.class); + + /** + * Task queue + */ + protected final TaskQueue requestQueue = new TaskQueue(); + + private RegistryClientConfig config; + + private RegisterCache registerCache; + + private AtomicBoolean inited = new AtomicBoolean(false); + + /** + * Instantiates a new Worker thread. + * + * @param client the client connection + * @param config the config + */ + public WorkerThread(Client client, RegistryClientConfig config, RegisterCache registerCache) { + super(client); + this.config = config; + this.registerCache = registerCache; + this.setName("RegistryWorkerThread"); + this.setDaemon(true); + } + + /** + * Schedule. + * + * @param event the event + */ + @Override + public void schedule(TaskEvent event) { + if (inited.compareAndSet(false, true)) { + this.start(); + } + requestQueue.put(event); + signal(); + } + + /** + * Schedule. + * + * @param events the events + */ + @Override + public void schedule(List events) { + if (inited.compareAndSet(false, true)) { + this.start(); + } + requestQueue.putAll(events); + } + + /** + * Handle. + */ + @Override + public void handle() { + //noinspection InfiniteLoopStatement + while (true) { + try { + // check connection status, try to reconnect to the server when connection lose + client.ensureConnected(); + + if (requestQueue.isEmpty()) { + await(config.getRecheckInterval()); + continue; + } + + Iterator lt = requestQueue.iterator(); + + while (lt.hasNext()) { + client.ensureConnected(); + TaskEvent ev = lt.next(); + lt.remove(); + int sendCount = ev.incSendCount(); + + // Resent needs delay when task event is not the first time to send. + if (sendCount != 0 && ev.delayTime() > 0) { + continue; + } + + handleTask(ev); + } + + // Cleaning completed task, it will take more time when the registration number is large. + requestQueue.cleanCompletedTasks(); + } catch (Throwable e) { + LOGGER.error("[send] handle data error!", e); + } + } + } + + private void handleTask(TaskEvent event) { + if (null == event) { + return; + } + + try { + event.setTriggerTime(System.currentTimeMillis()); + Register register = event.getSource(); + + if (!(register instanceof AbstractInternalRegister)) { + LOGGER.warn("[register] register type unknown, {}", register); + return; + } + + AbstractInternalRegister abstractInternalRegister = (AbstractInternalRegister) register; + + SyncTask syncTask = abstractInternalRegister.assemblySyncTask(); + String requestId = syncTask.getRequestId(); + + if (syncTask.isDone()) { + LOGGER.info("[register] register already sync succeeded, {}", register); + return; + } + + Object request = syncTask.getRequest(); + + Object result = client.invokeSync(request); + + if (!(result instanceof RegisterResponse)) { + LOGGER.warn("[register] result type is wrong, {}", result); + return; + } + + RegisterResponse response = (RegisterResponse) result; + if (!response.isSuccess()) { + LOGGER.info("[register] register to server failed, {}, {}", request, response); + return; + } + + boolean syncOK = abstractInternalRegister.syncOK(requestId, response.getVersion(), + response.isRefused()); + if (!syncOK) { + LOGGER.info("[register] requestId has expired, ignore this response, {}, {}, {}", + requestId, request, response); + return; + } + + if (!register.isEnabled()) { + registerCache.remove(register.getRegistId()); + } + + if (response.isRefused()) { + LOGGER.info("[register] register refused by server, {}, {}, {}", requestId, + request, response); + } else { + LOGGER.info("[register] register to server success, {}, {}, {}", requestId, + request, response); + } + } catch (Exception e) { + LOGGER.error("[send] handle request failed, {}", event, e); + } + } + +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/util/CommonUtils.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/CommonUtils.java new file mode 100644 index 000000000..f2fd2ecbe --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/CommonUtils.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import java.util.Collection; + +/** + * The type Common utils. + * @author zhuoyu.sjw + * @version $Id : CommonUtils.java, v 0.1 2018-07-15 22:48 zhuoyu.sjw Exp $$ + */ +public class CommonUtils { + + /** + * Is not empty boolean. + * + * @param collection the collection + * @return the boolean + */ + public static boolean isNotEmpty(Collection collection) { + return collection != null && !collection.isEmpty(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/util/HttpClientUtils.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/HttpClientUtils.java new file mode 100644 index 000000000..2415ea560 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/HttpClientUtils.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; +import java.util.Map.Entry; + +/** + * The type Http client utils. + * @author zhuoyu.sjw + * @version $Id : HttpClientUtils.java, v 0.1 2018-03-22 17:38 zhuoyu.sjw Exp $$ + */ +public class HttpClientUtils { + private static final char AND = '&'; + + /** + * Get string. + * + * @param url the url + * @param params the params + * @param config the config + * @return the string + * @throws Exception the exception + */ + public static String get(String url, Map params, RegistryClientConfig config) + throws Exception { + HttpURLConnection httpURLConnection = create(getFullPath(url, params), config); + httpURLConnection.setRequestMethod("GET"); + + BufferedReader reader = null; + try { + StringBuilder stringBuffer = new StringBuilder(); + + int responseCode = httpURLConnection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + String charset = httpURLConnection.getContentEncoding(); + if (charset != null) { + reader = new BufferedReader(new InputStreamReader( + httpURLConnection.getInputStream(), charset)); + } else { + reader = new BufferedReader(new InputStreamReader( + httpURLConnection.getInputStream())); + } + + String strCurrentLine; + while ((strCurrentLine = reader.readLine()) != null) { + stringBuffer.append(strCurrentLine).append("\n"); + } + if (stringBuffer.length() > 0 + && stringBuffer.charAt(stringBuffer.length() - 1) == '\n') { + stringBuffer.deleteCharAt(stringBuffer.length() - 1); + } + + return stringBuffer.toString(); + } + } finally { + httpURLConnection.disconnect(); + if (null != reader) { + reader.close(); + } + } + return null; + } + + /** + * Create http url connection. + * + * @param httpUrl the http url + * @param config the config + * @return the http url connection + * @throws Exception the exception + */ + private static HttpURLConnection create(String httpUrl, RegistryClientConfig config) + throws Exception { + URL url = new URL(httpUrl); + URLConnection urlConnection = url.openConnection(); + HttpURLConnection httpConnection = (HttpURLConnection) urlConnection; + httpConnection.setDoOutput(true); + httpConnection.setDoInput(true); + httpConnection.setUseCaches(false); + httpConnection.setRequestProperty("Content-type", "text/plain"); + httpConnection.setConnectTimeout(config.getConnectTimeout()); + httpConnection.setReadTimeout(config.getSocketTimeout()); + return httpConnection; + } + + private static String getFullPath(String url, Map params) { + StringBuilder sb = new StringBuilder(url); + if (params != null) { + sb.append("?"); + for (Entry param : params.entrySet()) { + sb.append(param.getKey()); + sb.append("="); + sb.append(param.getValue()); + sb.append("&"); + } + if (sb.charAt(sb.length() - 1) == AND) { + sb.deleteCharAt(sb.length() - 1); + } + } + return sb.toString(); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/util/ServerNodeParser.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/ServerNodeParser.java new file mode 100644 index 000000000..da8b41f77 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/ServerNodeParser.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import com.alipay.sofa.registry.client.provider.DefaultServerNode; +import com.alipay.sofa.registry.client.remoting.ServerNode; + +import java.util.Properties; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ServerNodeParser.java, v 0.1 2018-03-22 20:28 zhuoyu.sjw Exp $$ + */ +public class ServerNodeParser { + + /** symbol : */ + private static final char COLON = ':'; + + /** symbol = */ + private static final char EQUAL = '='; + + /** symbol & */ + private static final char AND = '&'; + + /** symbol ? */ + private static final char QUES = '?'; + + /** + * @see com.alipay.remoting.RemotingAddressParser#parse(String) + */ + @SuppressWarnings("ConstantConditions") + public static ServerNode parse(String url) { + if (StringUtils.isBlank(url)) { + throw new IllegalArgumentException("Illegal format address string [" + url + + "], should not be blank! "); + } + String ip = null; + String port = null; + Properties properties = null; + + int size = url.length(); + int pos = 0; + for (int i = 0; i < size; ++i) { + if (COLON == url.charAt(i)) { + ip = url.substring(pos, i); + pos = i; + // should not end with COLON + if (i == size - 1) { + throw new IllegalArgumentException("Illegal format address string [" + url + + "], should not end with COLON[:]! "); + } + break; + } + // must have one COLON + if (i == size - 1) { + throw new IllegalArgumentException("Illegal format address string [" + url + + "], must have one COLON[:]! "); + } + } + + for (int i = pos; i < size; ++i) { + if (QUES == url.charAt(i)) { + port = url.substring(pos + 1, i); + pos = i; + if (i == size - 1) { + // should not end with QUES + throw new IllegalArgumentException("Illegal format address string [" + url + + "], should not end with QUES[?]! "); + } + break; + } + // end without a QUES + if (i == size - 1) { + port = url.substring(pos + 1, i + 1); + pos = size; + } + } + + if (pos < (size - 1)) { + properties = new Properties(); + while (pos < (size - 1)) { + String key = null; + String value = null; + for (int i = pos; i < size; ++i) { + if (EQUAL == url.charAt(i)) { + key = url.substring(pos + 1, i); + pos = i; + if (i == size - 1) { + // should not end with EQUAL + throw new IllegalArgumentException( + "Illegal format address string [" + url + + "], should not end with EQUAL[=]! "); + } + break; + } + if (i == size - 1) { + // must have one EQUAL + throw new IllegalArgumentException("Illegal format address string [" + url + + "], must have one EQUAL[=]! "); + } + } + for (int i = pos; i < size; ++i) { + if (AND == url.charAt(i)) { + value = url.substring(pos + 1, i); + pos = i; + if (i == size - 1) { + // should not end with AND + throw new IllegalArgumentException("Illegal format address string [" + + url + + "], should not end with AND[&]! "); + } + break; + } + // end without more AND + if (i == size - 1) { + value = url.substring(pos + 1, i + 1); + pos = size; + } + } + properties.put(key, value); + } + } + return new DefaultServerNode(url, ip, Integer.parseInt(port), properties); + } +} diff --git a/client/impl/src/main/java/com/alipay/sofa/registry/client/util/StringUtils.java b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/StringUtils.java new file mode 100644 index 000000000..63e4f3773 --- /dev/null +++ b/client/impl/src/main/java/com/alipay/sofa/registry/client/util/StringUtils.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +/** + * The type String utils. + * @author zhuoyu.sjw + * @version $Id : StringUtils.java, v 0.1 2018-03-05 17:36 zhuoyu.sjw Exp $$ + */ +public class StringUtils { + + /** + * The constant EMPTY. + */ + public static final String EMPTY = ""; + + /** + * Is empty boolean. + * + * @param cs the cs + * @return the boolean + */ + public static boolean isEmpty(CharSequence cs) { + return cs == null || cs.length() == 0; + } + + /** + * Is not empty boolean. + * + * @param cs the cs + * @return the boolean + */ + public static boolean isNotEmpty(CharSequence cs) { + return !isEmpty(cs); + } + + /** + * Is blank boolean. + * + * @param cs the cs + * @return the boolean + */ + public static boolean isBlank(CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; + } + + /** + * Is not blank boolean. + * + * @param cs the cs + * @return the boolean + */ + public static boolean isNotBlank(CharSequence cs) { + return !isBlank(cs); + } + + /** + *

Returns either the passed in String, + * or if the String is {@code null}, an empty String ("").

+ * + *
+     * StringUtils.defaultString(null)  = ""
+     * StringUtils.defaultString("")    = ""
+     * StringUtils.defaultString("bat") = "bat"
+     * 
+ * + * @param str the String to check, may be null + * @return the passed in String, or the empty String if it was {@code null} + * @see String#valueOf(Object) String#valueOf(Object) + */ + public static String defaultString(final Object str) { + return toString(str, EMPTY); + } + + /** + * To string string. + * + * @param o the o + * @param defaultVal the default val + * @return the string + */ + public static String toString(Object o, String defaultVal) { + return o == null ? defaultVal : o.toString(); + } + + /** + * To string string. + * + * @param o the o + * @return the string + */ + public static String toString(Object o) { + return toString(o, null); + } +} diff --git a/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j/log-conf.xml b/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j/log-conf.xml new file mode 100644 index 000000000..cbd2e0d00 --- /dev/null +++ b/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j/log-conf.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j2/log-conf.xml b/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j2/log-conf.xml new file mode 100644 index 000000000..aab1d9024 --- /dev/null +++ b/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/log4j2/log-conf.xml @@ -0,0 +1,86 @@ + + + + + + ${sys:logging.path}/registry + ${sys:com.alipay.sofa.registry.client.log.level} + ${sys:com.alipay.sofa.registry.client.log.encode} + + + + + + + + + + %d %-5p %C{1}#%L %-32t - %m%n + + + + + + + + + + + + + %d %-5p %-32t - %m%n + + + + + + + + + + + + + %d %-5p %-32t - %m%n + + + + + + + + + + %d %-5p %-32t - %m%n + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/logback/log-conf.xml b/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/logback/log-conf.xml new file mode 100644 index 000000000..3ec6052ab --- /dev/null +++ b/client/impl/src/main/resources/com/alipay/sofa/registry/client/log/logback/log-conf.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + true + + + ERROR + + + ${LOG_HOME}/common-error.log + + ${LOG_HOME}/common-error.log.%d{yyyy-MM-dd} + 30 + + + %d %-5p %C{1}#%L %-32t - %m%n + ${LOG_ENCODE} + + + + + true + + + ERROR + DENY + + + ${LOG_LEVEL} + ACCEPT + + + ${LOG_HOME}/common-default.log + + ${LOG_HOME}/common-default.log.%d{yyyy-MM-dd} + 30 + + + %d %-5p %-32t - %m%n + ${LOG_ENCODE} + + + + + true + + + ERROR + DENY + + + ${LOG_LEVEL} + ACCEPT + + + ${LOG_HOME}/registry-client.log + + ${LOG_HOME}/registry-client.log.%d{yyyy-MM-dd} + 30 + + + %d %-5p %-32t - %m%n + ${LOG_ENCODE} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/MockServer.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/MockServer.java new file mode 100644 index 000000000..4e941f2aa --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/MockServer.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client; + +import com.alipay.remoting.BizContext; +import com.alipay.remoting.rpc.RpcServer; +import com.alipay.remoting.rpc.protocol.SyncUserProcessor; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.BaseRegister; +import com.alipay.sofa.registry.core.model.ConfiguratorRegister; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.PublisherRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.core.model.SubscriberRegister; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * The type Mock server. + * @author zhuoyu.sjw + * @version $Id : MockServer.java, v 0.1 2017-12-25 22:39 zhuoyu.sjw Exp $$ + */ +public class MockServer { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(MockServer.class); + + private RpcServer rpcServer; + + private String ip = "127.0.0.1"; + + private int port = 9600; + + private Map publisherMap = new HashMap(); + private Map subscriberMap = new HashMap(); + private Map configuratorMap = new HashMap(); + + /** + * Start. + */ + public void start() { + rpcServer = new RpcServer(port); + rpcServer.registerUserProcessor(new MockSubscriberRegisterProcessor()); + rpcServer.registerUserProcessor(new MockPublisherRegisterProcessor()); + rpcServer.registerUserProcessor(new MockConfiguratorRegisterProcesor()); + rpcServer.start(ip); + } + + /** + * Stop. + */ + public void stop() { + rpcServer.stop(); + } + + /** + * Getter method for property ip. + * + * @return property value of ip + */ + public String getIp() { + return ip; + } + + /** + * Setter method for property ip. + * + * @param ip value to be assigned to property ip + */ + public void setIp(String ip) { + this.ip = ip; + } + + /** + * Getter method for property port. + * + * @return property value of port + */ + public int getPort() { + return port; + } + + /** + * Setter method for property port. + * + * @param port value to be assigned to property port + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Query publisher by registId + * + * @param registId + * @return + */ + public PublisherRegister queryPubliser(String registId) { + return publisherMap.get(registId); + } + + /** + * Query subscriber by registId + * + * @param registId + * @return + */ + public SubscriberRegister querySubscriber(String registId) { + return subscriberMap.get(registId); + } + + /** + * The type Mock subscriber register processor. + */ + class MockSubscriberRegisterProcessor extends SyncUserProcessor { + + @Override + public Object handleRequest(BizContext bizCtx, SubscriberRegister request) throws Exception { + if ("subscribeAndRefused".equals(request.getDataId())) { + return response(request, true); + } + + Result result = new Result(); + result.setSuccess(true); + String registId = request.getRegistId(); + if (EventTypeConstants.REGISTER.equals(request.getEventType())) { + subscriberMap.put(registId, request); + } else if (EventTypeConstants.UNREGISTER.equals(request.getEventType())) { + subscriberMap.remove(registId); + } + return response(request); + } + + @Override + public String interest() { + return SubscriberRegister.class.getName(); + } + } + + /** + * The type Mock publisher register processor. + */ + class MockPublisherRegisterProcessor extends SyncUserProcessor { + + @Override + public Object handleRequest(BizContext bizCtx, PublisherRegister request) throws Exception { + if ("publishAndRefused".equals(request.getDataId())) { + return response(request, true); + } + String registId = request.getRegistId(); + List dataList = request.getDataList(); + LOGGER.info(registId + " " + request.getEventType() + " " + dataList); + if (EventTypeConstants.REGISTER.equals(request.getEventType())) { + publisherMap.put(registId, request); + } else if (EventTypeConstants.UNREGISTER.equals(request.getEventType())) { + publisherMap.remove(registId); + } + return response(request); + } + + @Override + public String interest() { + return PublisherRegister.class.getName(); + } + } + + private RegisterResponse response(BaseRegister register) { + return response(register, false); + } + + private RegisterResponse response(BaseRegister register, boolean refused) { + RegisterResponse response = new RegisterResponse(); + response.setSuccess(true); + response.setVersion(register.getVersion()); + response.setRegistId(register.getRegistId()); + response.setRefused(refused); + return response; + } + + class MockConfiguratorRegisterProcesor extends SyncUserProcessor { + + @Override + public Object handleRequest(BizContext bizCtx, ConfiguratorRegister request) + throws Exception { + if ("subscribeAndRefused".equals(request.getDataId())) { + return response(request, true); + } + + String registId = request.getRegistId(); + LOGGER.info("dataId: {} registId: {}", request.getDataId(), registId); + if (EventTypeConstants.REGISTER.equals(request.getEventType())) { + configuratorMap.put(registId, request); + } else if (EventTypeConstants.UNREGISTER.equals(request.getEventType())) { + configuratorMap.remove(registId); + } + return response(request); + } + + @Override + public String interest() { + return ConfiguratorRegister.class.getName(); + } + } +} diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/base/BaseTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/base/BaseTest.java new file mode 100644 index 000000000..c32d42500 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/base/BaseTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.base; + +import com.alipay.sofa.registry.client.MockServer; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClient; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfig; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder; +import com.alipay.sofa.registry.client.util.HttpClientUtils; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.when; + +/** + * + * @author zhuoyu.sjw + * @version $Id: BaseTest.java, v 0.1 2018-03-24 14:58 zhuoyu.sjw Exp $$ + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(HttpClientUtils.class) +public abstract class BaseTest { + + protected DefaultRegistryClient registryClient; + + protected String appName = "registry-test"; + + protected String dataCenter = "HZ"; + + protected String instanceId = "testInstanceId"; + + protected MockServer mockServer; + + @Before + public void setUp() throws Exception { + mockServer = new MockServer(); + mockServer.start(); + + PowerMockito.mockStatic(HttpClientUtils.class); + when( + HttpClientUtils.get(anyString(), anyMapOf(String.class, String.class), + any(RegistryClientConfig.class))).thenReturn( + mockServer.getIp() + ":" + mockServer.getPort()); + + DefaultRegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setAppName(appName).setDataCenter(dataCenter).setInstanceId(instanceId) + .setRegistryEndpoint(mockServer.getIp()).build(); + registryClient = new DefaultRegistryClient(config); + registryClient.init(); + } +} diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/event/DefaultEventBusTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/DefaultEventBusTest.java new file mode 100644 index 000000000..794f0751f --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/DefaultEventBusTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * + * @author zhuoyu.sjw + * @version $Id: DefaultEventBusTest.java, v 0.1 2018-07-15 22:31 zhuoyu.sjw Exp $$ + */ +public class DefaultEventBusTest { + + private DefaultEventBus eventBus; + + @Before + public void setUp() { + RegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setEventBusEnable(true).build(); + eventBus = new DefaultEventBus(config); + } + + @Test + public void isEnable0() { + RegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setEventBusEnable(false).build(); + eventBus = new DefaultEventBus(config); + assertFalse(eventBus.isEnable()); + } + + @Test + public void isEnable1() { + RegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setEventBusEnable(true).build(); + eventBus = new DefaultEventBus(config); + assertTrue(eventBus.isEnable()); + } + + @Test + public void register() { + TestEventSubscriber testEventSubscriber = new TestEventSubscriber(true); + + try { + assertFalse(eventBus.isEnable(TestEvent.class)); + eventBus.register(TestEvent.class, testEventSubscriber); + assertTrue(eventBus.isEnable(TestEvent.class)); + } finally { + eventBus.unRegister(TestEvent.class, testEventSubscriber); + } + assertFalse(eventBus.isEnable(TestEvent.class)); + } + + @Test + public void post() { + TestEventSubscriber testEventSubscriber = new TestEventSubscriber(true); + + try { + assertFalse(eventBus.isEnable(TestEvent.class)); + eventBus.register(TestEvent.class, testEventSubscriber); + assertTrue(eventBus.isEnable(TestEvent.class)); + final String data = "test-data"; + eventBus.post(new TestEvent(data)); + assertEquals(data, testEventSubscriber.getCache()); + } finally { + eventBus.unRegister(TestEvent.class, testEventSubscriber); + } + assertFalse(eventBus.isEnable(TestEvent.class)); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/event/LookoutSubscriberTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/LookoutSubscriberTest.java new file mode 100644 index 000000000..258125c06 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/LookoutSubscriberTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * + * @author zhuoyu.sjw + * @version $Id: LookoutSubscriberTest.java, v 0.1 2018-07-15 23:04 zhuoyu.sjw Exp $$ + */ +public class LookoutSubscriberTest { + + private LookoutSubscriber lookoutSubscriber; + + @Test + public void isSync() { + lookoutSubscriber = new LookoutSubscriber(); + assertFalse(lookoutSubscriber.isSync()); + } + + @Test + public void onSubscriberProcessEvent() { + lookoutSubscriber = new LookoutSubscriber(); + + SubscriberProcessEvent event = new SubscriberProcessEvent(); + Subscriber subscriber = mock(Subscriber.class); + event.setSubscriber(subscriber); + event.setConfig(DefaultRegistryClientConfigBuilder.start().setInstanceId("000001").build()); + event.setStart(System.currentTimeMillis()); + event.setEnd(System.currentTimeMillis() + 1); + event.setThrowable(null); + + when(subscriber.getDataId()).thenReturn("test-dataId"); + + lookoutSubscriber.onEvent(event); + + verify(subscriber, times(1)).getDataId(); + } + + @Test + public void onConfiguratorProcessEvent() { + lookoutSubscriber = new LookoutSubscriber(); + + ConfiguratorProcessEvent event = new ConfiguratorProcessEvent(); + Configurator configurator = mock(Configurator.class); + event.setConfigurator(configurator); + event.setConfig(DefaultRegistryClientConfigBuilder.start().setInstanceId("000001").build()); + event.setStart(System.currentTimeMillis()); + event.setEnd(System.currentTimeMillis() + 1); + event.setThrowable(null); + + when(configurator.getDataId()).thenReturn("test-dataId"); + + lookoutSubscriber.onEvent(event); + + verify(configurator, times(1)).getDataId(); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEvent.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEvent.java new file mode 100644 index 000000000..7f968eef0 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEvent.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.model.Event; + +/** + * + * @author zhuoyu.sjw + * @version $Id: TestEvent.java, v 0.1 2018-07-15 22:38 zhuoyu.sjw Exp $$ + */ +public class TestEvent implements Event { + + private String data; + + public TestEvent(String data) { + this.data = data; + } + + /** + * Getter method for property data. + * + * @return property value of data + */ + public String getData() { + return data; + } + + /** + * Setter method for property data. + * + * @param data value to be assigned to property data + */ + public void setData(String data) { + this.data = data; + } +} diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEventSubscriber.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEventSubscriber.java new file mode 100644 index 000000000..bd80884ca --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/event/TestEventSubscriber.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.event; + +import com.alipay.sofa.registry.client.api.EventSubscriber; +import com.alipay.sofa.registry.client.api.model.Event; + +/** + * + * @author zhuoyu.sjw + * @version $Id: TestEventSubscriber.java, v 0.1 2018-07-15 22:39 zhuoyu.sjw Exp $$ + */ +public class TestEventSubscriber implements EventSubscriber { + + private boolean sync; + + private String cache; + + public TestEventSubscriber(boolean sync) { + this.sync = sync; + } + + @Override + public boolean isSync() { + return sync; + } + + @Override + public void onEvent(Event event) { + if (event instanceof TestEvent) { + cache = ((TestEvent) event).getData(); + } + } + + /** + * Getter method for property cache. + * + * @return property value of cache + */ + public String getCache() { + return cache; + } +} diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/model/ConfiguratorDataTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/model/ConfiguratorDataTest.java new file mode 100644 index 000000000..f96462995 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/model/ConfiguratorDataTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.model; + +import com.alipay.sofa.registry.core.model.DataBox; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class ConfiguratorDataTest { + + @Test + public void testAll() { + ConfiguratorData data = new ConfiguratorData(); + data.setDataBox(new DataBox()); + data.setVersion(1234L); + Assert.assertNotNull(data.getDataBox()); + Assert.assertTrue(1234L == data.getVersion()); + } + +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientTest.java new file mode 100644 index 000000000..183ebb4ec --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultRegistryClientTest.java @@ -0,0 +1,300 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.ConfigDataObserver; +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.api.Publisher; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.client.api.model.ConfigData; +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.client.api.registration.ConfiguratorRegistration; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.client.base.BaseTest; +import com.alipay.sofa.registry.core.model.PublisherRegister; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.core.model.SubscriberRegister; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +/** + * The type Default registry client test. + * + * @author zhuoyu.sjw + * @version $Id : DefaultRegistryClientTest.java, v 0.1 2017-11-24 20:05 zhuoyu.sjw Exp $$ + */ +public class DefaultRegistryClientTest extends BaseTest { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRegistryClientTest.class); + + private String dataId = "com.alipay.sofa.registry.client.provider.DefaultRegistryClientTest"; + + private String appName = "registry-test"; + + /** + * Teardown. + */ + @After + public void teardown() { + mockServer.stop(); + } + + /** + * Register publisher. + */ + @Test + public void registerPublisher() throws InterruptedException { + PublisherRegistration registration = new PublisherRegistration(dataId); + Publisher publisher = registryClient.register(registration); + assertNotNull(publisher); + assertEquals(dataId, publisher.getDataId()); + + Thread.sleep(1000L); + + RegisterCache registerCache = registryClient.getRegisterCache(); + + Publisher publisherCache = registerCache.getPublisherByRegistId(publisher.getRegistId()); + assertNotNull(publisherCache); + assertTrue(publisher instanceof DefaultPublisher); + // set cache success + assertEquals(publisher.getRegistId(), publisherCache.getRegistId()); + DefaultPublisher defaultPublisher = (DefaultPublisher) publisher; + assertTrue(defaultPublisher.isRegistered()); + + defaultPublisher.republish("republish test"); + + Thread.sleep(500L); + // register success when republish + assertTrue(defaultPublisher.isRegistered()); + } + + /** + * Register subscriber. + */ + @Test + public void registerSubscriber() throws InterruptedException { + SubscriberDataObserver dataObserver = new SubscriberDataObserver() { + @Override + public void handleData(String dataId, UserData data) { + LOGGER.info("handle data, dataId: {}, data: {}", dataId, data); + } + }; + SubscriberRegistration registration = new SubscriberRegistration(dataId, dataObserver); + registration.setScopeEnum(ScopeEnum.dataCenter); + Subscriber subscriber = registryClient.register(registration); + assertNotNull(subscriber); + assertEquals(dataId, subscriber.getDataId()); + + Thread.sleep(500L); + + RegisterCache registerCache = registryClient.getRegisterCache(); + + Subscriber register = registerCache.getSubscriberByRegistId(subscriber.getRegistId()); + assertNotNull(register); + // set cache success + assertEquals(subscriber.getRegistId(), register.getRegistId()); + // register success + assertTrue(register.isRegistered()); + } + + /** + * Register configurator. + */ + @Test + public void registerConfigurator() throws InterruptedException { + ConfigDataObserver dataObserver = new ConfigDataObserver() { + @Override + public void handleData(String dataId, ConfigData configData) { + LOGGER.info("handle data, dataId: {}, data: {}", dataId, configData); + + } + }; + + ConfiguratorRegistration registration = new ConfiguratorRegistration(dataId, dataObserver); + + Configurator configurator = registryClient.register(registration); + assertNotNull(configurator); + assertEquals(dataId, configurator.getDataId()); + + Thread.sleep(500L); + + RegisterCache registerCache = registryClient.getRegisterCache(); + + Configurator register = registerCache.getConfiguratorByRegistId(configurator.getRegistId()); + assertNotNull(register); + // set cache success + assertEquals(configurator.getRegistId(), register.getRegistId()); + // register success + assertTrue(register.isRegistered()); + } + + @Test + public void unregisterSinglePublisherTest() throws InterruptedException { + String dataId = "unregister-test-data-id"; + + PublisherRegistration publisherRegistration = new PublisherRegistration(dataId); + Publisher publisher = registryClient.register(publisherRegistration); + + int unregisterCount = registryClient.unregister(dataId, null, RegistryType.PUBLISHER); + assertEquals(1, unregisterCount); + + Thread.sleep(500L); + + Publisher temp = registryClient.getRegisterCache().getPublisherByRegistId( + publisher.getRegistId()); + + assertNull(temp); + } + + @Test + public void unregisterSingleSubscriberTest() throws InterruptedException { + String dataId = "unregister-test-data-id"; + + SubscriberDataObserver dataObserver = mock(SubscriberDataObserver.class); + SubscriberRegistration subscriberRegistration = new SubscriberRegistration(dataId, + dataObserver); + + Subscriber subscriber = registryClient.register(subscriberRegistration); + + int unregisterCount = registryClient.unregister(dataId, null, RegistryType.SUBSCRIBER); + assertEquals(1, unregisterCount); + + Thread.sleep(500L); + + Subscriber temp = registryClient.getRegisterCache().getSubscriberByRegistId( + subscriber.getRegistId()); + + assertNull(temp); + } + + @Test + public void unregisterSingleConfiguratorTest() throws InterruptedException { + String dataId = "unregister-test-data-id"; + + ConfigDataObserver dataObserver = mock(ConfigDataObserver.class); + + ConfiguratorRegistration registration = new ConfiguratorRegistration(dataId, dataObserver); + + Configurator configurator = registryClient.register(registration); + + int unregisterCount = registryClient.unregister(dataId, null, RegistryType.CONFIGURATOR); + assertEquals(1, unregisterCount); + + Thread.sleep(500L); + + Subscriber temp = registryClient.getRegisterCache().getSubscriberByRegistId( + configurator.getRegistId()); + + assertNull(temp); + } + + @Test + public void unregisterMultiTest() throws InterruptedException { + String dataId = "unregister-test-data-id"; + + // 1. register + PublisherRegistration publisherRegistration1 = new PublisherRegistration(dataId); + Publisher publisher1 = registryClient.register(publisherRegistration1); + + PublisherRegistration publisherRegistration2 = new PublisherRegistration(dataId); + Publisher publisher2 = registryClient.register(publisherRegistration2); + + SubscriberDataObserver dataObserver = mock(SubscriberDataObserver.class); + SubscriberRegistration subscriberRegistration1 = new SubscriberRegistration(dataId, + dataObserver); + + Subscriber subscriber1 = registryClient.register(subscriberRegistration1); + + SubscriberRegistration subscriberRegistration2 = new SubscriberRegistration(dataId, + dataObserver); + + Subscriber subscriber2 = registryClient.register(subscriberRegistration2); + + Thread.sleep(500L); + + // 2. unregister publisher + int unregisterCount = registryClient.unregister(dataId, null, RegistryType.PUBLISHER); + assertEquals(2, unregisterCount); + + Thread.sleep(500L); + + // 3. check publisher register cache + RegisterCache registerCache = registryClient.getRegisterCache(); + Publisher tempPub = registerCache.getPublisherByRegistId(publisher1.getRegistId()); + assertNull(tempPub); + + tempPub = registerCache.getPublisherByRegistId(publisher2.getRegistId()); + assertNull(tempPub); + + // 4. unregister subscriber + unregisterCount = registryClient.unregister(dataId, null, RegistryType.SUBSCRIBER); + assertEquals(2, unregisterCount); + + Thread.sleep(500L); + + // 5. check subscriber register cache + Subscriber tempSub = registerCache.getSubscriberByRegistId(subscriber1.getRegistId()); + assertNull(tempSub); + + tempSub = registerCache.getSubscriberByRegistId(subscriber2.getRegistId()); + assertNull(tempSub); + } + + @Test + public void testSetAppNameByRegistration() { + PublisherRegistration publisherRegistration = new PublisherRegistration(dataId); + final String testApp = "test-app"; + publisherRegistration.setAppName(testApp); + + Publisher publisher = registryClient.register(publisherRegistration); + PublisherRegister register = ((DefaultPublisher) publisher).assembly(); + + assertEquals(testApp, register.getAppName()); + + SubscriberRegistration subscriberRegistration = new SubscriberRegistration(dataId, + mock(SubscriberDataObserver.class)); + subscriberRegistration.setAppName(testApp); + + Subscriber subscriber = registryClient.register(subscriberRegistration); + SubscriberRegister subscriberRegister = ((DefaultSubscriber) subscriber).assembly(); + + assertEquals(testApp, subscriberRegister.getAppName()); + } + + @Test + public void testSetAppNameByConfig() { + PublisherRegistration publisherRegistration = new PublisherRegistration(dataId); + + Publisher publisher = registryClient.register(publisherRegistration); + PublisherRegister register = ((DefaultPublisher) publisher).assembly(); + + assertEquals(appName, register.getAppName()); + + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultServerManagerTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultServerManagerTest.java new file mode 100644 index 000000000..298711b27 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultServerManagerTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.remoting.ServerManager; +import com.alipay.sofa.registry.client.remoting.ServerNode; +import com.alipay.sofa.registry.client.util.HttpClientUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.List; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +/** + * + * @author zhuoyu.sjw + * @version $Id: DefaultServerManagerTest.java, v 0.1 2018-03-23 14:54 zhuoyu.sjw Exp $$ + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest(HttpClientUtils.class) +public class DefaultServerManagerTest { + + @Test + public void initServerList() throws Exception { + // given + PowerMockito.mockStatic(HttpClientUtils.class); + RegistryClientConfig config = mock(RegistryClientConfig.class); + + // when + when(config.getSyncConfigRetryInterval()).thenReturn(100); + when( + HttpClientUtils.get(anyString(), anyMapOf(String.class, String.class), + any(RegistryClientConfig.class))).thenReturn("127.0.0.1:9600;127.0.0.2:9600"); + + // then + ServerManager serverManager = new DefaultServerManager(config); + + List serverList = serverManager.getServerList(); + + assertNotNull(serverList); + + Thread.sleep(450); + + // verify + PowerMockito.verifyStatic(times(4)); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultSubscriberTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultSubscriberTest.java new file mode 100644 index 000000000..44cc981dd --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/DefaultSubscriberTest.java @@ -0,0 +1,284 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.client.model.SegmentData; +import com.alipay.sofa.registry.core.model.DataBox; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * To test DefaultSubscriber. + * + * @author hui.shih + * @version $Id: DefaultSubscriberTest.java, v 0.1 2018-03-26 16:11 hui.shih Exp $$ + */ +public class DefaultSubscriberTest { + + public final String ZHEJIANG = "Zhejiang"; + public final String HANGZHOU = "Hangzhou"; + public final String NINGBO = "Ningbo"; + public final String WENZHOU = "Wenzhou"; + + public final String JIANGSU = "Jiangsu"; + public final String NANJING = "Nanjing"; + + public final String FUJIAN = "Fujian"; + public final String FUZHOU = "Fuzhou"; + public final String XIAMEN = "Xiamen"; + + public final String segmentA = "a"; + + public final String segmentB = "b"; + + @Test + public void testPutReceivedData() { + + String localZone = ZHEJIANG; + + DefaultRegistryClientConfig config = DefaultRegistryClientConfigBuilder.start().build(); + DefaultSubscriber defaultSubscriber = new DefaultSubscriber(null, null, config); + + UserData initUserData = defaultSubscriber.peekData(); + + assertNull(initUserData.getLocalZone()); + assertTrue(initUserData.getZoneData().isEmpty()); + + long versionA = 0; + long versionB = 0; + + // 1. receive data normally + Map> map1 = new HashMap>(); + addToDataBoxMap(map1, ZHEJIANG, HANGZHOU); + SegmentData sd1 = new SegmentData(); + sd1.setSegment(segmentA); + sd1.setVersion(++versionA); + sd1.setData(map1); + + defaultSubscriber.putReceivedData(sd1, localZone); + UserData userData1 = defaultSubscriber.peekData(); + + Map> expectedMap1 = new HashMap>(); + addToStringMap(expectedMap1, ZHEJIANG, HANGZHOU); + + assertEquals(localZone, userData1.getLocalZone()); + assertZoneDataEquals(expectedMap1, userData1.getZoneData()); + + // 2. receive data normally again + Map> map2 = new HashMap>(); + addToDataBoxMap(map2, ZHEJIANG, NINGBO, WENZHOU); + SegmentData sd2 = new SegmentData(); + sd2.setSegment(segmentA); + sd2.setVersion(++versionA); + sd2.setData(map2); + + defaultSubscriber.putReceivedData(sd2, localZone); + UserData userData2 = defaultSubscriber.peekData(); + + Map> expectedMap2 = new HashMap>(); + addToStringMap(expectedMap2, ZHEJIANG, NINGBO, WENZHOU); + + assertEquals(localZone, userData2.getLocalZone()); + assertZoneDataEquals(expectedMap2, userData2.getZoneData()); + + // 3. illegal version + Map> map3 = new HashMap>(); + addToDataBoxMap(map3, ZHEJIANG, NINGBO); + SegmentData sd3 = new SegmentData(); + sd3.setSegment(segmentA); + sd3.setVersion(versionA); + sd3.setData(map3); + + defaultSubscriber.putReceivedData(sd3, localZone); + UserData userData3 = defaultSubscriber.peekData(); + + assertZoneDataEquals(expectedMap2, userData3.getZoneData()); + + // 4. from another segment + Map> map4 = new HashMap>(); + addToDataBoxMap(map4, ZHEJIANG, HANGZHOU); + SegmentData sd4 = new SegmentData(); + sd4.setSegment(segmentB); + sd4.setVersion(++versionB); + sd4.setData(map4); + + defaultSubscriber.putReceivedData(sd4, localZone); + UserData userData4 = defaultSubscriber.peekData(); + + Map> expectedMap4 = new HashMap>(); + addToStringMap(expectedMap4, ZHEJIANG, HANGZHOU, NINGBO, WENZHOU); + + assertZoneDataEquals(expectedMap4, userData4.getZoneData()); + + // 5. another segment, another zone + Map> map5 = new HashMap>(); + addToDataBoxMap(map5, JIANGSU, NANJING); + SegmentData sd5 = new SegmentData(); + sd5.setSegment(segmentB); + sd5.setVersion(++versionB); + sd5.setData(map5); + + defaultSubscriber.putReceivedData(sd5, localZone); + UserData userData5 = defaultSubscriber.peekData(); + + Map> expectedMap5 = new HashMap>(); + addToStringMap(expectedMap5, ZHEJIANG, NINGBO, WENZHOU); + addToStringMap(expectedMap5, JIANGSU, NANJING); + + assertZoneDataEquals(expectedMap5, userData5.getZoneData()); + + // 6. push empty + Map> map6 = new HashMap>(); + SegmentData sd6 = new SegmentData(); + sd6.setSegment(segmentA); + sd6.setVersion(++versionA); + sd6.setData(map6); + + defaultSubscriber.putReceivedData(sd6, localZone); + UserData userData6 = defaultSubscriber.peekData(); + + Map> expectedMap6 = new HashMap>(); + addToStringMap(expectedMap6, JIANGSU, NANJING); + + assertZoneDataEquals(expectedMap6, userData6.getZoneData()); + + // 7. different segments without intersection + Map> map7 = new HashMap>(); + addToDataBoxMap(map7, ZHEJIANG, NINGBO, WENZHOU); + addToDataBoxMap(map7, FUJIAN, XIAMEN); + + SegmentData sd7 = new SegmentData(); + sd7.setSegment(segmentA); + sd7.setVersion(++versionA); + sd7.setData(map7); + + defaultSubscriber.putReceivedData(sd7, localZone); + UserData userData7 = defaultSubscriber.peekData(); + + Map> expectedMap7 = new HashMap>(); + addToStringMap(expectedMap7, ZHEJIANG, NINGBO, WENZHOU); + addToStringMap(expectedMap7, JIANGSU, NANJING); + addToStringMap(expectedMap7, FUJIAN, XIAMEN); + + assertZoneDataEquals(expectedMap7, userData7.getZoneData()); + + // 8. different segments with intersection + Map> map8 = new HashMap>(); + addToDataBoxMap(map8, ZHEJIANG, HANGZHOU); + addToDataBoxMap(map8, JIANGSU, NANJING); + addToDataBoxMap(map8, FUJIAN, FUZHOU); + + SegmentData sd8 = new SegmentData(); + sd8.setSegment(segmentB); + sd8.setVersion(++versionB); + sd8.setData(map8); + + defaultSubscriber.putReceivedData(sd8, localZone); + UserData userData8 = defaultSubscriber.peekData(); + + Map> expectedMap8 = new HashMap>(); + addToStringMap(expectedMap8, ZHEJIANG, HANGZHOU, NINGBO, WENZHOU); + addToStringMap(expectedMap8, JIANGSU, NANJING); + addToStringMap(expectedMap8, FUJIAN, FUZHOU, XIAMEN); + + assertZoneDataEquals(expectedMap8, userData8.getZoneData()); + + // 9. set available segments + + List availableSegments9 = new ArrayList(); + availableSegments9.add(segmentB); + defaultSubscriber.setAvailableSegments(availableSegments9); + + UserData userData9 = defaultSubscriber.peekData(); + + Map> expectedMap9 = new HashMap>(); + addToStringMap(expectedMap9, ZHEJIANG, HANGZHOU); + addToStringMap(expectedMap9, JIANGSU, NANJING); + addToStringMap(expectedMap9, FUJIAN, FUZHOU); + + assertZoneDataEquals(expectedMap9, userData9.getZoneData()); + + // 10. add available segments + + List availableSegments10 = new ArrayList(); + availableSegments10.add(segmentA); + availableSegments10.add(segmentB); + defaultSubscriber.setAvailableSegments(availableSegments10); + + UserData userData10 = defaultSubscriber.peekData(); + + assertZoneDataEquals(expectedMap8, userData10.getZoneData()); + } + + private void addToDataBoxMap(Map> map, String key, String... values) { + List list = map.get(key); + if (list == null) { + list = new ArrayList(); + map.put(key, list); + } + for (String value : values) { + DataBox dataBox = new DataBox(); + dataBox.setData(value); + list.add(dataBox); + } + + } + + private void addToStringMap(Map> map, String key, String... values) { + List list = map.get(key); + if (list == null) { + list = new ArrayList(); + map.put(key, list); + } + for (String value : values) { + list.add(value); + } + + } + + private void assertZoneDataEquals(Map> a, Map> b) { + assertEquals(sortAllList(a), sortAllList(b)); + } + + private Map> sortAllList(Map> map) { + if (map == null) { + return null; + } + Map> copyMap = new HashMap>(); + for (Map.Entry> entry : map.entrySet()) { + if (entry.getValue() == null) { + copyMap.put(entry.getKey(), null); + } else { + List copyList = new ArrayList(entry.getValue()); + Collections.sort(copyList); + copyMap.put(entry.getKey(), copyList); + } + } + return copyMap; + } + +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/RegisterOrderTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/RegisterOrderTest.java new file mode 100644 index 000000000..54374cfbb --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/provider/RegisterOrderTest.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.provider; + +import com.alipay.sofa.registry.client.api.Publisher; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.client.base.BaseTest; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.PublisherRegister; +import com.alipay.sofa.registry.core.model.SubscriberRegister; +import org.junit.After; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * + * To test all kinds of sequence of register action + * + * @author hui.shih + * @version $Id: RegisterOrderTest.java, v 0.1 2018-03-07 16:28 hui.shih Exp $$ + */ +public class RegisterOrderTest extends BaseTest { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRegistryClientTest.class); + + private String dataId = "com.alipay.sofa.registry.client.provider.RegisterOrderTest"; + + /** + * Teardown. + */ + @After + public void teardown() { + mockServer.stop(); + } + + @Test + public void publishFrequently() throws InterruptedException { + + String dataPrefix = "publishFrequently"; + + Publisher publisher = registryClient.register(new PublisherRegistration(dataId), + dataPrefix + 0); + + int republishCount = 100; + for (int i = 1; i <= republishCount; i++) { + publisher.republish(dataPrefix + i); + } + + Thread.sleep(1000L); + + DefaultPublisher defaultPublisher = (DefaultPublisher) publisher; + String registeId = defaultPublisher.getRegistId(); + + // check client status + assertTrue(defaultPublisher.isRegistered()); + assertTrue(defaultPublisher.isEnabled()); + assertEquals(republishCount + 1, defaultPublisher.getPubVersion().intValue()); + + // check server status + List data = mockServer.queryPubliser(registeId).getDataList(); + assertEquals(1, data.size()); + assertEquals(dataPrefix + republishCount, data.get(0).getData()); + } + + @Test + public void unregisterAndRepublish() throws InterruptedException { + + String dataPrefix = "unregisterAndRepublish"; + + // step 1 + Publisher publisher = registryClient.register(new PublisherRegistration(dataId), + dataPrefix + 0); + // step 2 + publisher.unregister(); + + try { + // step 3 + publisher.republish(dataPrefix + 1); + fail("No exception thrown."); + } catch (Exception ex) { + // Must throw a RuntimeException + assertTrue(ex instanceof IllegalStateException); + } + + Thread.sleep(500L); + + assertTrue(publisher.isRegistered()); + assertFalse(publisher.isEnabled()); + + } + + @Test + public void publishAndUnregister() throws InterruptedException { + + String data = "publishAndUnregister"; + + // step 1 + Publisher publisher = registryClient.register(new PublisherRegistration(dataId), data); + + Thread.sleep(500L); + + String registId = publisher.getRegistId(); + PublisherRegister publisherRegister = mockServer.queryPubliser(registId); + + assertNotNull(publisherRegister); + assertEquals(data, publisherRegister.getDataList().get(0).getData()); + + // step 2 + publisher.unregister(); + + Thread.sleep(500L); + + assertNull(mockServer.queryPubliser(registId)); + + } + + @Test + public void publishAndRefused() throws InterruptedException { + + String data = "publishAndRefused"; + + // step 1 + Publisher publisher = registryClient.register(new PublisherRegistration(data), data); + + Thread.sleep(500L); + + String registId = publisher.getRegistId(); + PublisherRegister publisherRegister = mockServer.queryPubliser(registId); + + assertNull(publisherRegister); + + // step 2 + try { + publisher.republish(data); + } catch (Exception e) { + assertTrue(e instanceof IllegalStateException); + assertEquals("Publisher is refused by server. Try to check your configuration.", + e.getMessage()); + } + } + + @Test + public void subscribeAndUnregister() throws InterruptedException { + + SubscriberDataObserver dataObserver = new SubscriberDataObserver() { + @Override + public void handleData(String dataId, UserData data) { + LOGGER.info("handle data, dataId: {}, data: {}", dataId, data); + } + }; + + // step 1 + Subscriber subscriber = registryClient.register(new SubscriberRegistration(dataId, + dataObserver)); + + Thread.sleep(500L); + + String registId = subscriber.getRegistId(); + SubscriberRegister subscriberRegister = mockServer.querySubscriber(registId); + assertNotNull(subscriberRegister); + + // step 2 + subscriber.unregister(); + + Thread.sleep(500L); + + assertNull(mockServer.queryPubliser(registId)); + + } + + @Test + public void subscribeAndRefused() throws InterruptedException { + + SubscriberDataObserver dataObserver = new SubscriberDataObserver() { + @Override + public void handleData(String dataId, UserData data) { + LOGGER.info("handle data, dataId: {}, data: {}", dataId, data); + } + }; + + // step 1 + Subscriber subscriber = registryClient.register(new SubscriberRegistration( + "subscribeAndRefused", dataObserver)); + + Thread.sleep(500L); + + String registId = subscriber.getRegistId(); + SubscriberRegister subscriberRegister = mockServer.querySubscriber(registId); + assertNull(subscriberRegister); + + assertTrue(subscriber instanceof AbstractInternalRegister); + assertTrue(((AbstractInternalRegister) subscriber).isRefused()); + } + +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessorTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessorTest.java new file mode 100644 index 000000000..6794e638b --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedConfigDataProcessorTest.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.sofa.registry.client.api.Configurator; +import com.alipay.sofa.registry.client.provider.DefaultConfigurator; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.task.ObserverHandler; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.core.model.Result; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Arrays; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author GengZhang + */ +public class ReceivedConfigDataProcessorTest { + + private static ReceivedConfigDataProcessor processor; + + @BeforeClass + public static void init() { + RegisterCache registerCache = mock(RegisterCache.class); + ObserverHandler handler = mock(ObserverHandler.class); + Configurator configurator2 = mock(Configurator.class); + when(registerCache.getConfiguratorByRegistId("11")).thenReturn(null); + when(registerCache.getConfiguratorByRegistId("22")).thenReturn(configurator2); + DefaultConfigurator configurator3 = mock(DefaultConfigurator.class); + when(registerCache.getConfiguratorByRegistId("33")).thenReturn(configurator3); + doThrow(new RuntimeException()).when(handler).notify(configurator3); + + processor = new ReceivedConfigDataProcessor(registerCache, handler); + } + + @Test + public void handleRequest() { + Result result = (Result) processor.handleRequest(null, null); + Assert.assertTrue(result.isSuccess()); + Assert.assertNull(result.getMessage()); + + ReceivedConfigData request = new ReceivedConfigData(); + request.setDataBox(new DataBox()); + request.setVersion(1234L); + request.setConfiguratorRegistIds(null); + result = (Result) processor.handleRequest(null, request); + Assert.assertFalse(result.isSuccess()); + Assert.assertEquals("", result.getMessage()); + + request.setConfiguratorRegistIds(Arrays.asList("11", "22", "33")); + result = (Result) processor.handleRequest(null, request); + Assert.assertTrue(result.isSuccess()); + Assert.assertNull(result.getMessage()); + } + + @Test + public void interest() { + Assert.assertEquals(ReceivedConfigData.class.getName(), processor.interest()); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessorTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessorTest.java new file mode 100644 index 000000000..cbdd22ffa --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/remoting/ReceivedDataProcessorTest.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.remoting; + +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.provider.DefaultSubscriber; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.task.ObserverHandler; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.Result; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author GengZhang + */ +public class ReceivedDataProcessorTest { + + private static ReceivedDataProcessor processor; + + @BeforeClass + public static void init() { + RegisterCache registerCache = mock(RegisterCache.class); + ObserverHandler handler = mock(ObserverHandler.class); + Subscriber configurator2 = mock(Subscriber.class); + when(registerCache.getSubscriberByRegistId("11")).thenReturn(null); + when(registerCache.getSubscriberByRegistId("22")).thenReturn(configurator2); + DefaultSubscriber configurator3 = mock(DefaultSubscriber.class); + when(registerCache.getSubscriberByRegistId("33")).thenReturn(configurator3); + doThrow(new RuntimeException()).when(handler).notify(configurator3); + + processor = new ReceivedDataProcessor(registerCache, handler); + } + + @Test + public void handleRequest() { + Result result = (Result) processor.handleRequest(null, null); + Assert.assertTrue(result.isSuccess()); + Assert.assertNull(result.getMessage()); + + ReceivedData request = new ReceivedData(); + result = (Result) processor.handleRequest(null, request); + Assert.assertTrue(result.isSuccess()); + Assert.assertNull(result.getMessage()); + + request = new ReceivedData(); + request.setSubscriberRegistIds(null); + request.setData(new HashMap>()); + request.setVersion(1234L); + request.setSegment("seg1"); + request.setLocalZone("local"); + + result = (Result) processor.handleRequest(null, request); + Assert.assertFalse(result.isSuccess()); + Assert.assertEquals("", result.getMessage()); + + request.setSubscriberRegistIds(Arrays.asList("11", "22", "33")); + result = (Result) processor.handleRequest(null, request); + Assert.assertTrue(result.isSuccess()); + Assert.assertNull(result.getMessage()); + } + + @Test + public void interest() { + Assert.assertEquals(ReceivedData.class.getName(), processor.interest()); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/task/SyncConfigThreadTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/task/SyncConfigThreadTest.java new file mode 100644 index 000000000..5d75ae3e4 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/task/SyncConfigThreadTest.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.remoting.exception.RemotingException; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.Subscriber; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder; +import com.alipay.sofa.registry.client.provider.DefaultSubscriber; +import com.alipay.sofa.registry.client.provider.RegisterCache; +import com.alipay.sofa.registry.client.remoting.Client; +import com.alipay.sofa.registry.core.model.SyncConfigResponse; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyListOf; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SyncConfigThreadTest.java, v 0.1 2018-03-15 14:33 zhuoyu.sjw Exp $$ + */ +public class SyncConfigThreadTest { + + @Test + public void syncConfigTest() throws RemotingException, InterruptedException { + + // mock + RegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setDataCenter("test-data-center").setZone("test-zone") + .setSyncConfigRetryInterval(1000).build(); + + Client client = mock(Client.class); + RegisterCache registerCache = mock(RegisterCache.class); + ObserverHandler observerHandler = mock(ObserverHandler.class); + DefaultSubscriber subscriber = mock(DefaultSubscriber.class); + + // when + when(client.isConnected()).thenReturn(true); + + SyncConfigResponse response = new SyncConfigResponse(); + response.setSuccess(true); + response.setAvailableSegments(Arrays.asList("segment1", "segment2")); + response.setRetryInterval(3000000); + when(client.invokeSync(anyObject())).thenReturn(response); + + List subscribers = new ArrayList(); + subscribers.add(subscriber); + when(registerCache.getAllSubscribers()).thenReturn(subscribers); + + when(subscriber.getAvailableSegments()).thenReturn(new ArrayList()); + + // do + SyncConfigThread configThread = new SyncConfigThread(client, registerCache, config, + observerHandler); + configThread.start(); + + Thread.sleep(2000L); + + // verify + verify(client, times(1)).isConnected(); + verify(client, times(1)).invokeSync(any()); + + verify(subscriber, times(1)).setAvailableSegments(anyListOf(String.class)); + + verify(observerHandler, times(1)).notify(eq(subscriber)); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/task/TaskEventTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/task/TaskEventTest.java new file mode 100644 index 000000000..3d98d42cf --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/task/TaskEventTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.task; + +import com.alipay.sofa.registry.client.api.Register; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.mockito.Mockito.when; + +/** + * @author GengZhang + */ +public class TaskEventTest { + + @Test + public void delayTime() { + TaskEvent event1 = new TaskEvent(null); + Assert.assertTrue(event1.delayTime() <= 200); + event1.incSendCount(); + Assert.assertTrue(event1.delayTime() <= 400); + event1.incSendCount(); + Assert.assertTrue(event1.delayTime() <= 600); + event1.incSendCount(); + Assert.assertTrue(event1.delayTime() <= 800); + event1.incSendCount(); + Assert.assertTrue(event1.delayTime() <= 1000); + event1.incSendCount(); + Assert.assertTrue(event1.delayTime() <= 1000); + } + + @Test + public void testCompare() { + TaskEvent event1 = new TaskEvent(null); + TaskEvent event2 = new TaskEvent(null); + Assert.assertEquals(0, event1.compareTo(event2)); + + event1.incSendCount(); + Assert.assertEquals(1, event1.compareTo(event2)); + Assert.assertEquals(-1, event2.compareTo(event1)); + event2.incSendCount(); + + Register register = Mockito.mock(Register.class); + TaskEvent event3 = new TaskEvent(register); + TaskEvent event4 = new TaskEvent(register); + TaskEvent event5 = new TaskEvent(null); + Assert.assertEquals(1, event4.compareTo(event5)); + Assert.assertEquals(-1, event5.compareTo(event3)); + + Register register6 = Mockito.mock(Register.class); + when(register6.getTimestamp()).thenReturn(123L); + Register register7 = Mockito.mock(Register.class); + when(register7.getTimestamp()).thenReturn(234L); + TaskEvent event6 = new TaskEvent(register6); + TaskEvent event7 = new TaskEvent(register7); + TaskEvent event8 = new TaskEvent(register7); + Assert.assertEquals(1, event7.compareTo(event6)); + Assert.assertEquals(-1, event6.compareTo(event7)); + Assert.assertEquals(0, event8.compareTo(event7)); + } + + @Test + public void testEquals() { + TaskEvent event1 = new TaskEvent(null); + Assert.assertTrue(event1.equals(event1)); + Assert.assertFalse(event1.equals("xxxx")); + TaskEvent event2 = new TaskEvent(null); + Assert.assertTrue(event1.equals(event2)); + + event1.incSendCount(); + Assert.assertFalse(event1.equals(event2)); + event2.incSendCount(); + + event1.setTriggerTime(123); + Assert.assertFalse(event1.equals(event2)); + event2.setTriggerTime(123); + + Register register = Mockito.mock(Register.class); + TaskEvent event3 = new TaskEvent(register); + TaskEvent event4 = new TaskEvent(register); + Assert.assertTrue(event3.equals(event4)); + } + + @Test + public void testHashCode() { + TaskEvent event1 = new TaskEvent(null); + TaskEvent event2 = new TaskEvent(null); + Assert.assertEquals(event1.hashCode(), event2.hashCode()); + event1.setTriggerTime(1234); + Assert.assertNotEquals(event1.hashCode(), event2.hashCode()); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/util/CommonUtilsTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/CommonUtilsTest.java new file mode 100644 index 000000000..e66d4e8e2 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/CommonUtilsTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Collections; + +/** + * @author GengZhang + */ +public class CommonUtilsTest { + + @Test + public void isNotEmpty() { + Assert.assertTrue(CommonUtils.isNotEmpty(Collections.singletonList("xxx"))); + Assert.assertFalse(CommonUtils.isNotEmpty(null)); + Assert.assertFalse(CommonUtils.isNotEmpty(Collections.emptyList())); + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/util/HttpClientUtilsTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/HttpClientUtilsTest.java new file mode 100644 index 000000000..b45da2ed7 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/HttpClientUtilsTest.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +/** + * @author GengZhang + */ +public class HttpClientUtilsTest { + + private static HttpServer httpServer; + + @BeforeClass + public static void start() throws IOException { + httpServer = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(5678), 0); + httpServer.createContext("/xxx", new MockHandler()); + httpServer.createContext("/yyy", new ErrorHandler()); + httpServer.setExecutor(null); + httpServer.start(); + } + + @AfterClass + public static void stop() { + httpServer.stop(1); + } + + @Test + public void testGet() { + String url = "http://127.0.0.1:56789/xxx"; + Map map = new HashMap(); + map.put("x", "1"); + map.put("y", "2"); + RegistryClientConfig clientConfig = new DefaultRegistryClientConfigBuilder().build(); + try { + // wrong url + HttpClientUtils.get(url, map, clientConfig); + Assert.fail(); + } catch (Exception e) { + } + + url = "http://127.0.0.1:5678/xxx"; + try { + HttpClientUtils.get(url, map, clientConfig); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + + url = "http://127.0.0.1:5678/yyy"; + try { + Assert.assertNull(HttpClientUtils.get(url, map, clientConfig)); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + + static class MockHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + String response = "hello world"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } + + static class ErrorHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + String response = "ServerDown"; + exchange.sendResponseHeaders(500, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/util/ServerNodeParserTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/ServerNodeParserTest.java new file mode 100644 index 000000000..5fdb579f1 --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/ServerNodeParserTest.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import com.alipay.sofa.registry.client.remoting.ServerNode; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class ServerNodeParserTest { + + @Test + public void parse() { + boolean error = false; + try { + ServerNodeParser.parse(null); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + try { + ServerNodeParser.parse("127.0.0.1:"); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + try { + ServerNodeParser.parse("127.0.0.1"); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + try { + ServerNodeParser.parse("127.0.0.1:12345?"); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + try { + ServerNodeParser.parse("127.0.0.1:12345?x"); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + try { + ServerNodeParser.parse("127.0.0.1:12345?x="); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + try { + ServerNodeParser.parse("127.0.0.1:12345?x=1&"); + } catch (Exception e) { + Assert.assertTrue(e instanceof IllegalArgumentException); + error = true; + } + Assert.assertTrue(error); + + error = false; + String url = "127.0.0.2:12345"; + ServerNode node = ServerNodeParser.parse(url); + + Assert.assertEquals("127.0.0.2", node.getHost()); + Assert.assertEquals(12345, node.getPort()); + + url = "127.0.0.3:23456?x=1&y=2&z=3"; + node = ServerNodeParser.parse(url); + Assert.assertEquals("127.0.0.3", node.getHost()); + Assert.assertEquals(23456, node.getPort()); + + } +} \ No newline at end of file diff --git a/client/impl/src/test/java/com/alipay/sofa/registry/client/util/StringUtilsTest.java b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/StringUtilsTest.java new file mode 100644 index 000000000..f60ca729b --- /dev/null +++ b/client/impl/src/test/java/com/alipay/sofa/registry/client/util/StringUtilsTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.util; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class StringUtilsTest { + + @Test + public void isEmpty() { + Assert.assertTrue(StringUtils.isEmpty(null)); + Assert.assertTrue(StringUtils.isEmpty("")); + Assert.assertFalse(StringUtils.isEmpty(" ")); + } + + @Test + public void isNotEmpty() { + Assert.assertFalse(StringUtils.isNotEmpty(null)); + Assert.assertFalse(StringUtils.isNotEmpty("")); + Assert.assertTrue(StringUtils.isNotEmpty(" ")); + } + + @Test + public void isBlank() { + Assert.assertTrue(StringUtils.isBlank(null)); + Assert.assertTrue(StringUtils.isBlank("")); + Assert.assertTrue(StringUtils.isBlank(" ")); + Assert.assertFalse(StringUtils.isBlank(" 1")); + } + + @Test + public void isNotBlank() { + Assert.assertFalse(StringUtils.isNotBlank(null)); + Assert.assertFalse(StringUtils.isNotBlank("")); + Assert.assertFalse(StringUtils.isNotBlank(" ")); + Assert.assertTrue(StringUtils.isNotBlank(" 1")); + } + + @Test + public void defaultString() { + Assert.assertEquals("", StringUtils.defaultString(null)); + Assert.assertEquals("x", StringUtils.defaultString("x")); + } + + @Test + public void testToString() { + Assert.assertEquals(null, StringUtils.toString(null)); + Assert.assertEquals("Bean:11", StringUtils.toString(new Bean("11"))); + + Assert.assertEquals(null, StringUtils.toString((Object) null, null)); + Assert.assertEquals("1", StringUtils.toString((Object) null, "1")); + Assert.assertEquals("Bean:11", StringUtils.toString(new Bean("11"), null)); + } + + class Bean { + private String s; + + public Bean() { + + } + + public Bean(String s) { + this.s = s; + } + + @Override + public String toString() { + return "Bean:" + s; + } + } +} \ No newline at end of file diff --git a/client/log/pom.xml b/client/log/pom.xml new file mode 100644 index 000000000..e25260abf --- /dev/null +++ b/client/log/pom.xml @@ -0,0 +1,54 @@ + + + + com.alipay.sofa + registry-client-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-client-log + + + ../../ + + + + + org.slf4j + slf4j-api + + + com.alipay.sofa.common + sofa-common-tools + + + + junit + junit + test + + + + + + + org.apache.maven.plugins + maven-install-plugin + + ${module.install.skip} + + + + org.apache.maven.plugins + maven-deploy-plugin + + ${module.deploy.skip} + + + + + diff --git a/client/log/src/main/java/com/alipay/sofa/registry/client/log/LoggerFactory.java b/client/log/src/main/java/com/alipay/sofa/registry/client/log/LoggerFactory.java new file mode 100644 index 000000000..ba80b7480 --- /dev/null +++ b/client/log/src/main/java/com/alipay/sofa/registry/client/log/LoggerFactory.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.log; + +import com.alipay.sofa.common.log.LoggerSpaceManager; +import org.slf4j.Logger; + +import java.io.File; + +/** + * The type Logger factory. + * @author zhuoyu.sjw + * @version $Id : LoggerFactory.java, v 0.1 2018-03-24 12:06 zhuoyu.sjw Exp $$ + */ +public class LoggerFactory { + + private static final String LOG_SPACE_PROPERTY = "registry.client.log.space"; + private static final String LOG_PATH = "logging.path"; + private static final String LOG_PATH_DEFAULT = System.getProperty("user.home") + + File.separator + "logs"; + private static final String CLIENT_LOG_LEVEL = "com.alipay.sofa.registry.client.log.level"; + private static final String CLIENT_LOG_LEVEL_DEFAULT = "INFO"; + private static final String CLIENT_LOG_ENCODE = "com.alipay.sofa.registry.client.log.encode"; + private static final String CLIENT_LOG_ENCODE_DEFAULT = "UTF-8"; + private static String logSpace = "com.alipay.sofa.registry.client"; + + static { + LoggerFactory.logSpace = getLogSpace(); + + String logPath = System.getProperty(LOG_PATH); + String logLevel = System.getProperty(CLIENT_LOG_LEVEL); + String logEncode = System.getProperty(CLIENT_LOG_ENCODE); + if (isBlank(logPath)) { + System.setProperty(LOG_PATH, LOG_PATH_DEFAULT); + } + if (isBlank(logLevel)) { + System.setProperty(CLIENT_LOG_LEVEL, CLIENT_LOG_LEVEL_DEFAULT); + } + if (isBlank(logEncode)) { + System.setProperty(CLIENT_LOG_ENCODE, CLIENT_LOG_ENCODE_DEFAULT); + } + } + + static String getLogSpace() { + String sysLogSpace = System.getProperty(LOG_SPACE_PROPERTY); + return (null != sysLogSpace && !sysLogSpace.isEmpty()) ? sysLogSpace : logSpace; + } + + /** + * Gets logger. + * + * @param clazz the clazz + * @return the logger + */ + public static Logger getLogger(Class clazz) { + if (clazz == null) { + return null; + } + return getLogger(clazz.getCanonicalName()); + } + + /** + * Gets logger. + * + * @param name the name + * @return the logger + */ + public static Logger getLogger(String name) { + if (name == null || name.isEmpty()) { + return null; + } + return LoggerSpaceManager.getLoggerBySpace(name, logSpace); + } + + static boolean isBlank(CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/client/log/src/test/java/com/alipay/sofa/registry/client/log/LoggerFactoryTest.java b/client/log/src/test/java/com/alipay/sofa/registry/client/log/LoggerFactoryTest.java new file mode 100644 index 000000000..208cb3dbf --- /dev/null +++ b/client/log/src/test/java/com/alipay/sofa/registry/client/log/LoggerFactoryTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.client.log; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author GengZhang + */ +public class LoggerFactoryTest { + + @Test + public void getLogger() { + Assert.assertNull(LoggerFactory.getLogger((String) null)); + Assert.assertNull(LoggerFactory.getLogger((Class) null)); + Assert.assertEquals(LoggerFactory.getLogger(LoggerFactoryTest.class), + LoggerFactory.getLogger(LoggerFactoryTest.class.getCanonicalName())); + + } + + @Test + public void getLogSpace() { + Assert.assertEquals("com.alipay.sofa.registry.client", LoggerFactory.getLogSpace()); + String key = "registry.client.log.space"; + String old = System.getProperty(key); // + try { + System.setProperty(key, "xxx"); + Assert.assertEquals("xxx", LoggerFactory.getLogSpace()); + } finally { + if (old == null) { + System.clearProperty(key); + } else { + System.setProperty(key, old); + } + } + Assert.assertEquals("com.alipay.sofa.registry.client", LoggerFactory.getLogSpace()); + } + + @Test + public void testIsBlank() { + Assert.assertFalse(LoggerFactory.isBlank("123")); + Assert.assertTrue(LoggerFactory.isBlank(" ")); + Assert.assertTrue(LoggerFactory.isBlank("")); + Assert.assertTrue(LoggerFactory.isBlank(null)); + Assert.assertTrue(LoggerFactory.isBlank(" ")); + Assert.assertTrue(LoggerFactory.isBlank("\r\t")); + } + +} \ No newline at end of file diff --git a/client/pom.xml b/client/pom.xml new file mode 100644 index 000000000..7f15577e9 --- /dev/null +++ b/client/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + + com.alipay.sofa + registry-parent + 5.2.0-SNAPSHOT + ../pom.xml + + + registry-client-parent + pom + http://www.antfin.com + [SOFA] Registry Client. + + + The Ant Financial + http://www.antfin.com/ + + + + api + log + impl + all + + + + + true + true + true + 1.6 + 1.6 + UTF-8 + 1.4.6 + ../ + + + + + + com.alipay.sofa + registry-core + ${project.version} + + + com.alipay.sofa + registry-client-api + ${project.version} + + + com.alipay.sofa + registry-client-log + ${project.version} + + + com.alipay.sofa + registry-client-impl + ${project.version} + + + com.alipay.sofa + bolt + ${bolt.version} + + + com.alipay.sofa.common + sofa-common-tools + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + + + + + diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 000000000..e01707058 --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,45 @@ + + + + com.alipay.sofa + registry-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-core + + + + 1.6 + 1.6 + UTF-8 + ../ + + + + + junit + junit + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + + + + + diff --git a/core/src/main/java/com/alipay/sofa/registry/core/constants/EventTypeConstants.java b/core/src/main/java/com/alipay/sofa/registry/core/constants/EventTypeConstants.java new file mode 100644 index 000000000..2539da47e --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/constants/EventTypeConstants.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.constants; + +/** + * + * @author zhuoyu.sjw + * @version $Id: EventTypeConstants.java, v 0.1 2018-03-01 19:15 zhuoyu.sjw Exp $$ + */ +public class EventTypeConstants { + + public static final String REGISTER = "REGISTER"; + + public static final String UNREGISTER = "UNREGISTER"; +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/BaseRegister.java b/core/src/main/java/com/alipay/sofa/registry/core/model/BaseRegister.java new file mode 100644 index 000000000..fe5a6c5ad --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/BaseRegister.java @@ -0,0 +1,347 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author zhuoyu.sjw + * @version $Id: BaseRegister.java, v 0.1 2017-11-28 14:32 zhuoyu.sjw Exp $$ + */ +public class BaseRegister implements Serializable { + + private static final long serialVersionUID = -3825175839851738346L; + + private String instanceId; + + private String zone; + + private String appName; + + private String dataId; + + private String group; + + private String processId; + + private String registId; + + private String clientId; + + private String dataInfoId; + + private String ip; + + private Integer port; + + private String eventType; + + private Long version; + + private Long timestamp; + + private Map attributes = new HashMap(); + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + /** + * Getter method for property zone. + * + * @return property value of zone + */ + public String getZone() { + return zone; + } + + /** + * Setter method for property zone. + * + * @param zone value to be assigned to property zone + */ + public void setZone(String zone) { + this.zone = zone; + } + + /** + * Getter method for property appName. + * + * @return property value of appName + */ + public String getAppName() { + return appName; + } + + /** + * Setter method for property appName. + * + * @param appName value to be assigned to property appName + */ + public void setAppName(String appName) { + this.appName = appName; + } + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = dataId; + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Getter method for property processId. + * + * @return property value of processId + */ + public String getProcessId() { + return processId; + } + + /** + * Setter method for property processId. + * + * @param processId value to be assigned to property processId + */ + public void setProcessId(String processId) { + this.processId = processId; + } + + /** + * Getter method for property registId. + * + * @return property value of registId + */ + public String getRegistId() { + return registId; + } + + /** + * Setter method for property registId. + * + * @param registId value to be assigned to property registId + */ + public void setRegistId(String registId) { + this.registId = registId; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property timestamp. + * + * @return property value of timestamp + */ + public Long getTimestamp() { + return timestamp; + } + + /** + * Setter method for property timestamp. + * + * @param timestamp value to be assigned to property timestamp + */ + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + /** + * Getter method for property eventType. + * + * @return property value of eventType + */ + public String getEventType() { + return eventType; + } + + /** + * Setter method for property eventType. + * + * @param eventType value to be assigned to property eventType + */ + public void setEventType(String eventType) { + this.eventType = eventType; + } + + /** + * Getter method for property clientId. + * + * @return property value of clientId + */ + public String getClientId() { + return clientId; + } + + /** + * Setter method for property clientId. + * + * @param clientId value to be assigned to property clientId + */ + public void setClientId(String clientId) { + this.clientId = clientId; + } + + /** + * Getter method for property ip. + * + * @return property value of ip + */ + public String getIp() { + return ip; + } + + /** + * Setter method for property ip. + * + * @param ip value to be assigned to property ip + */ + public void setIp(String ip) { + this.ip = ip; + } + + /** + * Getter method for property port. + * + * @return property value of port + */ + public Integer getPort() { + return port; + } + + /** + * Setter method for property port. + * + * @param port value to be assigned to property port + */ + public void setPort(Integer port) { + this.port = port; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property attributes. + * + * @return property value of attributes + */ + public Map getAttributes() { + return attributes; + } + + /** + * Setter method for property attributes. + * + * @param attributes value to be assigned to property attributes + */ + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "BaseRegister{" + "instanceId='" + instanceId + '\'' + ", zone='" + zone + '\'' + + ", appName='" + appName + '\'' + ", dataId='" + dataId + '\'' + ", group='" + + group + '\'' + ", processId='" + processId + '\'' + ", registId='" + registId + + '\'' + ", clientId='" + clientId + '\'' + ", dataInfoId='" + dataInfoId + '\'' + + ", ip='" + ip + '\'' + ", port=" + port + ", eventType='" + eventType + '\'' + + ", version=" + version + ", timestamp=" + timestamp + ", attributes=" + attributes + + '}'; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/ConfiguratorRegister.java b/core/src/main/java/com/alipay/sofa/registry/core/model/ConfiguratorRegister.java new file mode 100644 index 000000000..0c2f33af7 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/ConfiguratorRegister.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ConfiguratorRegister.java, v 0.1 2018-04-17 17:45 zhuoyu.sjw Exp $$ + */ +public class ConfiguratorRegister extends BaseRegister { + private static final long serialVersionUID = 3636660681387698721L; + +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/DataBox.java b/core/src/main/java/com/alipay/sofa/registry/core/model/DataBox.java new file mode 100644 index 000000000..98dd01ad7 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/DataBox.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; + +/** + * The type DataBox. + * @author zhuoyu.sjw + * @version $Id : DataBox.java, v 0.1 2017-11-28 17:47 zhuoyu.sjw Exp $$ + */ +public class DataBox implements Serializable { + + /** UID */ + private static final long serialVersionUID = 2817539491173993030L; + + /** Actual data */ + private String data; + + /** + * Instantiates a new DataBox. + */ + public DataBox() { + } + + /** + * Instantiates a new Data box. + * + * @param data the data + */ + public DataBox(String data) { + this.data = data; + } + + /** + * Getter method for property data. + * + * @return property value of data + */ + public String getData() { + return data; + } + + /** + * Setter method for property data. + * + * @param data value to be assigned to property data + */ + public void setData(String data) { + this.data = data; + } + + @Override + public String toString() { + return "DataBox{data='" + data + "'}"; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/PublisherRegister.java b/core/src/main/java/com/alipay/sofa/registry/core/model/PublisherRegister.java new file mode 100644 index 000000000..7bdc25015 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/PublisherRegister.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.util.List; + +/** + * The type Publisher register. + * @author zhuoyu.sjw + * @version $Id : PublisherRegister.java, v 0.1 2017-11-28 15:39 zhuoyu.sjw Exp $$ + */ +public class PublisherRegister extends BaseRegister { + + private static final long serialVersionUID = 17084511452627565L; + + private List dataList; + + /** + * Getter method for property dataList. + * + * @return property value of dataList + */ + public List getDataList() { + return dataList; + } + + /** + * Setter method for property dataList. + * + * @param dataList value to be assigned to property dataList + */ + public void setDataList(List dataList) { + this.dataList = dataList; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "PublisherRegister{" + "dataList=" + dataList + '}' + super.toString(); + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedConfigData.java b/core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedConfigData.java new file mode 100644 index 000000000..a7c1e182c --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedConfigData.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; +import java.util.List; + +/** + * The type Received config data. + * @author zhuoyu.sjw + * @version $Id : ReceivedConfigData.java, v 0.1 2018-04-17 18:00 zhuoyu.sjw Exp $$ + */ +public class ReceivedConfigData implements Serializable { + + private static final long serialVersionUID = 4077554672965455808L; + + private String dataId; + + private String group; + + private String instanceId; + + private List configuratorRegistIds; + + private DataBox dataBox; + + private Long version; + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = dataId; + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + /** + * Getter method for property dataBox. + * + * @return property value of dataBox + */ + public DataBox getDataBox() { + return dataBox; + } + + /** + * Setter method for property dataBox. + * + * @param dataBox value to be assigned to property dataBox + */ + public void setDataBox(DataBox dataBox) { + this.dataBox = dataBox; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property configuratorRegistIds. + * + * @return property value of configuratorRegistIds + */ + public List getConfiguratorRegistIds() { + return configuratorRegistIds; + } + + /** + * Setter method for property configuratorRegistIds. + * + * @param configuratorRegistIds value to be assigned to property configuratorRegistIds + */ + public void setConfiguratorRegistIds(List configuratorRegistIds) { + this.configuratorRegistIds = configuratorRegistIds; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "ReceivedConfigData{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + + ", instanceId='" + instanceId + '\'' + ", configuratorRegistIds=" + + configuratorRegistIds + ", dataBox=" + dataBox + ", version=" + version + '}'; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedData.java b/core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedData.java new file mode 100644 index 000000000..f4ef744c5 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/ReceivedData.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * The type Received data multi. + * @author zhuoyu.sjw + * @version $Id : ReceivedData.java, v 0.1 2017-11-23 22:23 zhuoyu.sjw Exp $$ + */ +public class ReceivedData implements Serializable { + + private static final long serialVersionUID = -7322781873212812819L; + + private String dataId; + + private String group; + + private String instanceId; + + private String segment; + + private String scope; + + private List subscriberRegistIds; + + private Map> data; + + private Long version; + + private String localZone; + + /** + * Instantiates a new Received data multi. + */ + public ReceivedData() { + } + + /** + * Instantiates a new Received data multi. + * + * @param dataId the data id + * @param group the group + * @param instanceId the instance id + * @param segment the data center + * @param subscriberRegistIds the subscriber regist ids + * @param data the data + * @param version the version + */ + public ReceivedData(String dataId, String group, String instanceId, String segment, + List subscriberRegistIds, Map> data, + Long version) { + this.dataId = dataId; + this.group = group; + this.instanceId = instanceId; + this.segment = segment; + this.subscriberRegistIds = subscriberRegistIds; + this.data = data; + this.version = version; + } + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = dataId; + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + /** + * Getter method for property segment. + * + * @return property value of segment + */ + public String getSegment() { + return segment; + } + + /** + * Setter method for property segment. + * + * @param segment value to be assigned to property segment + */ + public void setSegment(String segment) { + this.segment = segment; + } + + /** + * Getter method for property scope. + * + * @return property value of scope + */ + public String getScope() { + return scope; + } + + /** + * Setter method for property scope. + * + * @param scope value to be assigned to property scope + */ + public void setScope(String scope) { + this.scope = scope; + } + + /** + * Getter method for property subscriberRegistIds. + * + * @return property value of subscriberRegistIds + */ + public List getSubscriberRegistIds() { + return subscriberRegistIds; + } + + /** + * Setter method for property subscriberRegistIds. + * + * @param subscriberRegistIds value to be assigned to property subscriberRegistIds + */ + public void setSubscriberRegistIds(List subscriberRegistIds) { + this.subscriberRegistIds = subscriberRegistIds; + } + + /** + * Getter method for property data. + * + * @return property value of data + */ + public Map> getData() { + return data; + } + + /** + * Setter method for property data. + * + * @param data value to be assigned to property data + */ + public void setData(Map> data) { + this.data = data; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property localZone. + * + * @return property value of localZone + */ + public String getLocalZone() { + return localZone; + } + + /** + * Setter method for property localZone. + * + * @param localZone value to be assigned to property localZone + */ + public void setLocalZone(String localZone) { + this.localZone = localZone; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "ReceivedData{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + + ", instanceId='" + instanceId + '\'' + ", segment='" + segment + '\'' + + ", scope='" + scope + '\'' + ", subscriberRegistIds=" + subscriberRegistIds + + ", version=" + version + ", localZone='" + localZone + '\'' + '}'; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/RegisterResponse.java b/core/src/main/java/com/alipay/sofa/registry/core/model/RegisterResponse.java new file mode 100644 index 000000000..33ce9e5dd --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/RegisterResponse.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; + +/** + * + * @author zhuoyu.sjw + * @version $Id: RegisterResponse.java, v 0.1 2018-03-05 18:11 zhuoyu.sjw Exp $$ + */ +public class RegisterResponse implements Serializable { + + private static final long serialVersionUID = -3692498042919432434L; + + private boolean success; + + private String registId; + + private long version; + + private boolean refused; + + private String message; + + /** + * Getter method for property success. + * + * @return property value of success + */ + public boolean isSuccess() { + return success; + } + + /** + * Setter method for property success. + * + * @param success value to be assigned to property success + */ + public void setSuccess(boolean success) { + this.success = success; + } + + /** + * Getter method for property registId. + * + * @return property value of registId + */ + public String getRegistId() { + return registId; + } + + /** + * Setter method for property registId. + * + * @param registId value to be assigned to property registId + */ + public void setRegistId(String registId) { + this.registId = registId; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(long version) { + this.version = version; + } + + /** + * Getter method for property refused. + * + * @return property value of refused + */ + public boolean isRefused() { + return refused; + } + + /** + * Setter method for property refused. + * + * @param refused value to be assigned to property refused + */ + public void setRefused(boolean refused) { + this.refused = refused; + } + + /** + * Getter method for property message. + * + * @return property value of message + */ + public String getMessage() { + return message; + } + + /** + * Setter method for property message. + * + * @param message value to be assigned to property message + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + return "RegisterResponse{" + "success=" + success + ", registId='" + registId + '\'' + + ", version=" + version + ", refused=" + refused + ", message='" + message + '\'' + + '}'; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/Result.java b/core/src/main/java/com/alipay/sofa/registry/core/model/Result.java new file mode 100644 index 000000000..90e8c7733 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/Result.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; + +/** + * + * @author zhuoyu.sjw + * @version $Id: Result.java, v 0.1 2017-11-30 15:48 zhuoyu.sjw Exp $$ + */ +public class Result implements Serializable { + + private static final long serialVersionUID = -3861771860629530576L; + + private boolean success; + + private String message; + + /** + * Getter method for property success. + * + * @return property value of success + */ + public boolean isSuccess() { + return success; + } + + /** + * Setter method for property success. + * + * @param success value to be assigned to property success + */ + public void setSuccess(boolean success) { + this.success = success; + } + + /** + * Getter method for property message. + * + * @return property value of message + */ + public String getMessage() { + return message; + } + + /** + * Setter method for property message. + * + * @param message value to be assigned to property message + */ + public void setMessage(String message) { + this.message = message; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "Result{" + "success=" + success + ", message='" + message + '\'' + '}'; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/ScopeEnum.java b/core/src/main/java/com/alipay/sofa/registry/core/model/ScopeEnum.java new file mode 100644 index 000000000..aad4f628b --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/ScopeEnum.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +/** + * The enum Scope enum. + * + * @author zhuoyu.sjw + * @version $Id : ScopeEnum.java, v 0.1 2017-11-22 15:36 zhuoyu.sjw Exp $$ + */ +public enum ScopeEnum { + + /** zone scope: only can receive pub list at same zone */ + zone, + /** dataCenter scope: only can receive pub list at same dataCenter (multi zone) */ + dataCenter, + /** global scope: can receive pub list at all dataCenter (multi zone) */ + global; + + public static boolean contains(String name) { + for (ScopeEnum scopeEnum : values()) { + if (scopeEnum.name().equals(name)) { + return true; + } + } + return false; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/SubscriberRegister.java b/core/src/main/java/com/alipay/sofa/registry/core/model/SubscriberRegister.java new file mode 100644 index 000000000..8dd822779 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/SubscriberRegister.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SubscriberRegister.java, v 0.1 2017-11-28 15:40 zhuoyu.sjw Exp $$ + */ +public class SubscriberRegister extends BaseRegister { + private static final long serialVersionUID = 5884257055097046886L; + + private String scope; + + /** + * Getter method for property scope. + * + * @return property value of scope + */ + public String getScope() { + return scope; + } + + /** + * Setter method for property scope. + * + * @param scope value to be assigned to property scope + */ + public void setScope(String scope) { + this.scope = scope; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "SubscriberRegister{" + "scope='" + scope + '\'' + '}' + super.toString(); + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigRequest.java b/core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigRequest.java new file mode 100644 index 000000000..fa3be30f7 --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigRequest.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SyncConfigRequest.java, v 0.1 2018-03-14 23:06 zhuoyu.sjw Exp $$ + */ +public class SyncConfigRequest implements Serializable { + + private static final long serialVersionUID = -843642420869816713L; + + private String dataCenter; + + private String zone; + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + } + + /** + * Getter method for property zone. + * + * @return property value of zone + */ + public String getZone() { + return zone; + } + + /** + * Setter method for property zone. + * + * @param zone value to be assigned to property zone + */ + public void setZone(String zone) { + this.zone = zone; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "SyncConfigRequest{" + "dataCenter='" + dataCenter + '\'' + ", zone='" + zone + '\'' + + '}'; + } +} diff --git a/core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigResponse.java b/core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigResponse.java new file mode 100644 index 000000000..70d9d972c --- /dev/null +++ b/core/src/main/java/com/alipay/sofa/registry/core/model/SyncConfigResponse.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.core.model; + +import java.io.Serializable; +import java.util.List; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SyncConfigResponse.java, v 0.1 2018-03-14 23:08 zhuoyu.sjw Exp $$ + */ +public class SyncConfigResponse extends Result implements Serializable { + + private static final long serialVersionUID = 5407436619633166827L; + + private List availableSegments; + + private int retryInterval; + + /** + * Getter method for property availableSegments. + * + * @return property value of availableSegments + */ + public List getAvailableSegments() { + return availableSegments; + } + + /** + * Setter method for property availableSegments. + * + * @param availableSegments value to be assigned to property availableSegments + */ + public void setAvailableSegments(List availableSegments) { + this.availableSegments = availableSegments; + } + + /** + * Getter method for property retryInterval. + * + * @return property value of retryInterval + */ + public int getRetryInterval() { + return retryInterval; + } + + /** + * Setter method for property retryInterval. + * + * @param retryInterval value to be assigned to property retryInterval + */ + public void setRetryInterval(int retryInterval) { + this.retryInterval = retryInterval; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "SyncConfigResponse{" + "availableSegments=" + availableSegments + + ", retryInterval=" + retryInterval + '}'; + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..c9d9fc3bb --- /dev/null +++ b/pom.xml @@ -0,0 +1,510 @@ + + + 4.0.0 + + com.alipay.sofa + registry-parent + 5.2.0-SNAPSHOT + pom + + ${project.groupId}:${project.artifactId} + http://github.com/alipay/sofa-registry + A high-performance, high-extensibility, production-level Java Registry framework. + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + The Ant Financial + http://www.antfin.com/ + + + + + Hui Wang + shangyu.wh@alibaba-inc.com + Ant Financial + + + KeZhu Wu + kezhu.wukz@antfin.com + Ant Financial + + + Jie Cao + caojie.cj@antfin.com + Ant Financial + + + + + scm:git:git://github.com/alipay/sofa-registry.git + scm:git:ssh://github.com/alipay/sofa-registry.git + http://github.com/alipay/sofa-registry/tree/master + + + + core + client + server + test + + + 1.8 + 1.8 + UTF-8 + 1.5.2 + 2.6 + 18.0 + 1.0.12 + 4.12 + 5.0.2 + ${junit.version}.2 + 1.0.2 + 3.3.6 + 4.1.25.Final + 2.26 + 3.5.1 + 1.7.21 + 1.5.2 + 1.10.19 + 1.6.6 + 1.2.4 + 4.0.2 + 2.4 + 9.4.12.v20180830 + ${user.dir} + + + + + + org.springframework.boot + spring-boot-starter-parent + 1.5.17.RELEASE + pom + import + + + com.alipay.sofa + registry-core + ${project.version} + + + com.alipay.sofa + registry-client-all + ${project.version} + + + com.alipay.sofa + registry-common-model + ${project.version} + + + com.alipay.sofa + registry-common-util + ${project.version} + + + com.alipay.sofa + registry-consistency + ${project.version} + + + com.alipay.sofa + registry-store-api + ${project.version} + + + com.alipay.sofa + registry-store-jraft + ${project.version} + + + com.alipay.sofa + registry-remoting-api + ${project.version} + + + com.alipay.sofa + registry-remoting-http + ${project.version} + + + com.alipay.sofa + registry-remoting-bolt + ${project.version} + + + com.alipay.sofa + registry-server-meta + ${project.version} + + + com.alipay.sofa + registry-server-session + ${project.version} + + + com.alipay.sofa + registry-server-data + ${project.version} + + + com.alipay.sofa + registry-server-integration + ${project.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + com.alipay.sofa + bolt + ${bolt.version} + + + com.alipay.sofa.common + sofa-common-tools + + + + + com.alipay.sofa.common + sofa-common-tools + ${sofa.common.tools.version} + + + com.google.guava + guava + ${google.guava.version} + + + commons-lang + commons-lang + ${commons.lang.version} + + + com.alipay.sofa + hessian + ${sofa.hessian.version} + + + io.netty + netty-all + ${netty.version} + + + org.glassfish.jersey.core + jersey-server + ${jersey.version} + + + org.glassfish.jersey.core + jersey-client + ${jersey.version} + + + org.glassfish.jersey.core + jersey-common + ${jersey.version} + + + org.glassfish.jersey.containers + jersey-container-netty-http + ${jersey.version} + + + org.glassfish.jersey.containers + jersey-container-jdk-http + ${jersey.version} + + + org.glassfish.jersey.containers + jersey-container-jetty-http + ${jersey.version} + + + org.glassfish.jersey.inject + jersey-hk2 + ${jersey.version} + + + org.glassfish.jersey.media + jersey-media-json-jackson + ${jersey.version} + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-http + ${jetty.version} + + + org.eclipse.jetty + jetty-util + ${jetty.version} + + + org.eclipse.jetty + jetty-io + ${jetty.version} + + + org.eclipse.jetty + jetty-continuation + ${jetty.version} + + + com.alipay.sofa.lookout + lookout-api + ${lookout.version} + + + com.google.protobuf + protobuf-java + ${protobuf.version} + + + com.alipay.sofa + jraft-core + ${jraft.version} + + + org.apache.logging.log4j + log4j-slf4j-impl + + + com.alipay.remoting + bolt + + + + + commons-io + commons-io + ${commons-io.version} + + + + + io.dropwizard.metrics + metrics-core + ${metrics.version} + + + + + junit + junit + ${junit.version} + test + + + org.mockito + mockito-core + ${mockito.version} + test + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + org.powermock + powermock-api-mockito + ${powermock.version} + test + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + + jar + + + + + + com.mycila + license-maven-plugin + 3.0 + + + generate-sources + + remove + format + + + + + true +
${main.user.dir}/tools/codestyle/HEADER
+ + **/src/main/java/** + **/src/test/java/** + + true + + SLASHSTAR_STYLE + +
+
+ + com.googlecode.maven-java-formatter-plugin + maven-java-formatter-plugin + 0.4 + + + + format + + + + + ${main.user.dir}/tools/codestyle/formatter.xml + UTF-8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.21.0 + + + org.jacoco + jacoco-maven-plugin + 0.7.9 + + false + + + + default-prepare-agent + + prepare-agent + + + + default-report + test + + report-aggregate + + + + +
+
+ + + + jdk8 + + [1.8,) + + + false + true + + + + ci-install + + true + false + + + + ci-test + + false + true + + + + release + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + + attach-javadocs + + jar + + + -Xdoclint:none + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + false + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + + +
diff --git a/server/common/model/pom.xml b/server/common/model/pom.xml new file mode 100644 index 000000000..d87c55c92 --- /dev/null +++ b/server/common/model/pom.xml @@ -0,0 +1,37 @@ + + + + com.alipay.sofa + registry-common + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-common-model + + + ../../../ + + + + + com.alipay.sofa + registry-core + + + com.alipay.sofa + registry-consistency + + + com.fasterxml.jackson.core + jackson-annotations + + + com.alipay.sofa + registry-common-util + + + diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/CommonResponse.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/CommonResponse.java new file mode 100644 index 000000000..e85455adf --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/CommonResponse.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +import java.io.Serializable; + +/** + * common result + * + * @author qian.lqlq + * @version $Id: CommonResponse.java, v 0.1 2017-12-06 15:48 qian.lqlq Exp $ + */ +public class CommonResponse implements Serializable { + + private static final long serialVersionUID = 8269764971983130557L; + + private boolean success; + + private String message; + + /** + * constructor + */ + public CommonResponse() { + } + + /** + * constructor + * @param success + * @param message + */ + public CommonResponse(boolean success, String message) { + this.success = success; + this.message = message; + } + + /** + * build success resp + * @return + */ + public static CommonResponse buildSuccessResponse() { + return new CommonResponse(true, ""); + } + + /** + * build success resp + * @return + */ + public static CommonResponse buildSuccessResponse(String msg) { + return new CommonResponse(true, msg); + } + + /** + * build fail resp + * @param msg + * @return + */ + public static CommonResponse buildFailedResponse(String msg) { + return new CommonResponse(false, msg); + } + + /** + * Getter method for property success. + * + * @return property value of success + */ + public boolean isSuccess() { + return success; + } + + /** + * Setter method for property success. + * + * @param success value to be assigned to property success + */ + public void setSuccess(boolean success) { + this.success = success; + } + + /** + * Getter method for property message. + * + * @return property value of message + */ + public String getMessage() { + return message; + } + + /** + * Setter method for property message. + * + * @param message value to be assigned to property message + */ + public void setMessage(String message) { + this.message = message; + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ElementType.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ElementType.java new file mode 100644 index 000000000..69adfbcdf --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ElementType.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +/** + * + * @author shangyu.wh + * @version $Id: ElementType.java, v 0.1 2018-08-17 16:22 shangyu.wh Exp $ + */ +public enum ElementType { + + /** + * sub zone scope,@see DefaultSubscriber + */ + SUBSCRIBER, + /** + * multiple zone sub,@see DefaultSubscriberMulti + */ + MULTISUBSCRIBER, + /** */ + PUBLISHER +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/GenericResponse.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/GenericResponse.java new file mode 100644 index 000000000..1f258d584 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/GenericResponse.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +/** + * generic response + * + * @author qian.lqlq + * @version $Id: GenericResponse.java, v 0.1 2017-12-06 19:54 qian.lqlq Exp $ + */ +public class GenericResponse extends CommonResponse { + + private static final long serialVersionUID = -3986568405174281303L; + + private T data; + + /** + * get success response + * @param data + * @return + */ + public GenericResponse fillSucceed(T data) { + this.setSuccess(true); + this.setData(data); + return this; + } + + /** + * get fail response + * @param msg + * @return + */ + public GenericResponse fillFailed(String msg) { + this.setSuccess(false); + this.setMessage(msg); + return this; + } + + /** + * Getter method for property data. + * + * @return property value of data + */ + public T getData() { + return data; + } + + /** + * Setter method for property data. + * + * @param data value to be assigned to property data + */ + public void setData(T data) { + this.data = data; + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/Node.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/Node.java new file mode 100644 index 000000000..3342b422d --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/Node.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +import com.alipay.sofa.registry.common.model.store.URL; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: node.java, v 0.1 2017-11-28 11:59 shangyu.wh Exp $ + */ +public interface Node extends Serializable { + + /** + * node type enum + */ + enum NodeType { + CLIENT, SESSION, META, DATA, CONSOLE + } + + /** + * node status enum + */ + enum NodeStatus { + INIT, PREPARE, WORKING + } + + /** + * get node type + * @return + */ + NodeType getNodeType(); + + /** + * get node status + * @return + */ + NodeStatus getNodeStatus(); + + /** + * set node status + * @param nodeStatus + */ + void setNodeStatus(NodeStatus nodeStatus); + + /** + * get node url + * @return + */ + URL getNodeUrl(); +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PublishType.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PublishType.java new file mode 100644 index 000000000..d32dea92d --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PublishType.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +/** + * + * @author shangyu.wh + * @version $Id: PublishType.java, v 0.1 2018-08-29 17:11 shangyu.wh Exp $ + */ +public enum PublishType { + + /** + * normally publisher + */ + NORMAL, + /** + * TEMPORARY publisher + */ + TEMPORARY + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PushDataRetryRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PushDataRetryRequest.java new file mode 100644 index 000000000..37af0474a --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/PushDataRetryRequest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +import com.alipay.sofa.registry.common.model.store.URL; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: PushDataRetryRequest.java, v 0.1 2019-02-20 14:47 shangyu.wh Exp $ + */ +public class PushDataRetryRequest { + + private AtomicInteger retryTimes = new AtomicInteger(); + + private final T pushObj; + private final URL url; + + public PushDataRetryRequest(T pushObj, URL url) { + this.pushObj = pushObj; + this.url = url; + } + + /** + * Getter method for property retryTimes. + * + * @return property value of retryTimes + */ + public AtomicInteger getRetryTimes() { + return retryTimes; + } + + /** + * Getter method for property pushObj. + * + * @return property value of pushObj + */ + public T getPushObj() { + return pushObj; + } + + /** + * Getter method for property url. + * + * @return property value of url + */ + public URL getUrl() { + return url; + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBox.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBox.java new file mode 100644 index 000000000..75dc51877 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBox.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ServerDataBox.java, v 0.1 2018-03-03 17:44 zhuoyu.sjw Exp $$ + */ +public class ServerDataBox implements Serializable { + + /** UID */ + private static final long serialVersionUID = 2817539491173993030L; + /** */ + private static final int SERIALIZED_BY_JAVA = 1; + /** Null for locally instantiated, otherwise for internalized */ + private byte[] bytes; + /** Only available if bytes != null */ + private int serialization; + /** Actual object, lazy deserialized */ + private Object object; + + /** + * Instantiates a new DataBox. + */ + public ServerDataBox() { + } + + /** + * Instantiates a new DataBox. + * + * @param object the object + */ + public ServerDataBox(Object object) { + this.object = object; + } + + /** + * Instantiates a new DataBox. + * + * @param bytes the bytes + */ + public ServerDataBox(byte[] bytes) { + this.bytes = bytes; + this.serialization = SERIALIZED_BY_JAVA; + } + + /** + * Is in bytes boolean. + * + * @return boolean boolean + */ + @JsonIgnore + public boolean isInBytes() { + return bytes != null; + } + + /** + * Only when isInBytes() == false + * @return Object object + */ + public Object getObject() { + return object; + } + + /** + * transfer bytes to object + * @return Object object + * @throws IOException the io exception + * @throws ClassNotFoundException the class not found exception + */ + public Object extract() throws IOException, ClassNotFoundException { + if (isInBytes()) { + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + if (serialization != SERIALIZED_BY_JAVA) { + throw new IOException("Unsupported serialization type: " + serialization); + } + ServerDataBoxInputStream input = null; + try { + input = new ServerDataBoxInputStream(bis); + object = input.readObject(); + } finally { + if (input != null) { + input.close(); + } + } + } + + return object; + } + + /** + * change object to bytes + * + * @return NSwizzle swizzle + */ + public ServerDataBox object2bytes() { + if (!isInBytes()) { + bytes = getBytes(object); + serialization = SERIALIZED_BY_JAVA; + } + return this; + } + + public static byte[] getBytes(Object object) { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream javaos = null; + try { + javaos = new ObjectOutputStream(bos); + javaos.writeObject(object); + } catch (IOException ioe) { + //do nothing + } finally { + try { + if (null != javaos) { + javaos.close(); + } + } catch (IOException ioe) { + //do nothing + } + } + return bos.toByteArray(); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + serialization = in.readByte(); // Read serialization type + int size = in.readInt(); // Read byte stream size + bytes = new byte[size]; + in.readFully(bytes); // Read the byte stream + } + + private void writeObject(ObjectOutputStream out) throws IOException { + if (isInBytes()) { + out.writeByte(serialization); // Write serialization type + out.writeInt(bytes.length); // Write byte stream size + out.write(bytes); // Write the byte stream + } else { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream javaos = new ObjectOutputStream(bos); + try { + javaos.writeObject(object); + } finally { + try { + javaos.close(); + } catch (IOException ioe) { + //do nothing + } + } + out.writeByte(SERIALIZED_BY_JAVA); // Write serialization type + out.writeInt(bos.size()); // Write byte stream size + out.write(bos.toByteArray()); // Write the byte stream + } + } + + /** + * Get bytes byte [ ]. + * + * @return byte[] byte [ ] + */ + public byte[] getBytes() { + return bytes; + } + + /** + * Set bytes byte [ ]. + * + * @return byte[] byte [ ] + */ + public void setBytes(byte[] bytes) { + this.bytes = bytes; + } + + /** + * Gets serialization. + * + * @return int serialization + */ + public int getSerialization() { + return this.serialization; + } + + /** + * Sets serialization. + * + * @param serial the serial + */ + public void setSerialization(int serial) { + this.serialization = serial; + } + +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBoxInputStream.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBoxInputStream.java new file mode 100644 index 000000000..302cf80ef --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/ServerDataBoxInputStream.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; + +/** + * The type DataBox input stream. + * @author zhuoyu.sjw + * @version $Id : ServerDataBoxInputStream.java, v 0.1 2017-11-28 17:48 zhuoyu.sjw Exp $$ + */ +public class ServerDataBoxInputStream extends ObjectInputStream { + + /** + * Instantiates a new DataBox input stream. + * + * @param in the in + * @throws IOException the io exception + */ + public ServerDataBoxInputStream(InputStream in) throws IOException { + super(in); + } + + /** + * @see ObjectInputStream#resolveClass(ObjectStreamClass) + */ + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, + ClassNotFoundException { + String name = desc.getName(); + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + return Class.forName(name, false, classLoader); + } catch (ClassNotFoundException ex) { + return super.resolveClass(desc); + } + } +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/console/PersistenceData.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/console/PersistenceData.java new file mode 100644 index 000000000..75ae50f11 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/console/PersistenceData.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.console; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: PersistenceData.java, v 0.1 2018-04-18 11:20 shangyu.wh Exp $ + */ +public class PersistenceData implements Serializable { + + private String dataId; + + private String group; + + private String instanceId; + + private Long version; + + private String data; + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property data. + * + * @return property value of data + */ + public String getData() { + return data; + } + + /** + * Setter method for property data. + * + * @param data value to be assigned to property data + */ + public void setData(String data) { + this.data = data; + } + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = dataId; + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + @Override + public String toString() { + return "PersistenceData{" + "dataId='" + dataId + '\'' + ", group='" + group + '\'' + + ", instanceId='" + instanceId + '\'' + ", version=" + version + ", data='" + data + + '\'' + '}'; + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/constants/ValueConstants.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/constants/ValueConstants.java new file mode 100644 index 000000000..bd6f20409 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/constants/ValueConstants.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.constants; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ValueConstants.java, v 0.1 2018-03-28 23:07 zhuoyu.sjw Exp $$ + */ +public class ValueConstants { + + /** + * The constant DEFAULT_GROUP. + */ + public static final String DEFAULT_GROUP = "DEFAULT_GROUP"; + + /** + * The constant DEFAULT_ZONE. + */ + public static final String DEFAULT_ZONE = "DEFAULT_ZONE"; + + public static final String DEFAULT_INSTANCE_ID = "DEFAULT_INSTANCE_ID"; + + /** + * The constant DEFAULT_DATA_CENTER. + */ + public static final String DEFAULT_DATA_CENTER = "DefaultDataCenter"; + + public static final long DEFAULT_NO_DATUM_VERSION = 1L; + + private static final Integer SYSTEM_RAFT_PORT = Integer + .getInteger("RAFT_SERVER_PORT"); + + public static final int RAFT_SERVER_PORT = SYSTEM_RAFT_PORT != null ? SYSTEM_RAFT_PORT + : 9614; + + private static final String SYSTEM_RAFT_GROUP = System + .getProperty("RAFT_SERVER_GROUP"); + + public static final String RAFT_SERVER_GROUP = SYSTEM_RAFT_GROUP != null ? SYSTEM_RAFT_GROUP + : "RegistryGroup"; + + public static final String STOP_PUSH_DATA_SWITCH_DATA_ID = "session.stop.push.data.switch#@#9600#@#CONFIG"; + +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/ClientOffRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/ClientOffRequest.java new file mode 100644 index 000000000..0d48ab7ed --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/ClientOffRequest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * request to remove data of specific clients immediately + * + * @author qian.lqlq + * @version $Id: ClientOffRequest.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class ClientOffRequest implements Serializable { + + private static final long serialVersionUID = -3547806571058756207L; + + /** + * hosts of clients + */ + private List hosts; + + private long gmtOccur; + + /** + * constructor + */ + public ClientOffRequest() { + } + + /** + * constructor + * @param host + */ + public ClientOffRequest(String host) { + this.hosts = new ArrayList<>(); + this.hosts.add(host); + } + + /** + * Getter method for property hosts. + * + * @return property value of hosts + */ + public List getHosts() { + return hosts; + } + + /** + * Setter method for property hosts. + * + * @param hosts value to be assigned to property hosts + */ + public void setHosts(List hosts) { + this.hosts = hosts; + } + + /** + * Getter method for property gmtOccur. + * + * @return property value of gmtOccur + */ + public long getGmtOccur() { + return gmtOccur; + } + + /** + * Setter method for property gmtOccur. + * + * @param gmtOccur value to be assigned to property gmtOccur + */ + public void setGmtOccur(long gmtOccur) { + this.gmtOccur = gmtOccur; + } + + @Override + public String toString() { + return new StringBuilder("[ClientOffRequest] ips=").append(this.hosts) + .append(", gmtOccur=").append(gmtOccur).toString(); + } +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/Datum.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/Datum.java new file mode 100644 index 000000000..61044ea8f --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/Datum.java @@ -0,0 +1,269 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.WordCache; + +import java.io.Serializable; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * datum store in dataserver + * + * @author qian.lqlq + * @version $Id: Datum.java, v 0.1 2017-12-07 11:19 qian.lqlq Exp $ + */ +public class Datum implements Serializable { + + private static final long serialVersionUID = 5307489721610438103L; + + private String dataInfoId; + + private String dataCenter; + + private String dataId; + + private String instanceId; + + private String group; + + private Map pubMap = new ConcurrentHashMap<>(); + + private long version; + + private boolean containsUnPub = false; + + /** + * constructor + */ + public Datum() { + } + + /** + * constructor + * @param dataInfoId + * @param dataCenter + */ + public Datum(String dataInfoId, String dataCenter) { + this.dataInfoId = dataInfoId; + this.dataCenter = WordCache.getInstance().getWordCache(dataCenter); + updateVersion(); + } + + /** + * constructor + * @param publisher + * @param dataCenter + */ + public Datum(Publisher publisher, String dataCenter) { + this(publisher.getDataInfoId(), dataCenter); + this.dataId = publisher.getDataId(); + this.instanceId = publisher.getInstanceId(); + this.group = publisher.getGroup(); + pubMap.put(publisher.getRegisterId(), publisher); + } + + /** + * constructor + * @param publisher + * @param dataCenter + * @param version + */ + public Datum(Publisher publisher, String dataCenter, long version) { + this.dataInfoId = publisher.getDataInfoId(); + this.dataCenter = WordCache.getInstance().getWordCache(dataCenter); + this.version = version; + this.dataId = publisher.getDataId(); + this.instanceId = publisher.getInstanceId(); + this.group = publisher.getGroup(); + pubMap.put(publisher.getRegisterId(), publisher); + } + + public void updateVersion() { + this.version = System.currentTimeMillis(); + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = WordCache.getInstance().getWordCache(dataInfoId); + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = WordCache.getInstance().getWordCache(dataCenter); + } + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = WordCache.getInstance().getWordCache(dataId); + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = WordCache.getInstance().getWordCache(instanceId); + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = WordCache.getInstance().getWordCache(group); + } + + /** + * Getter method for property pubMap. + * + * @return property value of pubMap + */ + public Map getPubMap() { + return pubMap; + } + + /** + * Setter method for property pubMap. + * + * @param pubMap value to be assigned to property pubMap + */ + public void setPubMap(Map pubMap) { + this.pubMap = pubMap; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(long version) { + this.version = version; + } + + /** + * Getter method for property containsUnPub. + * + * @return property value of containsUnPub + */ + public boolean isContainsUnPub() { + return containsUnPub; + } + + /** + * Setter method for property containsUnPub. + * + * @param containsUnPub value to be assigned to property containsUnPub + */ + public void setContainsUnPub(boolean containsUnPub) { + this.containsUnPub = containsUnPub; + } + + public static Datum processDatum(Datum datum) { + datum.setDataCenter(datum.getDataCenter()); + datum.setDataInfoId(datum.getDataInfoId()); + datum.setDataId(datum.getDataId()); + datum.setGroup(datum.getGroup()); + datum.setInstanceId(datum.getInstanceId()); + + Map pubMap = datum.getPubMap(); + if (pubMap != null && !pubMap.isEmpty()) { + pubMap.forEach((registerId, publisher) -> Publisher.processPublisher(publisher)); + } + + return datum; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("[Datum] dataInfoId=").append(dataInfoId) + .append(", dataId=").append(dataId).append(", dataCenter=").append(dataCenter) + .append(", instanceId=").append(instanceId).append(", version=").append(version) + .append(", pubMap=").append(pubMap); + return sb.toString(); + } +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataRequest.java new file mode 100644 index 000000000..adff9ab73 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataRequest.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; + +/** + * request to get specific data + * + * @author qian.lqlq + * @version $Id: GetDataRequest.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class GetDataRequest implements Serializable { + + private static final long serialVersionUID = 8133437572926931258L; + + private String dataInfoId; + + /** + * if datacenter is null, means all datacenters + */ + private String dataCenter; + + /** + * constructor + */ + public GetDataRequest() { + } + + /** + * constructor + * @param dataInfoId + * @param dataCenter + */ + public GetDataRequest(String dataInfoId, String dataCenter) { + this.dataInfoId = dataInfoId; + this.dataCenter = dataCenter; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + } + + @Override + public String toString() { + return new StringBuilder("[GetDataRequest] dataCenter=").append(this.dataCenter) + .append(", dataInfoId=").append(this.dataInfoId).toString(); + } +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataVersionRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataVersionRequest.java new file mode 100644 index 000000000..3122f07da --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/GetDataVersionRequest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; +import java.util.List; + +/** + * request to get versions of specific data + * + * @author qian.lqlq + * @version $Id: GetDataVersionRequest.java, v 0.1 2017-12-01 下午4:58 qian.lqlq Exp $ + */ +public class GetDataVersionRequest implements Serializable { + + private static final long serialVersionUID = 8942977145684175886L; + + private List dataInfoIds; + + /** + * constructor + */ + public GetDataVersionRequest() { + } + + /** + * Getter method for property dataInfoIds. + * + * @return property value of dataInfoIds + */ + public List getDataInfoIds() { + return dataInfoIds; + } + + /** + * Setter method for property dataInfoIds. + * + * @param dataInfoIds value to be assigned to property dataInfoIds + */ + public void setDataInfoIds(List dataInfoIds) { + this.dataInfoIds = dataInfoIds; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("[GetDataVersionRequest] dataInfoIds="); + if (dataInfoIds != null) { + sb.append(this.dataInfoIds.size()); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyDataSyncRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyDataSyncRequest.java new file mode 100644 index 000000000..39f059651 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyDataSyncRequest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; + +/** + * + * @author qian.lqlq + * @version $Id: NotifyDataSyncRequest.java, v 0.1 2018-03-24 14:33 qian.lqlq Exp $ + */ +public class NotifyDataSyncRequest implements Serializable { + + private static final long serialVersionUID = 6855281580053659076L; + + private String dataInfoId; + + private String dataCenter; + + private long version; + + private String dataSourceType; + + /** + * constructor + */ + public NotifyDataSyncRequest() { + } + + /** + * constructor + * @param dataInfoId + * @param dataCenter + * @param version + * @param dataSourceType + */ + public NotifyDataSyncRequest(String dataInfoId, String dataCenter, long version, + String dataSourceType) { + this.dataInfoId = dataInfoId; + this.dataCenter = dataCenter; + this.version = version; + this.dataSourceType = dataSourceType; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(long version) { + this.version = version; + } + + /** + * Getter method for property dataSourceType. + * + * @return property value of dataSourceType + */ + public String getDataSourceType() { + return dataSourceType; + } + + /** + * Setter method for property dataSourceType. + * + * @param dataSourceType value to be assigned to property dataSourceType + */ + public void setDataSourceType(String dataSourceType) { + this.dataSourceType = dataSourceType; + } + + @Override + public String toString() { + return new StringBuilder("[NotifyDataSyncRequest] dataInfoId=").append(this.dataInfoId) + .append(", dataCenter=").append(this.dataCenter).append(", version=") + .append(this.version).append(", dataSourceType=").append(dataSourceType).toString(); + } +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyFetchDatumRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyFetchDatumRequest.java new file mode 100644 index 000000000..c33b123be --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyFetchDatumRequest.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author qian.lqlq + * @version $Id: NotifyFetchDatumRequest.java, v 0.1 2018-04-29 15:07 qian.lqlq Exp $ + */ +public class NotifyFetchDatumRequest implements Serializable { + + private static final long serialVersionUID = 410885158191567105L; + + private Map> dataVersionMap = new HashMap<>(); + + private String ip; + + private long changeVersion; + + /** + * construtor + * @param dataVersionMap + * @param ip + * @param changeVersion + */ + public NotifyFetchDatumRequest(Map> dataVersionMap, String ip, + long changeVersion) { + this.dataVersionMap = dataVersionMap; + this.ip = ip; + this.changeVersion = changeVersion; + } + + /** + * Getter method for property dataVersionMap. + * + * @return property value of dataVersionMap + */ + public Map> getDataVersionMap() { + return dataVersionMap; + } + + /** + * Setter method for property dataVersionMap. + * + * @param dataVersionMap value to be assigned to property dataVersionMap + */ + public void setDataVersionMap(Map> dataVersionMap) { + this.dataVersionMap = dataVersionMap; + } + + /** + * Getter method for property ip. + * + * @return property value of ip + */ + public String getIp() { + return ip; + } + + /** + * Setter method for property ip. + * + * @param ip value to be assigned to property ip + */ + public void setIp(String ip) { + this.ip = ip; + } + + /** + * Getter method for property changeVersion. + * + * @return property value of changeVersion + */ + public long getChangeVersion() { + return changeVersion; + } + + /** + * Setter method for property changeVersion. + * + * @param changeVersion value to be assigned to property changeVersion + */ + public void setChangeVersion(long changeVersion) { + this.changeVersion = changeVersion; + } + + @Override + public String toString() { + return new StringBuilder("[NotifyFetchDatumRequest] ip=").append(ip) + .append(", changeVersion=").append(changeVersion).toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyOnlineRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyOnlineRequest.java new file mode 100644 index 000000000..72472b6e8 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/NotifyOnlineRequest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; + +/** + * + * @author qian.lqlq + * @version $Id: NotifyOnlineRequest.java, v 0.1 2018-04-29 14:34 qian.lqlq Exp $ + */ +public class NotifyOnlineRequest implements Serializable { + + private static final long serialVersionUID = 934663828370697909L; + + private String ip; + + private long version; + + /** + * construtor + * @param ip + * @param version + */ + public NotifyOnlineRequest(String ip, long version) { + this.ip = ip; + this.version = version; + } + + /** + * Getter method for property ip. + * + * @return property value of ip + */ + public String getIp() { + return ip; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } + + @Override + public String toString() { + return new StringBuilder("[NotifyOnlineRequest] ip=").append(ip).append(", version=") + .append(version).toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/PublishDataRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/PublishDataRequest.java new file mode 100644 index 000000000..dfc244f74 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/PublishDataRequest.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import com.alipay.sofa.registry.common.model.store.Publisher; + +import java.io.Serializable; + +/** + * request to register publish data + * + * @author qian.lqlq + * @version $Id: PublishDataRequest.java, v 0.1 2017-12-06 15:56 qian.lqlq Exp $ + */ +public class PublishDataRequest implements Serializable { + + private static final long serialVersionUID = 3900211443485220361L; + + private Publisher publisher; + + private String sessionServerProcessId; + + /** + * Getter method for property publisher. + * + * @return property value of publisher + */ + public Publisher getPublisher() { + return publisher; + } + + /** + * Setter method for property publisher. + * + * @param publisher value to be assigned to property publisher + */ + public void setPublisher(Publisher publisher) { + this.publisher = publisher; + } + + /** + * Getter method for property sessionServerProcessId. + * + * @return property value of sessionServerProcessId + */ + public String getSessionServerProcessId() { + return sessionServerProcessId; + } + + /** + * Setter method for property sessionServerProcessId. + * + * @param sessionServerProcessId value to be assigned to property sessionServerProcessId + */ + public void setSessionServerProcessId(String sessionServerProcessId) { + this.sessionServerProcessId = sessionServerProcessId; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("[PublishDataRequest] sessionServerProcessId=") + .append(sessionServerProcessId); + sb.append(", dataInfoId="); + if (publisher != null) { + sb.append(publisher.getDataInfoId()); + sb.append(", sourceAddress=").append(publisher.getSourceAddress()); + sb.append(", registerId=").append(publisher.getRegisterId()); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SessionServerRegisterRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SessionServerRegisterRequest.java new file mode 100644 index 000000000..16f00f56b --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SessionServerRegisterRequest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: SessionServerRegisterRequest.java, v 0.1 2018-04-14 17:31 qian.lqlq Exp $ + */ +public class SessionServerRegisterRequest implements Serializable { + + private static final long serialVersionUID = 4872633119038341583L; + + private String processId; + + private Set clientHosts; + + /** + * constructor + * @param processId + * @param clientHosts + */ + public SessionServerRegisterRequest(String processId, Set clientHosts) { + this.processId = processId; + this.clientHosts = clientHosts; + } + + /** + * Getter method for property processId. + * + * @return property value of processId + */ + public String getProcessId() { + return processId; + } + + /** + * Setter method for property processId. + * + * @param processId value to be assigned to property processId + */ + public void setProcessId(String processId) { + this.processId = processId; + } + + /** + * Getter method for property clientHosts. + * + * @return property value of clientHosts + */ + public Set getClientHosts() { + return clientHosts; + } + + @Override + public String toString() { + return new StringBuilder("[SessionServerRegisterRequest] processId=") + .append(this.processId).append(", clientHosts=").append(this.clientHosts).toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncData.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncData.java new file mode 100644 index 000000000..f1eab66a2 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncData.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: SyncData.java, v 0.1 2018-03-07 17:57 shangyu.wh Exp $ + */ +public class SyncData implements Serializable { + + private String dataInfoId; + + private String dataCenter; + + private Collection datums; + + private boolean wholeDataTag; + + /** + * construtor + * @param dataInfoId + * @param dataCenter + * @param wholeDataTag + * @param datums + */ + public SyncData(String dataInfoId, String dataCenter, boolean wholeDataTag, + Collection datums) { + this.dataInfoId = dataInfoId; + this.dataCenter = dataCenter; + this.wholeDataTag = wholeDataTag; + this.datums = datums; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + } + + /** + * Getter method for property datums. + * + * @return property value of datums + */ + public Collection getDatums() { + return datums; + } + + /** + * Setter method for property datums. + * + * @param datums value to be assigned to property datums + */ + public void setDatums(Collection datums) { + this.datums = datums; + } + + /** + * Getter method for property wholeDataTag. + * + * @return property value of wholeDataTag + */ + public boolean getWholeDataTag() { + return wholeDataTag; + } + + /** + * Setter method for property wholeDataTag. + * + * @param wholeDataTag value to be assigned to property wholeDataTag + */ + public void setWholeDataTag(boolean wholeDataTag) { + this.wholeDataTag = wholeDataTag; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SyncData{"); + sb.append("dataInfoId='").append(dataInfoId).append('\''); + sb.append(", dataCenter='").append(dataCenter).append('\''); + sb.append(", wholeDataTag=").append(wholeDataTag); + sb.append(", datumsSize=").append(datums != null ? String.valueOf(datums.size()) : ""); + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncDataRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncDataRequest.java new file mode 100644 index 000000000..98a44f838 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/SyncDataRequest.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; + +/** + * request to sync data from dataserver in other dataCenter + * + * @author qian.lqlq + * @version $Id: SyncDataRequest.java, v 0.1 2018-03-07 15:22 qian.lqlq Exp $ + */ +public class SyncDataRequest implements Serializable { + + private static final long serialVersionUID = 7229539333106031495L; + + private String dataInfoId; + + private String dataCenter; + + private String dataSourceType; + + /** + * be null when dataInfoId not exist in local datumCache + */ + private Long version; + + /** + * construtor + * @param dataInfoId + * @param dataCenter + * @param version + * @param dataSourceType + */ + public SyncDataRequest(String dataInfoId, String dataCenter, Long version, String dataSourceType) { + this.dataInfoId = dataInfoId; + this.dataCenter = dataCenter; + this.version = version; + this.dataSourceType = dataSourceType; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property dataSourceType. + * + * @return property value of dataSourceType + */ + public String getDataSourceType() { + return dataSourceType; + } + + /** + * Setter method for property dataSourceType. + * + * @param dataSourceType value to be assigned to property dataSourceType + */ + public void setDataSourceType(String dataSourceType) { + this.dataSourceType = dataSourceType; + } + + @Override + public String toString() { + return new StringBuilder("[SyncDataRequest] dataInfoId=").append(dataInfoId) + .append(", dataCenter=").append(dataCenter).append(", version=").append(version) + .toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/UnPublishDataRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/UnPublishDataRequest.java new file mode 100644 index 000000000..cfa8554ac --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/dataserver/UnPublishDataRequest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.dataserver; + +import java.io.Serializable; + +/** + * request to unPublish data + * + * @author qian.lqlq + * @version $Id: UnPublishDataRequest.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class UnPublishDataRequest implements Serializable { + + private static final long serialVersionUID = 4344115202203415801L; + + private String dataInfoId; + + private String registerId; + + private long registerTimestamp; + + /** + * constructor + */ + public UnPublishDataRequest() { + } + + /** + * construtor + * @param dataInfoId + * @param registerId + * @param registerTimestamp + */ + public UnPublishDataRequest(String dataInfoId, String registerId, long registerTimestamp) { + this.dataInfoId = dataInfoId; + this.registerId = registerId; + this.registerTimestamp = registerTimestamp; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property registerId. + * + * @return property value of registerId + */ + public String getRegisterId() { + return registerId; + } + + /** + * Setter method for property registerId. + * + * @param registerId value to be assigned to property registerId + */ + public void setRegisterId(String registerId) { + this.registerId = registerId; + } + + /** + * Getter method for property registerTimestamp. + * + * @return property value of registerTimestamp + */ + public long getRegisterTimestamp() { + return registerTimestamp; + } + + /** + * Setter method for property registerTimestamp. + * + * @param registerTimestamp value to be assigned to property registerTimestamp + */ + public void setRegisterTimestamp(long registerTimestamp) { + this.registerTimestamp = registerTimestamp; + } + + @Override + public String toString() { + return new StringBuilder("[UnPublishDataRequest] dataInfoId=").append(this.dataInfoId) + .append(", registerId=").append(this.registerId).append(", registerTimestamp=") + .append(this.registerTimestamp).toString(); + } +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataCenterNodes.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataCenterNodes.java new file mode 100644 index 000000000..23097f494 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataCenterNodes.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; + +import java.io.Serializable; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: DataCenterNodes.java, v 0.1 2018-02-12 11:06 shangyu.wh Exp $ + */ +public class DataCenterNodes implements Serializable { + + private final NodeType nodeType; + + private Long version; + + private String dataCenterId; + + private Map nodes; + + /** + * constructor + * @param nodeType + * @param version + * @param dataCenterId + */ + public DataCenterNodes(NodeType nodeType, Long version, String dataCenterId) { + this.nodeType = nodeType; + this.version = version; + this.dataCenterId = dataCenterId; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property dataCenterId. + * + * @return property value of dataCenterId + */ + public String getDataCenterId() { + return dataCenterId; + } + + /** + * Setter method for property dataCenterId. + * + * @param dataCenterId value to be assigned to property dataCenterId + */ + public void setDataCenterId(String dataCenterId) { + this.dataCenterId = dataCenterId; + } + + /** + * Getter method for property nodes. + * + * @return property value of nodes + */ + public Map getNodes() { + return nodes; + } + + /** + * Setter method for property nodes. + * + * @param nodes value to be assigned to property nodes + */ + public void setNodes(Map nodes) { + this.nodes = nodes; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DataCenterNodes{"); + sb.append("nodeType=").append(nodeType); + sb.append(", version=").append(version); + sb.append(", dataCenterId='").append(dataCenterId).append('\''); + sb.append(", nodes=").append(nodes); + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataNode.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataNode.java new file mode 100644 index 000000000..ca3bba378 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataNode.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.consistency.hash.HashNode; + +/** + * + * @author shangyu.wh + * @version $Id: DataNode.java, v 0.1 2018-01-18 18:06 shangyu.wh Exp $ + */ +public class DataNode implements Node, HashNode { + + private final URL nodeUrl; + + private final String nodeName; + + private final String dataCenter; + + private String regionId; + + private NodeStatus nodeStatus; + + private long registrationTimestamp; + + /** + * constructor + * @param nodeUrl + * @param dataCenter + */ + public DataNode(URL nodeUrl, String dataCenter) { + this.nodeUrl = nodeUrl; + this.nodeName = nodeUrl.getIpAddress(); + this.dataCenter = dataCenter; + this.nodeStatus = NodeStatus.INIT; + } + + /** + * constructor + * @param nodeUrl + * @param dataCenter + * @param status + */ + public DataNode(URL nodeUrl, String dataCenter, NodeStatus status) { + this(nodeUrl, dataCenter); + this.nodeStatus = status; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DataNode)) { + return false; + } + + DataNode that = (DataNode) o; + + if (nodeStatus != null ? !nodeStatus.equals(that.nodeStatus) : that.nodeStatus != null) { + return false; + } + if (nodeName != null ? !nodeName.equals(that.nodeName) : that.nodeName != null) { + return false; + } + + if (dataCenter != null ? !dataCenter.equals(that.dataCenter) : that.dataCenter != null) { + return false; + } + + if (regionId != null ? !regionId.equals(that.regionId) : that.regionId != null) { + return false; + } + + if (registrationTimestamp != that.registrationTimestamp) { + return false; + } + + return nodeUrl != null ? (nodeUrl.getAddressString() != null ? nodeUrl.getAddressString() + .equals(that.nodeUrl.getAddressString()) : that.nodeUrl.getAddressString() != null) + : that.nodeUrl != null; + } + + /** + * Hash code int. + * + * @return the int + */ + @Override + public int hashCode() { + int result = nodeName != null ? nodeName.hashCode() : 0; + result = 31 * result + (dataCenter != null ? dataCenter.hashCode() : 0); + result = 31 * result + (regionId != null ? regionId.hashCode() : 0); + result = 31 * result + (nodeStatus != null ? nodeStatus.hashCode() : 0); + result = 31 * result + (int) (registrationTimestamp ^ (registrationTimestamp >>> 32)); + result = 31 + * result + + (nodeUrl != null ? (nodeUrl.getAddressString() != null ? nodeUrl + .getAddressString().hashCode() : 0) : 0); + return result; + } + + @Override + public NodeType getNodeType() { + return NodeType.DATA; + } + + @Override + public URL getNodeUrl() { + return nodeUrl; + } + + /** + * get ip address for nodeUrl + * @return + */ + public String getIp() { + return nodeUrl == null ? "" : nodeUrl.getIpAddress(); + } + + /** + * Getter method for property nodeName. + * + * @return property value of nodeName + */ + @Override + public String getNodeName() { + return nodeName; + } + + /** + * Getter method for property regionId. + * + * @return property value of regionId + */ + public String getRegionId() { + return regionId; + } + + /** + * Setter method for property regionId. + * + * @param regionId value to be assigned to property regionId + */ + public void setRegionId(String regionId) { + this.regionId = regionId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Getter method for property nodeStatus. + * + * @return property value of nodeStatus + */ + @Override + public NodeStatus getNodeStatus() { + return nodeStatus; + } + + /** + * Setter method for property nodeStatus. + * + * @param nodeStatus value to be assigned to property nodeStatus + */ + @Override + public void setNodeStatus(NodeStatus nodeStatus) { + this.nodeStatus = nodeStatus; + } + + /** + * Getter method for property registrationTimestamp. + * + * @return property value of registrationTimestamp + */ + public long getRegistrationTimestamp() { + return registrationTimestamp; + } + + /** + * Setter method for property registrationTimestamp. + * + * @param registrationTimestamp value to be assigned to property registrationTimestamp + */ + public void setRegistrationTimestamp(long registrationTimestamp) { + this.registrationTimestamp = registrationTimestamp; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DataNode{"); + sb.append("ip=").append(getIp()); + sb.append(", dataCenter='").append(dataCenter).append('\''); + sb.append(", regionId='").append(regionId).append('\''); + sb.append(", nodeStatus=").append(nodeStatus); + sb.append(", registrationTimestamp=").append(registrationTimestamp); + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataOperator.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataOperator.java new file mode 100644 index 000000000..e8b984932 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/DataOperator.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +/** + * + * @author shangyu.wh + * @version $Id: DataOperator.java, v 0.1 2018-04-17 21:03 shangyu.wh Exp $ + */ +public enum DataOperator { + ADD, REMOVE, UPDATE, QUERY +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/FetchProvideDataRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/FetchProvideDataRequest.java new file mode 100644 index 000000000..86de06583 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/FetchProvideDataRequest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: FetchProvideDataRequest.java, v 0.1 2018-04-17 21:19 shangyu.wh Exp $ + */ +public class FetchProvideDataRequest implements Serializable { + + private final String dataInfoId; + + /** + * construtor + * @param dataInfoId + */ + public FetchProvideDataRequest(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("FetchProvideDataRequest{"); + sb.append("dataInfoId='").append(dataInfoId).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetChangeListRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetChangeListRequest.java new file mode 100644 index 000000000..298ab73cc --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetChangeListRequest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node.NodeType; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: GetChangeListRequest.java, v 0.1 2018-02-12 11:02 shangyu.wh Exp $ + */ +public class GetChangeListRequest implements Serializable { + + private final NodeType nodeType; + + /** + * get list data dataCenter + */ + private String dataCenterId; + + /** + * constructor + * @param nodeType + * @param dataCenterId + */ + public GetChangeListRequest(NodeType nodeType, String dataCenterId) { + this.nodeType = nodeType; + this.dataCenterId = dataCenterId; + } + + /** + * Getter method for property dataCenterId. + * + * @return property value of dataCenterId + */ + public String getDataCenterId() { + return dataCenterId; + } + + /** + * Setter method for property dataCenterId. + * + * @param dataCenterId value to be assigned to property dataCenterId + */ + public void setDataCenterId(String dataCenterId) { + this.dataCenterId = dataCenterId; + } + + /** + * Getter method for property nodeType. + * + * @return property value of nodeType + */ + public NodeType getNodeType() { + return nodeType; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("GetChangeListRequest{"); + sb.append("nodeType=").append(nodeType); + sb.append(", dataCenterId='").append(dataCenterId).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetNodesRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetNodesRequest.java new file mode 100644 index 000000000..e802e06e4 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/GetNodesRequest.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node.NodeType; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: GetNodesRequest.java, v 0.1 2018-03-02 15:07 shangyu.wh Exp $ + */ +public class GetNodesRequest implements Serializable { + + private final NodeType nodeType; + + /** + * constructor + * @param nodeType + */ + public GetNodesRequest(NodeType nodeType) { + this.nodeType = nodeType; + } + + /** + * Getter method for property nodeType. + * + * @return property value of nodeType + */ + public NodeType getNodeType() { + return nodeType; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("GetNodesRequest{"); + sb.append("nodeType=").append(nodeType); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/MetaNode.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/MetaNode.java new file mode 100644 index 000000000..6adf2457c --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/MetaNode.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.store.URL; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNode.java, v 0.1 2018-03-02 16:42 shangyu.wh Exp $ + */ +public class MetaNode implements Node { + + private final NodeType nodeType = NodeType.META; + + private final URL nodeUrl; + + private final String dataCenter; + + private String name; + + private String regionId; + + private NodeStatus nodeStatus; + + /** + * constructor + * @param nodeUrl + * @param dataCenter + */ + public MetaNode(URL nodeUrl, String dataCenter) { + this.nodeUrl = nodeUrl; + this.name = getIp(); + this.dataCenter = dataCenter; + this.nodeStatus = NodeStatus.INIT; + } + + @Override + public NodeType getNodeType() { + return nodeType; + } + + @Override + public NodeStatus getNodeStatus() { + return nodeStatus; + } + + @Override + public URL getNodeUrl() { + return nodeUrl; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * get ip address from nodeUrl + * @return + */ + public String getIp() { + return nodeUrl == null ? "" : nodeUrl.getIpAddress(); + } + + /** + * Setter method for property nodeStatus. + * + * @param nodeStatus value to be assigned to property nodeStatus + */ + @Override + public void setNodeStatus(NodeStatus nodeStatus) { + this.nodeStatus = nodeStatus; + } + + /** + * Getter method for property name. + * + * @return property value of name + */ + public String getName() { + return name; + } + + /** + * Setter method for property name. + * + * @param name value to be assigned to property name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Getter method for property regionId. + * + * @return property value of regionId + */ + public String getRegionId() { + return regionId; + } + + /** + * Setter method for property regionId. + * + * @param regionId value to be assigned to property regionId + */ + public void setRegionId(String regionId) { + this.regionId = regionId; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("MetaNode{"); + sb.append("nodeUrl=").append(getIp()); + sb.append(", dataCenter='").append(dataCenter).append('\''); + sb.append(", regionId='").append(regionId).append('\''); + sb.append(", nodeStatus=").append(nodeStatus); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NodeChangeResult.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NodeChangeResult.java new file mode 100644 index 000000000..dd9e9c4c2 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NodeChangeResult.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; + +import java.io.Serializable; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: NodeChangeRequest.java, v 0.1 2018-01-11 16:55 shangyu.wh Exp $ + */ +public class NodeChangeResult implements Serializable { + + private final NodeType nodeType; + + private Map> nodes; + + private Long version; + + private Map dataCenterListVersions; + + /** local dataCenter id */ + private String localDataCenter; + + /** + * constructor + * @param nodeType + */ + public NodeChangeResult(NodeType nodeType) { + this.nodeType = nodeType; + } + + /** + * Getter method for property nodeType. + * + * @return property value of nodeType + */ + public NodeType getNodeType() { + return nodeType; + } + + /** + * Getter method for property nodes. + * + * @return property value of nodes + */ + public Map> getNodes() { + return nodes; + } + + /** + * Setter method for property nodes. + * + * @param nodes value to be assigned to property nodes + */ + public void setNodes(Map> nodes) { + this.nodes = nodes; + } + + /** + * Getter method for property localDataCenter. + * + * @return property value of localDataCenter + */ + public String getLocalDataCenter() { + return localDataCenter; + } + + /** + * Setter method for property localDataCenter. + * + * @param localDataCenter value to be assigned to property localDataCenter + */ + public void setLocalDataCenter(String localDataCenter) { + this.localDataCenter = localDataCenter; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property dataCenterListVersions. + * + * @return property value of dataCenterListVersions + */ + public Map getDataCenterListVersions() { + return dataCenterListVersions; + } + + /** + * Setter method for property dataCenterListVersions. + * + * @param dataCenterListVersions value to be assigned to property dataCenterListVersions + */ + public void setDataCenterListVersions(Map dataCenterListVersions) { + this.dataCenterListVersions = dataCenterListVersions; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("NodeChangeResult{"); + sb.append("nodeType=").append(nodeType); + sb.append(", nodes=").append(nodes); + sb.append(", version=").append(version); + sb.append(", dataCenterListVersions=").append(dataCenterListVersions); + sb.append(", localDataCenter='").append(localDataCenter).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NotifyProvideDataChange.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NotifyProvideDataChange.java new file mode 100644 index 000000000..ad14df8f0 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/NotifyProvideDataChange.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: NotifyProvideDataChange.java, v 0.1 2018-04-18 15:18 shangyu.wh Exp $ + */ +public class NotifyProvideDataChange implements Serializable { + + private String dataInfoId; + + private Long version; + + private DataOperator dataOperator; + + /** + * constructor + * @param dataInfoId + * @param version + * @param dataOperator + */ + public NotifyProvideDataChange(String dataInfoId, Long version, DataOperator dataOperator) { + this.dataInfoId = dataInfoId; + this.version = version; + this.dataOperator = dataOperator; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property dataOperator. + * + * @return property value of dataOperator + */ + public DataOperator getDataOperator() { + return dataOperator; + } + + /** + * Setter method for property dataOperator. + * + * @param dataOperator value to be assigned to property dataOperator + */ + public void setDataOperator(DataOperator dataOperator) { + this.dataOperator = dataOperator; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("NotifyProvideDataChange{"); + sb.append("dataInfoId='").append(dataInfoId).append('\''); + sb.append(", version=").append(version); + sb.append(", dataOperator=").append(dataOperator); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ProvideData.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ProvideData.java new file mode 100644 index 000000000..15955f64c --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ProvideData.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.ServerDataBox; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: ProvideData.java, v 0.1 2018-04-17 20:13 shangyu.wh Exp $ + */ +public class ProvideData implements Serializable { + + private ServerDataBox provideData; + + private String dataInfoId; + + private Long version; + + /** + * construtor + * @param provideData + * @param dataInfoId + * @param version + */ + public ProvideData(ServerDataBox provideData, String dataInfoId, Long version) { + this.provideData = provideData; + this.dataInfoId = dataInfoId; + this.version = version; + } + + /** + * Getter method for property provideData. + * + * @return property value of provideData + */ + public ServerDataBox getProvideData() { + return provideData; + } + + /** + * Setter method for property provideData. + * + * @param provideData value to be assigned to property provideData + */ + public void setProvideData(ServerDataBox provideData) { + this.provideData = provideData; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ProvideData{"); + sb.append("provideData=").append(provideData); + sb.append(", dataInfoId='").append(dataInfoId).append('\''); + sb.append(", version=").append(version); + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ReNewNodesRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ReNewNodesRequest.java new file mode 100644 index 000000000..50485e65c --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/ReNewNodesRequest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: RenewNodesRequest.java, v 0.1 2018-03-30 19:51 shangyu.wh Exp $ + */ +public class ReNewNodesRequest implements Serializable { + + private int duration; + + private final T node; + + /** + * constructor + * @param node + */ + public ReNewNodesRequest(T node) { + this.node = node; + } + + /** + * Getter method for property duration. + * + * @return property value of duration + */ + public int getDuration() { + return duration; + } + + /** + * Setter method for property duration. + * + * @param duration value to be assigned to property duration + */ + public void setDuration(int duration) { + this.duration = duration; + } + + /** + * Getter method for property node. + * + * @return property value of node + */ + public T getNode() { + return node; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ReNewNodesRequest{"); + sb.append("duration=").append(duration); + sb.append(", node=").append(node); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/SessionNode.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/SessionNode.java new file mode 100644 index 000000000..d6beeaf67 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/SessionNode.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.store.URL; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeRegister.java, v 0.1 2018-01-11 16:32 shangyu.wh Exp $ + */ +public class SessionNode implements Node { + + private URL nodeUrl; + + private String regionId; + + private String name; + + private NodeStatus nodeStatus; + + /** + * constructor + * @param nodeUrl + * @param regionId + */ + public SessionNode(URL nodeUrl, String regionId) { + this.nodeUrl = nodeUrl; + this.regionId = regionId; + this.nodeStatus = NodeStatus.INIT; + } + + @Override + public NodeType getNodeType() { + return NodeType.SESSION; + } + + @Override + public URL getNodeUrl() { + return nodeUrl; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SessionNode)) { + return false; + } + + SessionNode that = (SessionNode) o; + + if (nodeStatus != null ? !nodeStatus.equals(that.nodeStatus) : that.nodeStatus != null) { + return false; + } + if (name != null ? !name.equals(that.name) : that.name != null) { + return false; + } + + if (regionId != null ? !regionId.equals(that.regionId) : that.regionId != null) { + return false; + } + + return nodeUrl != null ? (nodeUrl.getAddressString() != null ? nodeUrl.getAddressString() + .equals(that.nodeUrl.getAddressString()) : that.nodeUrl.getAddressString() != null) + : that.nodeUrl != null; + } + + /** + * Hash code int. + * + * @return the int + */ + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (regionId != null ? regionId.hashCode() : 0); + result = 31 * result + (nodeStatus != null ? nodeStatus.hashCode() : 0); + result = 31 + * result + + (nodeUrl != null ? (nodeUrl.getAddressString() != null ? nodeUrl + .getAddressString().hashCode() : 0) : 0); + return result; + } + + /** + * Setter method for property nodeUrl. + * + * @param nodeUrl value to be assigned to property nodeUrl + */ + public void setNodeUrl(URL nodeUrl) { + this.nodeUrl = nodeUrl; + } + + /** + * Getter method for property regionId. + * + * @return property value of regionId + */ + public String getRegionId() { + return regionId; + } + + /** + * Setter method for property regionId. + * + * @param regionId value to be assigned to property regionId + */ + public void setRegionId(String regionId) { + this.regionId = regionId; + } + + /** + * Getter method for property name. + * + * @return property value of name + */ + public String getName() { + return name; + } + + /** + * Setter method for property name. + * + * @param name value to be assigned to property name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Getter method for property nodeStatus. + * + * @return property value of nodeStatus + */ + @Override + public NodeStatus getNodeStatus() { + return nodeStatus; + } + + /** + * Setter method for property nodeStatus. + * + * @param nodeStatus value to be assigned to property nodeStatus + */ + @Override + public void setNodeStatus(NodeStatus nodeStatus) { + this.nodeStatus = nodeStatus; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SessionNode{"); + sb.append("nodeUrl=").append(nodeUrl); + sb.append(", regionId='").append(regionId).append('\''); + sb.append(", name='").append(name).append('\''); + sb.append(", nodeStatus=").append(nodeStatus); + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/StatusConfirmRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/StatusConfirmRequest.java new file mode 100644 index 000000000..4182f1e7a --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/metaserver/StatusConfirmRequest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.metaserver; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeStatus; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: StatusConfirmRequest.java, v 0.1 2018-03-24 17:13 shangyu.wh Exp $ + */ +public class StatusConfirmRequest implements Serializable { + + private T node; + + private NodeStatus nodeStatus; + + /** + * construtor + * @param node + * @param nodeStatus + */ + public StatusConfirmRequest(T node, NodeStatus nodeStatus) { + this.node = node; + this.nodeStatus = nodeStatus; + } + + /** + * Getter method for property node. + * + * @return property value of node + */ + public T getNode() { + return node; + } + + /** + * Setter method for property node. + * + * @param node value to be assigned to property node + */ + public void setNode(T node) { + this.node = node; + } + + /** + * Getter method for property nodeStatus. + * + * @return property value of nodeStatus + */ + public NodeStatus getNodeStatus() { + return nodeStatus; + } + + /** + * Setter method for property nodeStatus. + * + * @param nodeStatus value to be assigned to property nodeStatus + */ + public void setNodeStatus(NodeStatus nodeStatus) { + this.nodeStatus = nodeStatus; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("StatusConfirmRequest{"); + sb.append("node=").append(node); + sb.append(", nodeStatus=").append(nodeStatus); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/CancelAddressRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/CancelAddressRequest.java new file mode 100644 index 000000000..6415ca2ae --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/CancelAddressRequest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.sessionserver; + +import java.io.Serializable; +import java.util.List; + +/** + * The type Cancel address request. + * @author shangyu.wh + * @version $Id : CancelAddressRequest.java, v 0.1 2017-12-22 17:04 shangyu.wh Exp $ + */ +public class CancelAddressRequest implements Serializable { + + private static final long serialVersionUID = -4398310292728124256L; + + private List connectIds; + + public CancelAddressRequest() { + } + + /** + * Constructor. + * + * @param connectIds the connect ids + */ + public CancelAddressRequest(List connectIds) { + this.connectIds = connectIds; + } + + /** + * Getter method for property connectIds. + * + * @return property value of connectIds + */ + public List getConnectIds() { + return connectIds; + } + + public void setConnectIds(List connectIds) { + this.connectIds = connectIds; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("CancelAddressRequest{"); + sb.append("connectIds=").append(connectIds); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataChangeRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataChangeRequest.java new file mode 100644 index 000000000..9f8d194c8 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataChangeRequest.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.sessionserver; + +import com.alipay.sofa.registry.common.model.store.WordCache; + +import java.io.Serializable; + +/** + * request to notify sessionserver when data changed + * + * @author qian.lqlq + * @version $Id: DataChangeRequest.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class DataChangeRequest implements Serializable { + + private static final long serialVersionUID = -7674982522990222894L; + + private String dataInfoId; + + private String dataCenter; + + private long version; + + /** + * constructor + */ + public DataChangeRequest() { + } + + /** + * constructor + * @param dataInfoId + * @param dataCenter + * @param version + */ + public DataChangeRequest(String dataInfoId, String dataCenter, long version) { + this.dataInfoId = dataInfoId; + this.dataCenter = dataCenter; + this.version = version; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = WordCache.getInstance().getWordCache(dataInfoId); + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = WordCache.getInstance().getWordCache(dataCenter); + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(long version) { + this.version = version; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DataChangeRequest{"); + sb.append("dataInfoId='").append(dataInfoId).append('\''); + sb.append(", dataCenter='").append(dataCenter).append('\''); + sb.append(", version=").append(version); + sb.append('}'); + return sb.toString(); + } + +} diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataPushRequest.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataPushRequest.java new file mode 100644 index 000000000..5eb1178d4 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/sessionserver/DataPushRequest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.sessionserver; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: DataPushRequest.java, v 0.1 2018-08-29 18:11 shangyu.wh Exp $ + */ +public class DataPushRequest implements Serializable { + + private Datum datum; + + /** + * constructor + * @param datum + */ + public DataPushRequest(Datum datum) { + this.datum = datum; + } + + /** + * Getter method for property datum. + * + * @return property value of datum + */ + public Datum getDatum() { + return datum; + } + + /** + * Setter method for property datum. + * + * @param datum value to be assigned to property datum + */ + public void setDatum(Datum datum) { + this.datum = datum; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DataPushRequest{"); + sb.append("dataInfoId=").append(datum.getDataInfoId()); + sb.append(", dataCenter=").append(datum.getDataCenter()); + sb.append(", version=").append(datum.getVersion()); + if (datum.getPubMap() != null) { + sb.append(", pubsize=").append(datum.getPubMap().size()); + } + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/BaseInfo.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/BaseInfo.java new file mode 100644 index 000000000..7c4983356 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/BaseInfo.java @@ -0,0 +1,388 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: BaseInfo.java, v 0.1 2017-11-30 16:31 shangyu.wh Exp $ + */ +public abstract class BaseInfo implements Serializable, StoreData { + + private static final long serialVersionUID = -6263388188316303789L; + + private String dataInfoId; + + private String dataId; + + private String clientId; + + private String instanceId; + + private String cell; + + private String appName; + + private String processId; + + private String registerId; + + private Long version; + + private URL sourceAddress; + + private ClientVersion clientVersion; + + private String group; + + private long registerTimestamp; + + private long clientRegisterTimestamp; + + private Map attributes = new HashMap<>(); + + /** + * ClientVersion Enum + */ + public enum ClientVersion { + /** */ + ProtocolPackage("1.x"), + /** */ + NProtocolpackage("2.x"), + /** */ + MProtocolpackage("3.x"), + /** */ + StoreData("4.x"); + + private String version; + + /** + * Set version val + * @param version + */ + ClientVersion(String version) { + this.version = version; + } + } + + /** + * Getter method for property cell. + * + * @return property value of cell + */ + public String getCell() { + return cell; + } + + /** + * Setter method for property cell. + * + * @param cell value to be assigned to property cell + */ + public void setCell(String cell) { + this.cell = WordCache.getInstance().getWordCache(cell); + } + + /** + * Getter method for property appName. + * + * @return property value of appName + */ + public String getAppName() { + return appName; + } + + /** + * Setter method for property appName. + * + * @param appName value to be assigned to property appName + */ + public void setAppName(String appName) { + this.appName = WordCache.getInstance().getWordCache(appName); + } + + /** + * Getter method for property processId. + * + * @return property value of processId + */ + public String getProcessId() { + return processId; + } + + /** + * Setter method for property processId. + * + * @param processId value to be assigned to property processId + */ + public void setProcessId(String processId) { + this.processId = processId; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property sourceAddress. + * + * @return property value of sourceAddress + */ + public URL getSourceAddress() { + return sourceAddress; + } + + /** + * Setter method for property sourceAddress. + * + * @param sourceAddress value to be assigned to property sourceAddress + */ + public void setSourceAddress(URL sourceAddress) { + this.sourceAddress = sourceAddress; + } + + /** + * Getter method for property attributes. + * + * @return property value of attributes + */ + public Map getAttributes() { + return attributes; + } + + /** + * Setter method for property attributes. + * + * @param attributes value to be assigned to property attributes + */ + public void setAttributes(Map attributes) { + Map newAttributes = new HashMap<>(); + if (attributes != null && !attributes.isEmpty()) { + attributes.forEach((key, value) -> newAttributes + .put(WordCache.getInstance().getWordCache(key), value)); + } + this.attributes = newAttributes; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = WordCache.getInstance().getWordCache(dataInfoId); + } + + @Override + @JsonIgnore + public String getId() { + return registerId; + } + + /** + * Getter method for property registerId. + * + * @return property value of registerId + */ + public String getRegisterId() { + return registerId; + } + + /** + * Setter method for property registerId. + * + * @param registerId value to be assigned to property registerId + */ + public void setRegisterId(String registerId) { + this.registerId = registerId; + } + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = WordCache.getInstance().getWordCache(dataId); + } + + /** + * Getter method for property clientId. + * + * @return property value of clientId + */ + public String getClientId() { + return clientId; + } + + /** + * Setter method for property clientId. + * + * @param clientId value to be assigned to property clientId + */ + public void setClientId(String clientId) { + this.clientId = WordCache.getInstance().getWordCache(clientId); + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = WordCache.getInstance().getWordCache(instanceId); + } + + /** + * Getter method for property group. + * + * @return property value of group + */ + public String getGroup() { + return group; + } + + /** + * Setter method for property group. + * + * @param group value to be assigned to property group + */ + public void setGroup(String group) { + this.group = WordCache.getInstance().getWordCache(group); + } + + /** + * Getter method for property registerTimestamp. + * + * @return property value of registerTimestamp + */ + public long getRegisterTimestamp() { + return registerTimestamp; + } + + /** + * Setter method for property registerTimestamp. + * + * @param registerTimestamp value to be assigned to property registerTimestamp + */ + public void setRegisterTimestamp(long registerTimestamp) { + this.registerTimestamp = registerTimestamp; + } + + /** + * Getter method for property clientVersion. + * + * @return property value of clientVersion + */ + public ClientVersion getClientVersion() { + return clientVersion; + } + + /** + * Setter method for property clientVersion. + * + * @param clientVersion value to be assigned to property clientVersion + */ + public void setClientVersion(ClientVersion clientVersion) { + this.clientVersion = clientVersion; + } + + public long getClientRegisterTimestamp() { + return clientRegisterTimestamp; + } + + /** + * Setter method for property clientRegisterTimestamp. + * + * @param clientRegisterTimestamp value to be assigned to property clientRegisterTimestamp + */ + public void setClientRegisterTimestamp(long clientRegisterTimestamp) { + this.clientRegisterTimestamp = clientRegisterTimestamp; + } + + protected String getOtherInfo() { + return ""; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(getDataType().toString()); + sb.append("{dataInfoId='").append(dataInfoId).append('\''); + sb.append(", clientId='").append(clientId).append('\''); + sb.append(", cell='").append(cell).append('\''); + sb.append(", appName='").append(appName).append('\''); + sb.append(", processId='").append(processId).append('\''); + sb.append(", registerId='").append(registerId).append('\''); + sb.append(", version=").append(version); + sb.append(", sourceAddress=").append(sourceAddress); + sb.append(", clientVersion=").append(clientVersion); + sb.append(", registerTimestamp=").append(registerTimestamp); + sb.append(", clientRegisterTimestamp=").append(clientRegisterTimestamp); + sb.append(", otherInfo=").append(getOtherInfo()); + sb.append(", attributes=").append(attributes); + sb.append('}'); + return sb.toString(); + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/DataInfo.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/DataInfo.java new file mode 100644 index 000000000..f519b44b0 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/DataInfo.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: DataInfo.java, v 0.1 2017-11-30 16:09 shangyu.wh Exp $ + */ +public class DataInfo implements Serializable { + + private String dataInfoId; + + private String instanceId; + + private String dataId; + + private String dataType; + + /** symbol : */ + public static final String DELIMITER = "#@#"; + + public static final int DATAID_LENTH = 3; + + /** + * @param instanceId + * @param dataId + * @param dataType + */ + public DataInfo(String instanceId, String dataId, String dataType) { + this.instanceId = instanceId; + this.dataId = dataId; + this.dataType = dataType; + this.dataInfoId = toDataInfoId(dataId, instanceId, dataType); + } + + /** + * @param dataId + * @param instanceId + * @param dataType + * @return + */ + public static String toDataInfoId(String dataId, String instanceId, String dataType) { + StringBuilder buf = new StringBuilder(); + if (dataId == null || dataId.isEmpty()) { + throw new IllegalArgumentException("error dataId:" + dataId); + } + buf.append(dataId); + + if (instanceId == null || instanceId.isEmpty()) { + throw new IllegalArgumentException("error instanceId:" + instanceId); + } + buf.append(DELIMITER).append(instanceId); + + if (dataType == null || dataType.isEmpty()) { + throw new IllegalArgumentException("error dataType:" + dataType); + } + buf.append(DELIMITER).append(dataType); + + return buf.toString(); + } + + /** + * + * @param dataInfoId + * @return + */ + public static DataInfo valueOf(String dataInfoId) { + if (dataInfoId == null || dataInfoId.isEmpty()) { + throw new IllegalArgumentException("dataInfoId null"); + } + + String[] str = dataInfoId.split(DELIMITER); + if (str.length != DATAID_LENTH) { + throw new IllegalArgumentException("dataInfoId input error!"); + } + + return new DataInfo(str[1], str[0], str[2]); + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property instanceId. + * + * @return property value of instanceId + */ + public String getInstanceId() { + return instanceId; + } + + /** + * Setter method for property instanceId. + * + * @param instanceId value to be assigned to property instanceId + */ + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + /** + * Getter method for property dataId. + * + * @return property value of dataId + */ + public String getDataId() { + return dataId; + } + + /** + * Setter method for property dataId. + * + * @param dataId value to be assigned to property dataId + */ + public void setDataId(String dataId) { + this.dataId = dataId; + } + + /** + * Getter method for property dataType. + * + * @return property value of dataType + */ + public String getDataType() { + return dataType; + } + + /** + * Setter method for property dataType. + * + * @param dataType value to be assigned to property dataType + */ + public void setDataType(String dataType) { + this.dataType = dataType; + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Publisher.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Publisher.java new file mode 100644 index 000000000..8ecd7566b --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Publisher.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +import com.alipay.sofa.registry.common.model.PublishType; +import com.alipay.sofa.registry.common.model.ServerDataBox; +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: Publisher.java, v 0.1 2017-11-30 16:04 shangyu.wh Exp $ + */ +public class Publisher extends BaseInfo { + + /** UID */ + private static final long serialVersionUID = 5859214992132895021L; + + private List dataList; + + private PublishType publishType = PublishType.NORMAL; + + /** + * Getter method for property dataList. + * + * @return property value of dataList + */ + public List getDataList() { + return dataList; + } + + /** + * Setter method for property dataList. + * + * @param dataList value to be assigned to property dataList + */ + public void setDataList(List dataList) { + this.dataList = dataList; + } + + public PublishType getPublishType() { + return publishType; + } + + /** + * Setter method for property publishType. + * + * @param publishType value to be assigned to property publishType + */ + public void setPublishType(PublishType publishType) { + this.publishType = publishType; + } + + @Override + @JsonIgnore + public DataType getDataType() { + return DataType.PUBLISHER; + } + + @Override + protected String getOtherInfo() { + final StringBuilder sb = new StringBuilder("dataList="); + if (dataList != null) { + sb.append(dataList.size()); + } else { + sb.append("null"); + } + sb.append(",").append("publishType=").append(publishType); + return sb.toString(); + } + + /** + * change publisher word cache + * @param publisher + * @return + */ + public static Publisher processPublisher(Publisher publisher) { + + publisher.setDataInfoId(publisher.getDataInfoId()); + publisher.setInstanceId(publisher.getInstanceId()); + publisher.setGroup(publisher.getGroup()); + publisher.setDataId(publisher.getDataId()); + publisher.setClientId(publisher.getClientId()); + publisher.setCell(publisher.getCell()); + publisher.setProcessId(publisher.getProcessId()); + publisher.setAppName(publisher.getAppName()); + + if (publisher.getSourceAddress() != null) { + publisher.setSourceAddress(new URL(publisher.getSourceAddress().getIpAddress(), + publisher.getSourceAddress().getPort())); + } + + publisher.setAttributes(publisher.getAttributes()); + + return publisher; + } + +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/StoreData.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/StoreData.java new file mode 100644 index 000000000..1ec2d9a66 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/StoreData.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +/** + * + * @author shangyu.wh + * @version $Id: StoreData.java, v 0.1 2017-11-30 19:48 shangyu.wh Exp $ + */ +public interface StoreData { + + /** + * DataType enum + */ + enum DataType { + SUBSCRIBER, PUBLISHER, WATCHER, UNPUBLISHER + } + + /** + * get store dataType + * @return + */ + DataType getDataType(); + + /** + * get store data ID + * @return + */ + ID getId(); +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Subscriber.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Subscriber.java new file mode 100644 index 000000000..2f0b8b78d --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Subscriber.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +import com.alipay.sofa.registry.common.model.ElementType; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: Subscriber.java, v 0.1 2017-11-30 16:03 shangyu.wh Exp $ + */ +public class Subscriber extends BaseInfo { + + /** UID */ + private static final long serialVersionUID = 98433360274932292L; + /** */ + private ScopeEnum scope; + /** */ + private ElementType elementType; + + /** + * all dataCenter push dataInfo version + */ + private Map lastPushVersions = new ConcurrentHashMap<>(); + + /** + * Getter method for property scope. + * + * @return property value of scope + */ + public ScopeEnum getScope() { + return scope; + } + + /** + * Setter method for property scope. + * + * @param scope value to be assigned to property scope + */ + public void setScope(ScopeEnum scope) { + this.scope = scope; + } + + public ElementType getElementType() { + return elementType; + } + + /** + * check version input greater than current version + * @param version + * @return + */ + public boolean checkVersion(String dataCenter, Long version) { + + Long oldVersion = lastPushVersions.get(dataCenter); + if (oldVersion == null) { + return version != null; + } else { + if (version != null) { + return version > oldVersion; + } + return false; + } + } + + /** + * check version input greater or equal to current version + * @param version + * @return + */ + public void checkAndUpdateVersion(String dataCenter, Long version) { + + while (true) { + Long oldVersion = lastPushVersions.putIfAbsent(dataCenter, version); + // Add firstly + if (oldVersion == null) { + break; + } else { + if (version > oldVersion) { + if (lastPushVersions.replace(dataCenter, oldVersion, version)) { + break; + } + } else { + break; + } + } + } + } + + /** + * Setter method for property elementType. + * + * @param elementType value to be assigned to property elementType + */ + public void setElementType(ElementType elementType) { + this.elementType = elementType; + } + + @Override + @JsonIgnore + public DataType getDataType() { + return DataType.SUBSCRIBER; + } + + @Override + protected String getOtherInfo() { + final StringBuilder sb = new StringBuilder("scope="); + sb.append(scope).append(","); + sb.append("elementType=").append(elementType).append(","); + sb.append("lastPushVersion=").append(lastPushVersions); + return sb.toString(); + } + + /** + * Getter method for property lastPushVersions. + * + * @return property value of lastPushVersions + */ + public Map getLastPushVersions() { + return lastPushVersions; + } + + /** + * Setter method for property lastPushVersions . + * + * @param lastPushVersions value to be assigned to property lastPushVersions + */ + public void setLastPushVersions(Map lastPushVersions) { + this.lastPushVersions = lastPushVersions; + } + + /** + * @see Object#toString() + */ + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Subscriber{"); + sb.append("scope=").append(scope); + sb.append(", elementType=").append(elementType); + sb.append(", lastPushVersions=").append(lastPushVersions); + sb.append(", super=").append(super.toString()); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/URL.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/URL.java new file mode 100644 index 000000000..8f68d56e6 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/URL.java @@ -0,0 +1,265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.io.Serializable; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: URL.java, v 0.1 2017-11-20 21:21 shangyu.wh Exp $ + */ +public final class URL implements Serializable { + private static final Logger LOGGER = LoggerFactory.getLogger(URL.class); + + /** symbol : */ + public static final char COLON = ':'; + + public static final byte HESSIAN_2 = 1; + + public static final byte PROTOBUF = 11; + + public static final byte JSON = 2; + + private ProtocolType protocol; + + private String host; + + private String ipAddress; + + private int port; + + private String path; + + private Byte serializerIndex; + + private Map parameters; + + private String addressString; + + /** + * ProtocolType Enum + */ + public enum ProtocolType { + TR, BOLT, HTTP + } + + public URL() { + } + + /** + * constructor + * @param protocol + * @param ipAddress + * @param port + * @param host + * @param path + * @param serializerIndex + * @param parameters + */ + public URL(ProtocolType protocol, String ipAddress, int port, String host, String path, + Byte serializerIndex, Map parameters) { + this.protocol = protocol; + this.host = host; + this.ipAddress = WordCache.getInstance().getWordCache(getIPAddressFromDomain(ipAddress)); + this.port = port; + this.addressString = WordCache.getInstance().getWordCache(buildAddressString()); + this.path = path; + this.serializerIndex = serializerIndex; + this.parameters = parameters; + } + + /** + * constructor + * @param ipAddress + * @param port + */ + public URL(String ipAddress, int port) { + this(null, ipAddress, port, "", "", HESSIAN_2, null); + } + + /** + * constructor + * @param address + */ + public URL(InetSocketAddress address) { + this(null, address.getAddress().getHostAddress(), address.getPort(), "", "", HESSIAN_2, + null); + } + + /** + * constructor + * @param address + * @param serializerIndex + */ + public URL(InetSocketAddress address, Byte serializerIndex) { + this(null, address.getAddress().getHostAddress(), address.getPort(), "", "", + serializerIndex, null); + } + + /** + * constructor + * @param ipAddress + */ + public URL(String ipAddress) { + this(ipAddress, 0); + } + + /** + * url transfer to InetSocketAddress + * @param url + * @return + */ + public static InetSocketAddress toInetSocketAddress(URL url) { + return new InetSocketAddress(url.getIpAddress(), url.getPort()); + } + + /** + * Getter method for property protocol. + * + * @return property value of protocol + */ + public ProtocolType getProtocol() { + return protocol; + } + + /** + * Getter method for property host. + * + * @return property value of host + */ + public String getHost() { + return host; + } + + /** + * Getter method for property ipAddress. + * + * @return property value of ipAddress + */ + public String getIpAddress() { + return ipAddress; + } + + /** + * Getter method for property port. + * + * @return property value of port + */ + public int getPort() { + return port; + } + + /** + * Getter method for property path. + * + * @return property value of path + */ + public String getPath() { + return path; + } + + /** + * Getter method for property parameters. + * + * @return property value of parameters + */ + public Map getParameters() { + return parameters; + } + + /** + * Getter method for property addressString. + * + * @return property value of addressString + */ + public String getAddressString() { + return addressString; + } + + /** + * build address string + * @return + */ + public String buildAddressString() { + StringBuilder sb = new StringBuilder(); + sb.append(ipAddress).append(COLON).append(port); + return sb.toString(); + } + + /** + * Getter method for property serializerIndex. + * + * @return property value of serializerIndex + */ + public Byte getSerializerIndex() { + return serializerIndex; + } + + private String getIPAddressFromDomain(String domain) { + try { + InetAddress a = InetAddress.getByName(domain); + return a.getHostAddress(); + } catch (UnknownHostException e) { + LOGGER.error("Can not resolve " + domain + " really ip."); + } + return domain; + } + + /** + * TODO Other protocol + * @param url + * @return + */ + public static URL valueOf(String url) { + + if (url == null || (url = url.trim()).length() == 0) { + throw new IllegalArgumentException("url == null"); + } + String ipAddress = ""; + String path = ""; + int port = 0; + ProtocolType protocol = null; + Map parameters = null; + + int i = url.indexOf(":"); + if (i >= 0 && i < url.length() - 1) { + port = Integer.parseInt(url.substring(i + 1)); + url = url.substring(0, i); + } + if (url.length() > 0) { + ipAddress = url; + } + + return new URL(protocol, ipAddress, port, "", path, HESSIAN_2, parameters); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("URL{"); + sb.append("address='").append(addressString).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Watcher.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Watcher.java new file mode 100644 index 000000000..6ffa610f9 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/Watcher.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +/** + * + * @author shangyu.wh + * @version $Id: Watcher.java, v 0.1 2018-04-17 18:22 shangyu.wh Exp $ + */ +public class Watcher extends BaseInfo { + + @Override + public DataType getDataType() { + return DataType.WATCHER; + } +} \ No newline at end of file diff --git a/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/WordCache.java b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/WordCache.java new file mode 100644 index 000000000..2734c8ac0 --- /dev/null +++ b/server/common/model/src/main/java/com/alipay/sofa/registry/common/model/store/WordCache.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.common.model.store; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: WordCache.java, v 0.1 2018-11-06 12:01 shangyu.wh Exp $ + */ +public class WordCache { + + private static volatile WordCache instance; + + /** + * get WordCache instance + * @return + */ + public static WordCache getInstance() { + if (instance == null) { + synchronized (WordCache.class) { + if (instance == null) { + instance = new WordCache(); + } + } + } + return instance; + } + + /** + * word cache map + */ + private ConcurrentHashMap map = new ConcurrentHashMap<>(); + + /** + * + * @param s + * @return String + */ + public String getWordCache(String s) { + if (s == null) { + return null; + } + String oldValue = map.putIfAbsent(s, s); + return oldValue == null ? s : oldValue; + } + +} \ No newline at end of file diff --git a/server/common/pom.xml b/server/common/pom.xml new file mode 100644 index 000000000..9027270dc --- /dev/null +++ b/server/common/pom.xml @@ -0,0 +1,25 @@ + + + + com.alipay.sofa + registry-server-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-common + pom + + + ../../ + + + + model + util + + + diff --git a/server/common/util/pom.xml b/server/common/util/pom.xml new file mode 100644 index 000000000..827af0b6e --- /dev/null +++ b/server/common/util/pom.xml @@ -0,0 +1,61 @@ + + + + com.alipay.sofa + registry-common + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-common-util + + + ../../../ + + + + + org.slf4j + slf4j-api + provided + + + com.alipay.sofa.common + sofa-common-tools + + + junit + junit + + + com.google.guava + guava + + + com.alipay.sofa + registry-core + + + io.dropwizard.metrics + metrics-core + + + ch.qos.logback + logback-classic + test + + + ch.qos.logback + logback-core + test + + + io.netty + netty-all + + + + diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/converter/ScopeEnumConverter.java b/server/common/util/src/main/java/com/alipay/sofa/registry/converter/ScopeEnumConverter.java new file mode 100644 index 000000000..8eac5128d --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/converter/ScopeEnumConverter.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.converter; + +import com.alipay.sofa.registry.core.model.ScopeEnum; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ScopeEnumConverter.java, v 0.1 2018-03-01 21:08 zhuoyu.sjw Exp $$ + */ +public class ScopeEnumConverter { + + /** + * scope convert func + * @param name + * @return + */ + public static ScopeEnum convertToScope(String name) { + if (ScopeEnum.contains(name)) { + return ScopeEnum.valueOf(name); + } + return ScopeEnum.zone; + } +} diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/log/Logger.java b/server/common/util/src/main/java/com/alipay/sofa/registry/log/Logger.java new file mode 100644 index 000000000..ab15880c5 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/log/Logger.java @@ -0,0 +1,249 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.log; + +/** + * import slf4j + * + * @author shangyu.wh + * @version $Id: Logger.java, v 0.1 2017-12-22 15:56 shangyu.wh Exp $ + */ +public interface Logger { + + /** + * TRACE level + * + * @return + * + */ + boolean isTraceEnabled(); + + /** + * Log TRACE level + * + * @param msg + */ + void trace(String msg); + + /** + * Log TRACE level + * @param format + * @param arg + */ + void trace(String format, Object arg); + + /** + * Log TRACE level + * @param format + * @param arg1 + * @param arg2 + */ + void trace(String format, Object arg1, Object arg2); + + /** + * Log TRACE level + * @param format + * @param arguments + */ + void trace(String format, Object... arguments); + + /** + * Log TRACE level + * @param msg + * @param t + */ + void trace(String msg, Throwable t); + + /** + * DEBUG level + * + * @return + */ + boolean isDebugEnabled(); + + /** + * Log DEBUG level. + * + * @param msg + */ + void debug(String msg); + + /** + * Log DEBUG level. + * @param format + * @param arg + */ + void debug(String format, Object arg); + + /** + * Log DEBUG level. + * @param format + * @param arg1 + * @param arg2 + */ + void debug(String format, Object arg1, Object arg2); + + /** + * Log DEBUG level. + * @param format + * @param arguments + */ + void debug(String format, Object... arguments); + + /** + * Log DEBUG level. + * @param msg + * @param t + */ + void debug(String msg, Throwable t); + + /** + * INFO level + * + * @return True if this Logger is enabled for the INFO level, + * false otherwise. + */ + boolean isInfoEnabled(); + + /** + * Log INFO level. + * + * @param msg + */ + void info(String msg); + + /** + * Log INFO level. + * @param format + * @param arg + */ + void info(String format, Object arg); + + /** + * Log INFO level. + * @param format + * @param arg1 + * @param arg2 + */ + void info(String format, Object arg1, Object arg2); + + /** + * Log INFO level. + * @param format + * @param arguments + */ + void info(String format, Object... arguments); + + /** + * Log INFO level. + * @param msg + * @param t + */ + void info(String msg, Throwable t); + + /** + * WARN level + * + * @return + */ + boolean isWarnEnabled(); + + /** + * Log WARN level. + * @param msg + */ + void warn(String msg); + + /** + * Log WARN level. + * @param format + * @param arg + */ + void warn(String format, Object arg); + + /** + * Log WARN level. + * @param format + * @param arguments + */ + void warn(String format, Object... arguments); + + /** + * Log WARN level. + * @param format + * @param arg1 + * @param arg2 + */ + void warn(String format, Object arg1, Object arg2); + + /** + * Log WARN level. + * @param msg + * @param t + */ + void warn(String msg, Throwable t); + + /** + * ERROR level + * + * @return + */ + boolean isErrorEnabled(); + + /** + * Log ERROR level. + * + * @param msg the message string to be logged + */ + void error(String msg); + + /** + * Log ERROR level. + * @param format + * @param arg + */ + void error(String format, Object arg); + + /** + * Log ERROR level. + * @param format + * @param arg1 + * @param arg2 + */ + void error(String format, Object arg1, Object arg2); + + /** + * Log ERROR level. + * @param format + * @param arguments + */ + void error(String format, Object... arguments); + + /** + * Log ERROR level. + * @param msg + * @param t + */ + void error(String msg, Throwable t); + + /** + * get actually logger + * @return + */ + Object getLogger(); + +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/log/LoggerFactory.java b/server/common/util/src/main/java/com/alipay/sofa/registry/log/LoggerFactory.java new file mode 100644 index 000000000..f136d7f48 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/log/LoggerFactory.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.log; + +/** + * + * @author shangyu.wh + * @version $Id: LoggerFactory.java, v 0.1 2017-12-22 15:55 shangyu.wh Exp $ + */ +public class LoggerFactory { + + /** + * get logger + * @param name + * @return + */ + public static Logger getLogger(String name) { + return new SLF4JLogger(name); + } + + /** + * get logger + * @param clazz + * @return + */ + public static Logger getLogger(Class clazz) { + return new SLF4JLogger(clazz); + } + + /** + * get logger + * @param name + * @param prefix + * @return + */ + public static Logger getLogger(String name, String prefix) { + return new SLF4JLogger(name, prefix); + } + + /** + * get logger + * @param clazz + * @param prefix + * @return + */ + public static Logger getLogger(Class clazz, String prefix) { + return new SLF4JLogger(clazz, prefix); + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/log/SLF4JLogger.java b/server/common/util/src/main/java/com/alipay/sofa/registry/log/SLF4JLogger.java new file mode 100644 index 000000000..935855fa4 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/log/SLF4JLogger.java @@ -0,0 +1,321 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.log; + +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: SLF4JLogger.java, v 0.1 2017-12-22 16:04 shangyu.wh Exp $ + */ +public class SLF4JLogger implements Logger, Serializable { + + private static final long serialVersionUID = 1L; + + private static final String LOG_PATH = "logging.path"; + private static final String LOG_PATH_DEFAULT = System.getProperty("user.home") + + File.separator + "logs"; + private static final String SERVER_LOG_LEVEL = "com.alipay.sofa.registry.server.log.level"; + private static final String SERVER_LOG_LEVEL_DEFAULT = "INFO"; + + private final String name; + + private final org.slf4j.Logger logger; + + private final String msgPrefix; + + /** symbol : */ + public static final char SPACE = ' '; + + static { + + String logPath = System.getProperty(LOG_PATH); + String logLevel = System.getProperty(SERVER_LOG_LEVEL); + if (logPath == null || logPath.isEmpty()) { + System.setProperty(LOG_PATH, LOG_PATH_DEFAULT); + } + if (logLevel == null || logLevel.isEmpty()) { + System.setProperty(SERVER_LOG_LEVEL, SERVER_LOG_LEVEL_DEFAULT); + } + + } + + /** + * @param name + */ + public SLF4JLogger(String name) { + this.name = name; + this.msgPrefix = ""; + this.logger = getLoggerBySpace(name); + } + + /** + * @param clazz + */ + public SLF4JLogger(Class clazz) { + this.name = clazz.getCanonicalName(); + this.msgPrefix = ""; + this.logger = getLoggerBySpace(name); + } + + /** + * @param name + * @param msgPrefix + */ + public SLF4JLogger(String name, String msgPrefix) { + this.name = name; + this.msgPrefix = msgPrefix; + this.logger = getLoggerBySpace(name); + } + + /** + * @param clazz + * @param msgPrefix + */ + public SLF4JLogger(Class clazz, String msgPrefix) { + this.name = clazz.getCanonicalName(); + this.msgPrefix = msgPrefix; + this.logger = getLoggerBySpace(name); + } + + /** + * @param name + * @return + */ + public org.slf4j.Logger getLoggerBySpace(String name) { + if (name == null || name.isEmpty()) { + return null; + } + return LoggerFactory.getLogger(name); + } + + @Override + public void trace(String msg) { + if (logger.isTraceEnabled()) { + logger.trace(processMsg(msg)); + } + } + + @Override + public void trace(String format, Object arg) { + if (logger.isTraceEnabled()) { + logger.trace(processMsg(format), arg); + } + } + + @Override + public void trace(String format, Object arg1, Object arg2) { + if (logger.isTraceEnabled()) { + logger.trace(processMsg(format), arg1, arg2); + } + } + + @Override + public void trace(String format, Object... arguments) { + if (logger.isTraceEnabled()) { + logger.trace(processMsg(format), arguments); + } + } + + @Override + public void trace(String msg, Throwable e) { + if (logger.isTraceEnabled()) { + logger.trace(processMsg(msg), e); + } + } + + @Override + public void debug(String msg) { + if (logger.isDebugEnabled()) { + logger.debug(processMsg(msg)); + } + } + + @Override + public void debug(String format, Object arg) { + if (logger.isDebugEnabled()) { + logger.debug(processMsg(format), arg); + } + } + + @Override + public void debug(String format, Object arg1, Object arg2) { + if (logger.isDebugEnabled()) { + logger.debug(processMsg(format), arg1, arg2); + } + } + + @Override + public void debug(String format, Object... arguments) { + if (logger.isDebugEnabled()) { + logger.debug(processMsg(format), arguments); + } + } + + @Override + public void debug(String msg, Throwable e) { + if (logger.isDebugEnabled()) { + logger.debug(processMsg(msg), e); + } + } + + @Override + public void info(String msg) { + if (logger.isInfoEnabled()) { + logger.info(processMsg(msg)); + } + } + + @Override + public void info(String format, Object arg) { + if (logger.isInfoEnabled()) { + logger.info(processMsg(format), arg); + } + } + + @Override + public void info(String format, Object arg1, Object arg2) { + if (logger.isInfoEnabled()) { + logger.info(processMsg(format), arg1, arg2); + } + } + + @Override + public void info(String format, Object... arguments) { + if (logger.isInfoEnabled()) { + logger.info(processMsg(format), arguments); + } + } + + @Override + public void info(String msg, Throwable e) { + if (logger.isInfoEnabled()) { + logger.info(processMsg(msg), e); + } + } + + @Override + public void warn(String msg) { + if (logger.isWarnEnabled()) { + logger.warn(processMsg(msg)); + } + } + + @Override + public void warn(String format, Object arg) { + if (logger.isWarnEnabled()) { + logger.warn(processMsg(format), arg); + } + } + + @Override + public void warn(String format, Object... arguments) { + if (logger.isWarnEnabled()) { + logger.warn(processMsg(format), arguments); + } + } + + @Override + public void warn(String format, Object arg1, Object arg2) { + if (logger.isWarnEnabled()) { + logger.warn(processMsg(format), arg1, arg2); + } + } + + @Override + public void warn(String msg, Throwable e) { + if (logger.isWarnEnabled()) { + logger.warn(processMsg(msg), e); + } + } + + @Override + public void error(String msg) { + if (logger.isErrorEnabled()) { + logger.error(processMsg(msg)); + } + } + + @Override + public void error(String format, Object arg) { + if (logger.isErrorEnabled()) { + logger.error(processMsg(format), arg); + } + } + + @Override + public void error(String format, Object arg1, Object arg2) { + if (logger.isErrorEnabled()) { + logger.error(processMsg(format), arg1, arg2); + } + } + + @Override + public void error(String format, Object... arguments) { + if (logger.isErrorEnabled()) { + logger.error(processMsg(format), arguments); + } + } + + @Override + public void error(String msg, Throwable e) { + if (logger.isErrorEnabled()) { + logger.error(processMsg(msg), e); + } + } + + @Override + public boolean isTraceEnabled() { + return logger.isTraceEnabled(); + } + + @Override + public boolean isDebugEnabled() { + return logger.isDebugEnabled(); + } + + @Override + public boolean isInfoEnabled() { + return logger.isInfoEnabled(); + } + + @Override + public boolean isWarnEnabled() { + return logger.isWarnEnabled(); + } + + @Override + public boolean isErrorEnabled() { + return logger.isErrorEnabled(); + } + + private String processMsg(String msg) { + if (msgPrefix.isEmpty()) { + return msg; + } + return msgPrefix + SPACE + msg; + } + + @Override + public Object getLogger() { + return logger; + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/metrics/ReporterUtils.java b/server/common/util/src/main/java/com/alipay/sofa/registry/metrics/ReporterUtils.java new file mode 100644 index 000000000..fb5f24e36 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/metrics/ReporterUtils.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.metrics; + +import com.alipay.sofa.registry.log.Logger; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Slf4jReporter; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ReporterUtils.java, v 0.1 2018-08-23 13:25 shangyu.wh Exp $ + */ +public class ReporterUtils { + + /** + * start slf4j reporter + * @param period + * @param registry + * @param loggerMetrics + */ + public static void startSlf4jReporter(long period, MetricRegistry registry, Logger loggerMetrics) { + Slf4jReporter reporter = Slf4jReporter.forRegistry(registry) + .outputTo((org.slf4j.Logger) loggerMetrics.getLogger()) + .convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build(); + if (period > 0) { + reporter.start(period, TimeUnit.SECONDS); + } else { + reporter.start(30, TimeUnit.SECONDS); + } + + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/metrics/TaskMetrics.java b/server/common/util/src/main/java/com/alipay/sofa/registry/metrics/TaskMetrics.java new file mode 100644 index 000000000..ae0ec816c --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/metrics/TaskMetrics.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.metrics; + +import com.codahale.metrics.Gauge; +import com.codahale.metrics.MetricRegistry; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * + * @author shangyu.wh + * @version $Id: ThreadMetrics.java, v 0.1 2018-11-18 15:19 shangyu.wh Exp $ + */ +public class TaskMetrics { + + private final MetricRegistry metrics; + + private TaskMetrics() { + this.metrics = new MetricRegistry(); + } + + private volatile static TaskMetrics instance; + + public static TaskMetrics getInstance() { + if (instance == null) { + synchronized (TaskMetrics.class) { + if (instance == null) { + instance = new TaskMetrics(); + } + } + } + + return instance; + } + + public MetricRegistry getMetricRegistry() { + return this.metrics; + } + + public void registerThreadExecutor(String executorName, ThreadPoolExecutor executor) { + + metrics.register(MetricRegistry.name(executorName, "queue"), + (Gauge) () -> executor.getQueue().size()); + + metrics.register(MetricRegistry.name(executorName, "current"), + (Gauge) executor::getPoolSize); + + metrics.register(MetricRegistry.name(executorName, "active"), + (Gauge) executor::getActiveCount); + + metrics.register(MetricRegistry.name(executorName, "completed"), + (Gauge) executor::getCompletedTaskCount); + + metrics.register(MetricRegistry.name(executorName, "task"), + (Gauge) executor::getTaskCount); + + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/net/NetUtil.java b/server/common/util/src/main/java/com/alipay/sofa/registry/net/NetUtil.java new file mode 100644 index 000000000..654f39305 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/net/NetUtil.java @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.net; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.regex.Pattern; + +/** + * The type Net util. + * @author shangyu.wh + * @version $Id : NetUtil.java, v 0.1 2017-11-22 12:13 shangyu.wh Exp $ + */ +public class NetUtil { + + private static final Logger LOGGER = LoggerFactory + .getLogger(NetUtil.class); + + /** + * The constant LOCALHOST. + */ + public static final String LOCALHOST = "127.0.0.1"; + + /** + * The constant ANYHOST. + */ + public static final String ANYHOST = "0.0.0.0"; + + /** symbol : */ + public static final char COLON = ':'; + + private static volatile InetAddress LOCAL_ADDRESS = null; + + private static final Pattern IP_PATTERN = Pattern + .compile("\\d{1,3}(\\.\\d{1,3}){3,5}$"); + + public static final String NETWORK_INTERFACE_IN = "network_interface_binding"; + + /** + * Gen host string. + * + * @param ip the ip + * @param port the port + * @return the string + */ + public static String genHost(String ip, int port) { + return ip + COLON + port; + } + + /** + * Gets local socket address. + * + * @return the local socket address + */ + public static InetSocketAddress getLocalSocketAddress() { + InetAddress address = getLocalAddress(); + String addressStr = address == null ? LOCALHOST : address.getHostAddress(); + return new InetSocketAddress(addressStr, 0); + } + + /** + * Gets ip address from domain. + * + * @param domain the domain + * @return the ip address from domain + */ + public static String getIPAddressFromDomain(String domain) { + try { + InetAddress a = InetAddress.getByName(domain); + if (LOCALHOST.equalsIgnoreCase(a.getHostAddress())) { + a = getLocalAddress(); + } + return a.getHostAddress(); + } catch (UnknownHostException e) { + throw new RuntimeException("Unknown host {" + domain + "}"); + } + } + + /** + * + * @param ip + * @return String + */ + public static String getDomainFromIP(String ip) { + try { + InetAddress a = InetAddress.getByName(ip); + return a.getCanonicalHostName(); + } catch (UnknownHostException e) { + LOGGER.error("[NetWorkUtils] Can not resolve ip " + ip + ". error is .", e); + } + return null; + } + + /** + * Gets local address. + * + * @return loccal IP all network card + */ + public static InetAddress getLocalAddress() { + if (LOCAL_ADDRESS != null) { + return LOCAL_ADDRESS; + } + InetAddress localAddress = getLocalAddress0(); + LOCAL_ADDRESS = localAddress; + return localAddress; + } + + /** + * To address string string. + * + * @param address the address + * @return the string + */ + public static String toAddressString(InetSocketAddress address) { + if (address == null || address.getAddress() == null) { + LOGGER + .error("InetSocketAddress to Address String error!In put inetSocketAddress or InetSocketAddress.getAddress is null"); + throw new RuntimeException( + "InetSocketAddress to Address String error!In put inetSocketAddress or InetSocketAddress.getAddress is null!"); + } + return address.getAddress().getHostAddress() + COLON + address.getPort(); + } + + private static boolean isValidAddress(InetAddress address) { + if (address == null || address.isLoopbackAddress()) { + return false; + } + String name = address.getHostAddress(); + return (name != null && !ANYHOST.equals(name) && !LOCALHOST.equals(name) && IP_PATTERN + .matcher(name).matches()); + } + + private static InetAddress getLocalAddress0() { + InetAddress localAddress = null; + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + if (interfaces != null) { + while (interfaces.hasMoreElements()) { + try { + NetworkInterface network = interfaces.nextElement(); + boolean useNi; + String rpcNi = System.getProperty(NETWORK_INTERFACE_IN); + if (rpcNi != null && !rpcNi.isEmpty()) { + if (rpcNi.equals(network.getDisplayName()) + || rpcNi.equals(network.getName())) { + useNi = true; + } else { + continue; + } + } else { + useNi = true; + } + + Enumeration addresses = network.getInetAddresses(); + if (addresses != null) { + while (addresses.hasMoreElements()) { + try { + InetAddress address = addresses.nextElement(); + if (useNi && isValidAddress(address)) { + return address; + } + } catch (Throwable e) { + LOGGER.warn( + "Failed to retriving ip address, " + e.getMessage(), e); + } + } + } + } catch (Throwable e) { + LOGGER.warn("Failed to retriving ip address, " + e.getMessage(), e); + } + } + } + } catch (Throwable e) { + LOGGER.warn("Failed to retriving ip address, " + e.getMessage(), e); + } + LOGGER.error("Could not get local host ip address, will use 127.0.0.1 instead."); + return localAddress; + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/Retryable.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/Retryable.java new file mode 100644 index 000000000..7aafd2579 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/Retryable.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task; + +/** + * + * @author shangyu.wh + * @version $Id: Retryable.java, v 0.1 2018-02-07 11:31 shangyu.wh Exp $ + */ +public interface Retryable { + + /** + * + * @return + */ + boolean checkRetryTimes(); +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/Task.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/Task.java new file mode 100644 index 000000000..6621f82f4 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/Task.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task; + +import com.alipay.sofa.registry.task.listener.TaskEvent; + +/** + * + * @author shangyu.wh + * @version $Id: Task.java, v 0.1 2018-01-15 14:23 shangyu.wh Exp $ + */ +public interface Task { + + /** + * + * @return + */ + long getExpiryTime(); + + /** + * + * @return + */ + String getTaskId(); + + /** + * + * @param taskEvent + */ + void setTaskEvent(TaskEvent taskEvent); + + /** + * + * @throws Throwable + */ + void execute() throws Throwable; +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/TaskClosure.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/TaskClosure.java new file mode 100644 index 000000000..4e3668571 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/TaskClosure.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task; + +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; + +/** + * + * @author shangyu.wh + * @version $Id: TaskClosture.java, v 0.1 2018-06-04 17:08 shangyu.wh Exp $ + */ +public interface TaskClosure { + + /** + * + * @param processingResult + * @param task + */ + void run(ProcessingResult processingResult, Task task); +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/AcceptorExecutor.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/AcceptorExecutor.java new file mode 100644 index 000000000..c0a26d410 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/AcceptorExecutor.java @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; + +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingDeque; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +/** + * An active object with an internal thread accepting tasks from clients, and dispatching them to + * workers in a pull based manner. Workers explicitly request an item or a batch of items whenever they are + * available. This guarantees that data to be processed are always up to date, and no stale data processing is done. + * + *

Task identification

+ * Each task passed for processing has a corresponding task id. This id is used to remove duplicates (replace + * older copies with newer ones). + * + *

Re-processing

+ * If data processing by a worker failed, and the failure is transient in nature, the worker will put back the + * task(s) back to the {@link AcceptorExecutor}. This data will be merged with current workload, possibly discarded if + * a newer version has been already received. + * + * @author Tomasz Bak + + * @author shangyu.wh modify + * @version $Id: AcceptorExecutor.java, v 0.1 2017-11-14 15:35 shangyu.wh Exp $ + */ +public class AcceptorExecutor { + + private static final Logger LOGGER = LoggerFactory + .getLogger(AcceptorExecutor.class); + + /** + * Get the maximum number of task that can be allowed to back up in the task pool + * Default 10000 + */ + private final int maxBufferSize; + + private final String name; + + private final AtomicBoolean isShutdown = new AtomicBoolean( + false); + + private final BlockingQueue> acceptorQueue = new LinkedBlockingQueue<>(); + private final BlockingDeque> reprocessQueue = new LinkedBlockingDeque<>(); + private final Thread acceptorThread; + + private final Map> pendingTasks = new HashMap<>(); + private final Deque processingOrder = new LinkedList<>(); + + private final Semaphore workSemaphore = new Semaphore(0); + private final BlockingQueue> itemWorkQueue = new LinkedBlockingQueue<>(); + + private final Semaphore batchWorkRequests = new Semaphore(0); + private final BlockingQueue>> batchWorkQueue = new LinkedBlockingQueue<>(); + + private final TrafficShaper trafficShaper; + + private AtomicLong acceptedTasks = new AtomicLong(); + + private AtomicLong replayedTasks = new AtomicLong(); + + private AtomicLong expiredTasks = new AtomicLong(); + + private AtomicLong overriddenTasks = new AtomicLong(); + + private AtomicLong queueOverflows = new AtomicLong(); + + AcceptorExecutor(String id, int maxBufferSize, long congestionRetryDelayMs, + long networkFailureRetryMs) { + this.name = "TaskAcceptor-" + id; + this.maxBufferSize = maxBufferSize; + this.trafficShaper = new TrafficShaper(congestionRetryDelayMs, networkFailureRetryMs); + + ThreadGroup threadGroup = new ThreadGroup("serverTaskExecutors"); + this.acceptorThread = new Thread(threadGroup, new AcceptorRunner(), "TaskAcceptor-" + id); + this.acceptorThread.setDaemon(true); + this.acceptorThread.start(); + + } + + void process(ID id, T task, long expiryTime) { + acceptorQueue.add(new TaskHolder<>(id, task, expiryTime)); + acceptedTasks.incrementAndGet(); + } + + void reprocess(TaskHolder taskHolder, ProcessingResult processingResult) { + reprocessQueue.add(taskHolder); + replayedTasks.incrementAndGet(); + trafficShaper.registerFailure(processingResult); + } + + BlockingQueue> requestWorkItem() { + workSemaphore.release(); + return itemWorkQueue; + } + + BlockingQueue>> requestWorkItems() { + batchWorkRequests.release(); + return batchWorkQueue; + } + + void shutdown() { + if (isShutdown.compareAndSet(false, true)) { + acceptorThread.interrupt(); + } + } + + class AcceptorRunner implements Runnable { + @Override + public void run() { + long scheduleTime = 0; + while (!isShutdown.get()) { + try { + drainInputQueues(); + + int totalItems = processingOrder.size(); + + long now = System.currentTimeMillis(); + if (scheduleTime < now) { + scheduleTime = now + trafficShaper.transmissionDelay(); + } + if (scheduleTime <= now) { + assignItemWork(); + } + + if (totalItems == processingOrder.size()) { + Thread.sleep(10); + } + } catch (InterruptedException ex) { + // Ignore + } catch (Throwable e) { + LOGGER.warn("AcceptorThread error", e); + } + } + } + + private boolean isFull() { + return pendingTasks.size() >= maxBufferSize; + } + + private void drainInputQueues() throws InterruptedException { + do { + drainReprocessQueue(); + drainAcceptorQueue(); + + if (!isShutdown.get()) { + // If all queues are empty, block for a while on the acceptor queue + if (reprocessQueue.isEmpty() && acceptorQueue.isEmpty() + && pendingTasks.isEmpty()) { + TaskHolder taskHolder = acceptorQueue + .poll(10, TimeUnit.MILLISECONDS); + if (taskHolder != null) { + appendTaskHolder(taskHolder); + } + } + } + } while (!reprocessQueue.isEmpty() || !acceptorQueue.isEmpty() + || pendingTasks.isEmpty()); + } + + private void drainAcceptorQueue() { + while (!acceptorQueue.isEmpty()) { + appendTaskHolder(acceptorQueue.poll()); + } + } + + private void drainReprocessQueue() { + long now = System.currentTimeMillis(); + while (!reprocessQueue.isEmpty() && !isFull()) { + TaskHolder taskHolder = reprocessQueue.pollLast(); + ID id = taskHolder.getId(); + //expiryTime < 0 means task no expired + if (taskHolder.getExpiryTime() > 0 && taskHolder.getExpiryTime() <= now) { + expiredTasks.incrementAndGet(); + } else if (pendingTasks.containsKey(id)) { + overriddenTasks.incrementAndGet(); + } else { + pendingTasks.put(id, taskHolder); + processingOrder.addFirst(id); + } + } + if (isFull()) { + LOGGER + .error( + "Now pending task full,it will clear reprocessQueue in to add new task,reprocessQueue size={},queueOverflows={},name={}", + reprocessQueue.size(), queueOverflows, name); + queueOverflows.addAndGet(reprocessQueue.size()); + reprocessQueue.clear(); + } + } + + private void appendTaskHolder(TaskHolder taskHolder) { + if (isFull()) { + LOGGER + .error( + "Now pending task full,it will remove first one to add task={},queueOverflows={},name={}", + taskHolder.getId(), queueOverflows, name); + pendingTasks.remove(processingOrder.poll()); + queueOverflows.incrementAndGet(); + } + TaskHolder previousTask = pendingTasks.put(taskHolder.getId(), taskHolder); + if (previousTask == null) { + processingOrder.add(taskHolder.getId()); + } else { + overriddenTasks.incrementAndGet(); + } + } + + void assignItemWork() { + if (!processingOrder.isEmpty()) { + if (workSemaphore.tryAcquire(1)) { + long now = System.currentTimeMillis(); + while (!processingOrder.isEmpty()) { + ID id = processingOrder.poll(); + TaskHolder holder = pendingTasks.remove(id); + //expiryTime < 0 means task no expired + if (holder.getExpiryTime() < 0 || holder.getExpiryTime() > now) { + itemWorkQueue.add(holder); + return; + } + expiredTasks.incrementAndGet(); + } + workSemaphore.release(); + } + } + } + + } + + /** + * Getter method for property maxBufferSize. + * + * @return property value of maxBufferSize + */ + public int getMaxBufferSize() { + return maxBufferSize; + } + + /** + * Getter method for property acceptedTasks. + * + * @return property value of acceptedTasks + */ + public AtomicLong getAcceptedTasks() { + return acceptedTasks; + } + + /** + * Getter method for property replayedTasks. + * + * @return property value of replayedTasks + */ + public AtomicLong getReplayedTasks() { + return replayedTasks; + } + + /** + * Getter method for property expiredTasks. + * + * @return property value of expiredTasks + */ + public AtomicLong getExpiredTasks() { + return expiredTasks; + } + + /** + * Getter method for property overriddenTasks. + * + * @return property value of overriddenTasks + */ + public AtomicLong getOverriddenTasks() { + return overriddenTasks; + } + + /** + * Getter method for property queueOverflows. + * + * @return property value of queueOverflows + */ + public AtomicLong getQueueOverflows() { + return queueOverflows; + } + + /** + * Get pending task size + * @return + */ + public int getPendingTaskSize() { + return pendingTasks.size(); + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatcher.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatcher.java new file mode 100644 index 000000000..3620065ec --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatcher.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +/** + * Task dispatcher takes task from clients, and delegates their execution to a configurable number of workers. + * The task can be processed one at a time or in batches. Only non-expired tasks are executed, and if a newer + * task with the same id is scheduled for execution, the old one is deleted. Lazy dispatch of work (only on demand) + * to workers, guarantees that data are always up to date, and no stale task processing takes place. + *

Task processor

+ * A client of this component must provide an implementation of {@link TaskProcessor} interface, which will do + * the actual work of task processing. This implementation must be thread safe, as it is called concurrently by + * multiple threads. + * + * @author Tomasz Bak + * + * @author shangyu.wh modify + * @version $Id: TaskDispatcher.java, v 0.1 2017-11-14 15:23 shangyu.wh Exp $ + */ +public interface TaskDispatcher { + + /** + * + * @param id + * @param task + * @param expiryTime + */ + void dispatch(ID id, T task, long expiryTime); + + /** + * + */ + void shutdown(); + + AcceptorExecutor getAcceptorExecutor(); +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatchers.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatchers.java new file mode 100644 index 000000000..c7a2d32e6 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskDispatchers.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * See {@link TaskDispatcher} for an overview. + * + * @author Tomasz Bak + * + * @author shangyu.wh modify + * @version $Id: TaskDispatchers.java, v 0.1 2017-11-14 16:11 shangyu.wh Exp $ + */ +public class TaskDispatchers { + + private static Map taskDispatcherMap = new ConcurrentHashMap<>(); + + private static final String TASK_DISPATCHER_END = "Dispatcher"; + + /** + * @param id + * @param taskProcessor + * @param + * @param + * @return + */ + public static TaskDispatcher createDefaultSingleTaskDispatcher(String id, + TaskProcessor taskProcessor) { + final String name = getDispatcherName(id); + + TaskDispatcher taskDispatcher = taskDispatcherMap.computeIfAbsent(name, + k->{ + + final AcceptorExecutor acceptorExecutor = new AcceptorExecutor( + name, 1000, 1000, 100 + ); + final TaskExecutors taskExecutor = TaskExecutors.createTaskExecutors(name, 20, taskProcessor, + acceptorExecutor); + + return new TaskDispatcher() { + @Override + public void dispatch(ID id, T task, long expiryTime) { + acceptorExecutor.process(id, task, expiryTime); + } + + @Override + public void shutdown() { + acceptorExecutor.shutdown(); + taskExecutor.shutdown(); + } + + @Override + public AcceptorExecutor getAcceptorExecutor() { + return acceptorExecutor; + } + }; + }); + return taskDispatcher; + } + + /** + * + */ + public static void stopDefaultSingleTaskDispatcher() { + taskDispatcherMap.forEach((k, v) -> { + if (v != null) { + v.shutdown(); + } + }); + } + + /** + * @param id + * @param maxBufferSize + * @param workerCount + * @param congestionRetryDelayMs + * @param networkFailureRetryMs + * @param taskProcessor + * @param + * @param + * @return + */ + public static TaskDispatcher createSingleTaskDispatcher(String id, + int maxBufferSize, + int workerCount, + long congestionRetryDelayMs, + long networkFailureRetryMs, + TaskProcessor taskProcessor) { + + return taskDispatcherMap.computeIfAbsent(id,k->{ + + final AcceptorExecutor acceptorExecutor = new AcceptorExecutor( + id, maxBufferSize, congestionRetryDelayMs, networkFailureRetryMs + ); + final TaskExecutors taskExecutor = TaskExecutors.createTaskExecutors(id, workerCount, taskProcessor, + acceptorExecutor); + + return new TaskDispatcher() { + @Override + public void dispatch(ID id, T task, long expiryTime) { + acceptorExecutor.process(id, task, expiryTime); + } + + @Override + public void shutdown() { + acceptorExecutor.shutdown(); + taskExecutor.shutdown(); + } + + @Override + public AcceptorExecutor getAcceptorExecutor() { + return acceptorExecutor; + } + }; + }); + + } + + public static String getDispatcherName(String name) { + return name + TASK_DISPATCHER_END; + } + + /** + * Getter method for property taskDispatcherMap. + * + * @return property value of taskDispatcherMap + */ + public static Map getTaskDispatcherMap() { + return taskDispatcherMap; + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskExecutors.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskExecutors.java new file mode 100644 index 000000000..b9176318e --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskExecutors.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +/** + * {@link TaskExecutors} instance holds a number of worker threads that cooperate with {@link AcceptorExecutor}. + * Each worker sends a job request to {@link AcceptorExecutor} whenever it is available, and processes it once + * provided with a task(s). + * + * @author Tomasz Bak + * + * @author shangyu.wh modify + * @version $Id: TaskExecutors.java, v 0.1 2017-11-14 16:00 shangyu.wh Exp $ + */ +public class TaskExecutors { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskExecutors.class); + + private final AtomicBoolean isShutdown; + private final List workerThreads; + + /** + * constructor + * @param workerRunnableFactory + * @param workerCount + * @param isShutdown + */ + TaskExecutors(Function> workerRunnableFactory, int workerCount, + AtomicBoolean isShutdown) { + this.isShutdown = isShutdown; + this.workerThreads = new ArrayList<>(); + + ThreadGroup threadGroup = new ThreadGroup("serverTaskExecutors"); + for (int i = 0; i < workerCount; i++) { + WorkerRunnable runnable = workerRunnableFactory.apply(i); + Thread workerThread = new Thread(threadGroup, runnable, runnable.getWorkerName()); + workerThreads.add(workerThread); + workerThread.setDaemon(true); + workerThread.start(); + } + } + + /** + * + * @param name + * @param workerCount + * @param processor + * @param acceptorExecutor + * @param + * @param + * @return + */ + static TaskExecutors createTaskExecutors(final String name, + int workerCount, + final TaskProcessor processor, + final AcceptorExecutor acceptorExecutor) { + final AtomicBoolean isShutdown = new AtomicBoolean(); + return new TaskExecutors<>(idx -> new WorkerRunnable<>(name + '-' + idx, isShutdown, + processor, + acceptorExecutor), workerCount, isShutdown); + } + + /** + * shutdown workerThread + */ + void shutdown() { + if (isShutdown.compareAndSet(false, true)) { + for (Thread workerThread : workerThreads) { + workerThread.interrupt(); + } + } + } + + /** + * + * @param + * @param + */ + static class WorkerRunnable implements Runnable { + + final String workerName; + final AtomicBoolean isShutdown; + final TaskProcessor processor; + final AcceptorExecutor acceptorExecutor; + + WorkerRunnable(String workerName, AtomicBoolean isShutdown, TaskProcessor processor, + AcceptorExecutor acceptorExecutor) { + this.workerName = workerName; + this.isShutdown = isShutdown; + this.processor = processor; + this.acceptorExecutor = acceptorExecutor; + } + + String getWorkerName() { + return workerName; + } + + @Override + public void run() { + try { + while (!isShutdown.get()) { + try { + BlockingQueue> workQueue = acceptorExecutor + .requestWorkItem(); + TaskHolder taskHolder; + while ((taskHolder = workQueue.poll(1, TimeUnit.SECONDS)) == null) { + if (isShutdown.get()) { + return; + } + } + ProcessingResult result = processor.process(taskHolder.getTask()); + switch (result) { + case Success: + break; + case Congestion: + acceptorExecutor.reprocess(taskHolder, result); + break; + case TransientError: + acceptorExecutor.reprocess(taskHolder, result); + break; + case PermanentError: + LOGGER.warn("Discarding a task of {} due to permanent error", + workerName); + break; + default: + break; + } + } catch (InterruptedException e) { + // Ignore + } catch (Throwable e) { + LOGGER.error("Single WorkerThread process error", e); + } + } + } catch (Throwable e) { + LOGGER.error("WorkerThread error", e); + } + } + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskHolder.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskHolder.java new file mode 100644 index 000000000..304395eb1 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskHolder.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +/** + * @author Tomasz Bak + * + * @author shangyu.wh modify + * @version $Id: TaskHolder.java, v 0.1 2017-11-14 14:57 shangyu.wh Exp $ + */ +public class TaskHolder { + + private final ID id; + private final T task; + private final long expiryTime; + private final long submitTimestamp; + + /** + * constructor + * @param id + * @param task + * @param expiryTime + */ + TaskHolder(ID id, T task, long expiryTime) { + this.id = id; + this.expiryTime = expiryTime; + this.task = task; + this.submitTimestamp = System.currentTimeMillis(); + } + + /** + * Getter method for property id. + * + * @return property value of id + */ + public ID getId() { + return id; + } + + /** + * Getter method for property task. + * + * @return property value of task + */ + public T getTask() { + return task; + } + + /** + * Getter method for property expiryTime. + * + * @return property value of expiryTime + */ + public long getExpiryTime() { + return expiryTime; + } + + /** + * Getter method for property submitTimestamp. + * + * @return property value of submitTimestamp + */ + public long getSubmitTimestamp() { + return submitTimestamp; + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskProcessor.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskProcessor.java new file mode 100644 index 000000000..886f627bf --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TaskProcessor.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +import java.util.List; + +/** + * An interface to be implemented by clients for task execution. + * + * @author Tomasz Bak + * + * @author shangyu.wh modify + * @version $Id: TaskProcessor.java, v 0.1 2017-11-14 15:27 shangyu.wh Exp $ + */ +public interface TaskProcessor { + + /** + * A processed task/task list ends up in one of the following states: + *
    + *
  • {@code Success} processing finished successfully
  • + *
  • {@code TransientError} processing failed, but shall be retried later
  • + *
  • {@code PermanentError} processing failed, and is non recoverable
  • + *
+ */ + enum ProcessingResult { + Success, Congestion, TransientError, PermanentError + } + + /** + * In non-batched mode a single task is processed at a time. + */ + ProcessingResult process(T task); + + /** + * For batched mode a collection of tasks is run at a time. The result is provided for the aggregated result, + * and all tasks are handled in the same way according to what is returned (for example are rescheduled, if the + * error is transient). + */ + ProcessingResult process(List tasks); +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TrafficShaper.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TrafficShaper.java new file mode 100644 index 000000000..2a492654d --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/batcher/TrafficShaper.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.batcher; + +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; + +/** + * {@link TrafficShaper} provides admission control policy prior to dispatching tasks to workers. + * It reacts to events coming via reprocess requests (transient failures, congestion), and delays the processing + * depending on this feedback. + * + * @author Tomasz Bak + * + * @author shangyu.wh modify + * @version $Id: TrafficShaper.java, v 0.1 2017-11-14 15:37 shangyu.wh Exp $ + */ +public class TrafficShaper { + + private static final long MAX_DELAY = 30 * 1000; + + private final long congestionRetryDelayMs; + private final long networkFailureRetryMs; + + private volatile long lastCongestionError; + private volatile long lastNetworkFailure; + + /** + * + * @param congestionRetryDelayMs + * @param networkFailureRetryMs + */ + TrafficShaper(long congestionRetryDelayMs, long networkFailureRetryMs) { + this.congestionRetryDelayMs = Math.min(MAX_DELAY, congestionRetryDelayMs); + this.networkFailureRetryMs = Math.min(MAX_DELAY, networkFailureRetryMs); + } + + /** + * + * @param processingResult + */ + void registerFailure(ProcessingResult processingResult) { + if (processingResult == ProcessingResult.Congestion) { + lastCongestionError = System.currentTimeMillis(); + } else if (processingResult == ProcessingResult.TransientError) { + lastNetworkFailure = System.currentTimeMillis(); + } + } + + /** + * + * @return + */ + long transmissionDelay() { + if (lastCongestionError == -1 && lastNetworkFailure == -1) { + return 0; + } + + long now = System.currentTimeMillis(); + if (lastCongestionError != -1) { + long congestionDelay = now - lastCongestionError; + if (congestionDelay >= 0 && congestionDelay < congestionRetryDelayMs) { + return congestionRetryDelayMs - congestionDelay; + } + lastCongestionError = -1; + } + + if (lastNetworkFailure != -1) { + long failureDelay = now - lastNetworkFailure; + if (failureDelay >= 0 && failureDelay < networkFailureRetryMs) { + return networkFailureRetryMs - failureDelay; + } + lastNetworkFailure = -1; + } + return 0; + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/DefaultTaskListenerManager.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/DefaultTaskListenerManager.java new file mode 100644 index 000000000..8e6b23077 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/DefaultTaskListenerManager.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.listener; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author xuanbei + * @since 2018/12/28 + */ +public class DefaultTaskListenerManager implements TaskListenerManager { + private Collection taskListeners = new ArrayList<>(); + + @Override + public Collection getTaskListeners() { + return taskListeners; + } + + @Override + public void addTaskListener(TaskListener taskListener) { + taskListeners.add(taskListener); + } + + @Override + public void sendTaskEvent(TaskEvent taskEvent) { + + for (TaskListener taskListener : taskListeners) { + if (taskListener.support(taskEvent)) { + taskListener.handleEvent(taskEvent); + } + } + } +} diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskEvent.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskEvent.java new file mode 100644 index 000000000..16f1abcc3 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskEvent.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.listener; + +import com.alipay.sofa.registry.task.TaskClosure; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: TaskEvent.java, v 0.1 2017-12-07 18:12 shangyu.wh Exp $ + */ +public class TaskEvent { + + public enum TaskType { + //Session task + SUBSCRIBER_REGISTER_FETCH_TASK("SubscriberRegisterFetchTask"), SUBSCRIBER_PUSH_EMPTY_TASK( + "SubscriberPushEmptyTask"), WATCHER_REGISTER_FETCH_TASK( + "WatcherRegisterFetchTask"), DATA_CHANGE_FETCH_TASK( + "DataChangeFetchTask"), DATA_PUSH_TASK( + "DataPushTask"), DATA_CHANGE_FETCH_CLOUD_TASK( + "DataChangeFetchCloudTask"), RECEIVED_DATA_MULTI_PUSH_TASK( + "ReceivedDataMultiPushTask"), RECEIVED_DATA_CONFIG_PUSH_TASK( + "ReceivedDataConfigPushTask"), CANCEL_DATA_TASK( + "CancelDataTask"), SYNC_PUBLISHER_TASK( + "SyncPublisherTask"), SYNC_SUBSCRIBER_TASK( + "SyncSubscriberTask"), SESSION_REGISTER_DATA_TASK( + "SessionRegisterDataTask"), PROVIDE_DATA_CHANGE_FETCH_TASK( + "ProvideDataChangeFetchTask"), + + SUBSCRIBER_MULTI_FETCH_TASK("SubscriberMultiFetchTask"), + + //Session Adapter task + USER_DATA_ELEMENT_PUSH_TASK("UserDataElementPushTask"), USER_DATA_ELEMENT_MULTI_PUSH_TASK( + "UserDataElementMultiPushTask"), + + //MetaServer task + SESSION_NODE_CHANGE_PUSH_TASK("SessionNodeChangePushTask"), DATA_NODE_CHANGE_PUSH_TASK( + "DataNodeChangePushTask"), RECEIVE_STATUS_CONFIRM_NOTIFY_TASK( + "ReceiveStatusConfirmNotifyTask"), PERSISTENCE_DATA_CHANGE_NOTIFY_TASK( + "PersistenceDataChangeNotifyTask"); + + private String name; + + TaskType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } + + private Object eventObj; + + private TaskType taskType; + + private long sendTimeStamp; + + private long createTime; + + private final Map attributes = new ConcurrentHashMap(); + + /** + * constructor + * @param taskType + */ + public TaskEvent(TaskType taskType) { + this.taskType = taskType; + this.createTime = System.currentTimeMillis(); + } + + private TaskClosure taskClosure; + + /** + * constructor + * @param eventObj + * @param taskType + */ + public TaskEvent(Object eventObj, TaskType taskType) { + this.eventObj = eventObj; + this.taskType = taskType; + } + + /** + * Getter method for property eventObj. + * + * @return property value of eventObj + */ + public Object getEventObj() { + return eventObj; + } + + /** + * Setter method for property eventObj. + * + * @param eventObj value to be assigned to property eventObj + */ + public void setEventObj(Object eventObj) { + this.eventObj = eventObj; + } + + /** + * Getter method for property taskType. + * + * @return property value of taskType + */ + public TaskType getTaskType() { + return taskType; + } + + /** + * get attribute by key + * @param key + * @return + */ + public Object getAttribute(String key) { + return attributes.get(key); + } + + /** + * set attribute + * @param key + * @param value + */ + public void setAttribute(String key, Object value) { + if (value == null) { + //The null value is not allowed in the ConcurrentHashMap. + attributes.remove(key); + } else { + attributes.put(key, value); + } + } + + /** + * Getter method for property taskClosure. + * + * @return property value of taskClosure + */ + public TaskClosure getTaskClosure() { + return taskClosure; + } + + /** + * Setter method for property taskClosure. + * + * @param taskClosure value to be assigned to property taskClosure + */ + public void setTaskClosure(TaskClosure taskClosure) { + this.taskClosure = taskClosure; + } + + /** + * Getter method for property sendTimeStamp. + * + * @return property value of sendTimeStamp + */ + public long getSendTimeStamp() { + return sendTimeStamp; + } + + /** + * Setter method for property sendTimeStamp. + * + * @param sendTimeStamp value to be assigned to property sendTimeStamp + */ + public void setSendTimeStamp(long sendTimeStamp) { + this.sendTimeStamp = sendTimeStamp; + } + + /** + * Getter method for property createTime. + * + * @return property value of createTime + */ + public long getCreateTime() { + return createTime; + } + + @Override + public String toString() { + return "TaskEvent{" + "eventObj=" + eventObj + ", sendTimeStamp=" + sendTimeStamp + + ", attributes=" + attributes + '}'; + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListener.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListener.java new file mode 100644 index 000000000..547d3b154 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListener.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.listener; + +/** + * + * @author shangyu.wh + * @version $Id: TaskListener.java, v 0.1 2017-12-07 18:11 shangyu.wh Exp $ + */ +public interface TaskListener { + + /** + * com.alipay.sofa.registry.server.meta.listener type check + * + * @param event + * @return true or false。 + */ + boolean support(TaskEvent event); + + /** + * event execute + * + * @param event + */ + void handleEvent(TaskEvent event); +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListenerManager.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListenerManager.java new file mode 100644 index 000000000..dc19c661d --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/listener/TaskListenerManager.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.listener; + +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: TaskListenerManager.java, v 0.1 2017-12-07 18:14 shangyu.wh Exp $ + */ +public interface TaskListenerManager { + + /** + * + * @return + */ + Collection getTaskListeners(); + + /** + * + * @param taskListener + */ + void addTaskListener(TaskListener taskListener); + + /** + * + * @param taskEvent + */ + void sendTaskEvent(TaskEvent taskEvent); +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/task/scheduler/TimedSupervisorTask.java b/server/common/util/src/main/java/com/alipay/sofa/registry/task/scheduler/TimedSupervisorTask.java new file mode 100644 index 000000000..64c49a8a1 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/task/scheduler/TimedSupervisorTask.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.scheduler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.util.TimerTask; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicLong; + +/** + * A supervisor task that schedules subtasks while enforce a timeout. + * Wrapped subtasks must be thread safe. + * + * @author David Qiang Liu + * + * + * @author shangyu.wh modify + * @version $Id: TimedSupervisorTask.java, v 0.1 2017-11-28 15:28 shangyu.wh Exp $ + */ +public class TimedSupervisorTask extends TimerTask { + + private static final Logger LOGGER = LoggerFactory + .getLogger(TimedSupervisorTask.class); + + private final ScheduledExecutorService scheduler; + private final ThreadPoolExecutor executor; + private final long timeoutMillis; + private final Runnable task; + + private String name; + + private final AtomicLong delay; + private final long maxDelay; + + /** + * constructor + * @param name + * @param scheduler + * @param executor + * @param timeout + * @param timeUnit + * @param expBackOffBound + * @param task + */ + public TimedSupervisorTask(String name, ScheduledExecutorService scheduler, + ThreadPoolExecutor executor, int timeout, TimeUnit timeUnit, + int expBackOffBound, Runnable task) { + this.name = name; + this.scheduler = scheduler; + this.executor = executor; + this.timeoutMillis = timeUnit.toMillis(timeout); + this.task = task; + this.delay = new AtomicLong(timeoutMillis); + this.maxDelay = timeoutMillis * expBackOffBound; + + } + + @Override + public void run() { + Future future = null; + try { + future = executor.submit(task); + // block until done or timeout + future.get(timeoutMillis, TimeUnit.MILLISECONDS); + delay.set(timeoutMillis); + } catch (TimeoutException e) { + LOGGER.error("{} task supervisor timed out", name, e); + + long currentDelay = delay.get(); + long newDelay = Math.min(maxDelay, currentDelay * 2); + delay.compareAndSet(currentDelay, newDelay); + + } catch (RejectedExecutionException e) { + LOGGER.error("{} task supervisor rejected the task: {}", name, task, e); + } catch (Throwable e) { + LOGGER.error("{} task supervisor threw an exception", name, e); + } finally { + if (future != null) { + future.cancel(true); + } + scheduler.schedule(this, delay.get(), TimeUnit.MILLISECONDS); + } + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/timer/AsyncHashedWheelTimer.java b/server/common/util/src/main/java/com/alipay/sofa/registry/timer/AsyncHashedWheelTimer.java new file mode 100644 index 000000000..e19b0039d --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/timer/AsyncHashedWheelTimer.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.timer; + +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * based on HashedWheelTimer, add function: exec TimerTask async + * + * @author kezhu.wukz + * @version $Id: AsyncHashedWheelTimer.java, v 0.1 2019-01-11 10:54 AM kezhu.wukz Exp $ + */ +public class AsyncHashedWheelTimer extends HashedWheelTimer { + + private static final Logger LOGGER = LoggerFactory + .getLogger(AsyncHashedWheelTimer.class); + + /** */ + public static final TaskFailedCallback DEFAULT_TASK_FAILED_CALLBACK = new TaskFailedCallback() { + @Override + public void executionRejected(Throwable e) { + LOGGER + .error( + "executionRejected: " + + e.getMessage(), + e); + } + + @Override + public void executionFailed(Throwable e) { + LOGGER + .error( + "executionFailed: " + + e.getMessage(), + e); + } + }; + + /** */ + private final Executor executor; + + /** */ + private final TaskFailedCallback taskFailedCallback; + + /** + * + * @param threadFactory + * @param tickDuration + * @param unit + * @param ticksPerWheel + * @param asyncThreadFactory + */ + public AsyncHashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, + int ticksPerWheel, ThreadFactory asyncThreadFactory, + TaskFailedCallback taskFailedCallback) { + super(threadFactory, tickDuration, unit, ticksPerWheel); + + this.executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, + new SynchronousQueue<>(), asyncThreadFactory); + this.taskFailedCallback = taskFailedCallback; + } + + /** + * + * @param threadFactory + * @param tickDuration + * @param unit + * @param ticksPerWheel + * @param asyncExecutor + */ + public AsyncHashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, + int ticksPerWheel, Executor asyncExecutor, + TaskFailedCallback taskFailedCallback) { + super(threadFactory, tickDuration, unit, ticksPerWheel); + + this.executor = asyncExecutor; + this.taskFailedCallback = taskFailedCallback; + } + + /** + * + * @param threadFactory + * @param tickDuration + * @param unit + * @param ticksPerWheel + * @param asyncThreadFactory + */ + public AsyncHashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, + int ticksPerWheel, ThreadFactory asyncThreadFactory) { + super(threadFactory, tickDuration, unit, ticksPerWheel); + + this.executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, + new SynchronousQueue<>(), asyncThreadFactory); + this.taskFailedCallback = DEFAULT_TASK_FAILED_CALLBACK; + } + + /** + * + * @param threadFactory + * @param tickDuration + * @param unit + * @param ticksPerWheel + * @param asyncExecutor + */ + public AsyncHashedWheelTimer(ThreadFactory threadFactory, long tickDuration, TimeUnit unit, + int ticksPerWheel, Executor asyncExecutor) { + super(threadFactory, tickDuration, unit, ticksPerWheel); + + this.executor = asyncExecutor; + this.taskFailedCallback = DEFAULT_TASK_FAILED_CALLBACK; + } + + /** + */ + @Override + public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) { + return super.newTimeout(new AsyncTimerTask(task), delay, unit); + } + + /** + * + */ + class AsyncTimerTask implements TimerTask, Runnable { + /** */ + TimerTask timerTask; + /** */ + Timeout timeout; + + /** + * @param timerTask + */ + public AsyncTimerTask(TimerTask timerTask) { + super(); + this.timerTask = timerTask; + } + + /** + */ + @Override + public void run(Timeout timeout) throws Exception { + this.timeout = timeout; + try { + AsyncHashedWheelTimer.this.executor.execute(this); + } catch (RejectedExecutionException e) { + taskFailedCallback.executionRejected(e); + } catch (Throwable e) { + taskFailedCallback.executionRejected(e); + } + } + + /** + * @see java.lang.Runnable#run() + */ + @Override + public void run() { + try { + this.timerTask.run(this.timeout); + } catch (Throwable e) { + taskFailedCallback.executionFailed(e); + } + } + + } + + public interface TaskFailedCallback { + + void executionRejected(Throwable e); + + void executionFailed(Throwable e); + + } + +} diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/util/CollectionUtils.java b/server/common/util/src/main/java/com/alipay/sofa/registry/util/CollectionUtils.java new file mode 100644 index 000000000..cc6311dd6 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/util/CollectionUtils.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import java.util.Collection; +import java.util.Optional; + +/** + * The type Collection utils. + * @author zhuoyu.sjw + * @version $Id : CollectionUtils.java, v 0.1 2018-04-12 14:54 zhuoyu.sjw Exp $$ + */ +public class CollectionUtils { + + /** + * Gets random. + * + * @param the type parameter + * @param e the e + * @return the random + */ + public static Optional getRandom(Collection e) { + return e.stream().skip((int) (e.size() * Math.random())).findFirst(); + } + +} diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/util/FileUtils.java b/server/common/util/src/main/java/com/alipay/sofa/registry/util/FileUtils.java new file mode 100644 index 000000000..c817bcfdd --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/util/FileUtils.java @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import java.io.Closeable; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * + * @author shangyu.wh + * @version $Id: FileUtils.java, v 0.1 2018-08-23 12:02 shangyu.wh Exp $ + */ +public class FileUtils { + + private static final int EOF = -1; + + /** + * write file + * @param file + * @param data + * @param append + * @throws IOException + */ + public static void writeByteArrayToFile(File file, byte[] data, boolean append) + throws IOException { + OutputStream out = null; + try { + out = openOutputStream(file, append); + out.write(data); + out.close(); // don't swallow close Exception if copy completes normally + } finally { + closeQuietly(out); + } + } + + /** + * read file + * @param file + * @return + * @throws IOException + */ + public static byte[] readFileToByteArray(File file) throws IOException { + InputStream in = null; + try { + in = openInputStream(file); + return toByteArray(in, file.length()); + } finally { + closeQuietly(in); + } + } + + /** + * create dir + * @param directory + * @throws IOException + */ + public static void forceMkdir(File directory) throws IOException { + if (directory.exists()) { + if (!directory.isDirectory()) { + String message = "File " + directory + " exists and is " + + "not a directory. Unable to create directory."; + throw new IOException(message); + } + } else { + if (!directory.mkdirs()) { + // Double-check that some other thread or process hasn't made + // the directory in the background + if (!directory.isDirectory()) { + String message = "Unable to create directory " + directory; + throw new IOException(message); + } + } + } + } + + /** + * file output stream + * @param file + * @param append + * @return + * @throws IOException + */ + public static FileOutputStream openOutputStream(File file, boolean append) throws IOException { + if (file.exists()) { + if (file.isDirectory()) { + throw new IOException("File '" + file + "' exists but is a directory"); + } + if (!file.canWrite()) { + throw new IOException("File '" + file + "' cannot be written to"); + } + } else { + File parent = file.getParentFile(); + if (parent != null) { + if (!parent.mkdirs() && !parent.isDirectory()) { + throw new IOException("Directory '" + parent + "' could not be created"); + } + } + } + return new FileOutputStream(file, append); + } + + /** + * file to inputStream + * @param file + * @return + * @throws IOException + */ + public static FileInputStream openInputStream(File file) throws IOException { + if (file.exists()) { + if (file.isDirectory()) { + throw new IOException("File '" + file + "' exists but is a directory"); + } + if (!file.canRead()) { + throw new IOException("File '" + file + "' cannot be read"); + } + } else { + throw new FileNotFoundException("File '" + file + "' does not exist"); + } + return new FileInputStream(file); + } + + /** + * transfer InputStream to byteArray + * @param input + * @param size + * @return + * @throws IOException + */ + public static byte[] toByteArray(InputStream input, long size) throws IOException { + + if (size > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + + size); + } + + return toByteArray(input, (int) size); + } + + /** + * transfer InputStream to byteArray + * @param input + * @param size + * @return + * @throws IOException + */ + public static byte[] toByteArray(InputStream input, int size) throws IOException { + + if (size < 0) { + throw new IllegalArgumentException("Size must be equal or greater than zero: " + size); + } + + if (size == 0) { + return new byte[0]; + } + + byte[] data = new byte[size]; + int offset = 0; + int readed; + + while (offset < size && (readed = input.read(data, offset, size - offset)) != EOF) { + offset += readed; + } + + if (offset != size) { + throw new IOException("Unexpected readed size. current: " + offset + ", excepted: " + + size); + } + + return data; + } + + /** + * + * @param closeable + */ + public static void closeQuietly(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (IOException ioe) { + // ignore + } + } + + public static void forceDelete(File file) throws IOException { + if (!file.exists()) { + return; + } + + if (file.isDirectory()) { + deleteDirectory(file); + } else { + if (!file.delete()) { + String message = "Unable to delete file: " + file; + throw new IOException(message); + } + } + } + + public static void deleteDirectory(File directory) throws IOException { + if (!directory.exists()) { + return; + } + + cleanDirectory(directory); + if (!directory.delete()) { + String message = "Unable to delete directory " + directory + "."; + throw new IOException(message); + } + } + + public static void cleanDirectory(File directory) throws IOException { + if (!directory.exists()) { + String message = directory + " does not exist"; + throw new IllegalArgumentException(message); + } + + if (!directory.isDirectory()) { + String message = directory + " is not a directory"; + throw new IllegalArgumentException(message); + } + + File[] files = directory.listFiles(); + if (files == null) { // null if security restricted + throw new IOException("Failed to list contents of " + directory); + } + + IOException exception = null; + for (int i = 0; i < files.length; i++) { + File file = files[i]; + try { + forceDelete(file); + } catch (IOException ioe) { + exception = ioe; + } + } + + if (null != exception) { + throw exception; + } + } +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/util/NamedThreadFactory.java b/server/common/util/src/main/java/com/alipay/sofa/registry/util/NamedThreadFactory.java new file mode 100644 index 000000000..c429ca42e --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/util/NamedThreadFactory.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: NamedThreadFactory.java, v 0.1 2018-10-11 11:25 shangyu.wh Exp $ + */ +public class NamedThreadFactory implements ThreadFactory { + + private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); + private final AtomicInteger threadNumber = new AtomicInteger(1); + private final ThreadGroup group; + private final String namePrefix; + private final boolean isDaemon; + + public NamedThreadFactory() { + this("ThreadPool"); + } + + public NamedThreadFactory(String name) { + this(name, false); + } + + public NamedThreadFactory(String preffix, boolean daemon) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + namePrefix = preffix + "-" + POOL_NUMBER.getAndIncrement() + "-thread-"; + isDaemon = daemon; + } + + /** + * Create a thread. + * + * @see ThreadFactory#newThread(Runnable) + */ + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); + t.setDaemon(isDaemon); + if (t.getPriority() != Thread.NORM_PRIORITY) { + t.setPriority(Thread.NORM_PRIORITY); + } + return t; + } + +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/util/ParaCheckUtil.java b/server/common/util/src/main/java/com/alipay/sofa/registry/util/ParaCheckUtil.java new file mode 100644 index 000000000..a24b83928 --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/util/ParaCheckUtil.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import java.util.Collection; + +/** + * @author qian.lqlq + * @version $Id: ParaCheckUtil.java, v 0.1 2017-12-06 21:20 qian.lqlq Exp $ + */ +public class ParaCheckUtil { + + /** + * check object not null + * @param param + * @param paraName + * @throws RuntimeException + */ + public static void checkNotNull(Object param, String paraName) throws RuntimeException { + if (param == null) { + throw new RuntimeException(String.format("%s is not allowed to be null", paraName)); + } + } + + /** + * check string not blank + * @param param + * @param paraName + * @throws RuntimeException + */ + public static void checkNotBlank(String param, String paraName) throws RuntimeException { + if (param == null || param.trim().length() == 0) { + throw new RuntimeException(String.format("%s is not allowed to be blank", paraName)); + } + } + + /** + * check param not empty + * @param param + * @param paraName + * @throws RuntimeException + */ + public static void checkNotEmpty(Collection param, String paraName) throws RuntimeException { + if (param == null || param.size() == 0) { + throw new RuntimeException(String.format("%s is not allowed to be empty", paraName)); + } + } + +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/util/PropertySplitter.java b/server/common/util/src/main/java/com/alipay/sofa/registry/util/PropertySplitter.java new file mode 100644 index 000000000..b56f53e9c --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/util/PropertySplitter.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import com.google.common.base.Splitter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * + * @author shangyu.wh + * @version $Id: PropertySplitter.java, v 0.1 2018-05-03 16:29 shangyu.wh Exp $ + */ +public class PropertySplitter { + + /** + * Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2 + */ + public Map map(String property) { + if (property == null) { + return new HashMap<>(); + } + return this.map(property, ","); + } + + /** + * Example: one.example.property = KEY1:VALUE1.1,VALUE1.2|KEY2:VALUE2.1,VALUE2.2 + */ + public Map> mapOfList(String property) { + if (property == null) { + return new HashMap<>(); + } + Map map = this.map(property, "|"); + + Map> mapOfList = new HashMap<>(); + for (Entry entry : map.entrySet()) { + mapOfList.put(entry.getKey(), this.list(entry.getValue())); + } + + return mapOfList; + } + + /** + * Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4 + */ + public Collection list(String property) { + if (property == null) { + return new ArrayList<>(); + } + return this.list(property, ","); + } + + /** + * Example: one.example.property = VALUE1.1,VALUE1.2|VALUE2.1,VALUE2.2 + */ + public Collection> groupedList(String property) { + if (property == null) { + return new ArrayList<>(); + } + Collection unGroupedList = this.list(property, "|"); + + Collection> groupedList = new ArrayList<>(); + for (String group : unGroupedList) { + groupedList.add(this.list(group)); + } + + return groupedList; + + } + + private Collection list(String property, String splitter) { + return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property); + } + + private Map map(String property, String splitter) { + return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":") + .split(property); + } + +} \ No newline at end of file diff --git a/server/common/util/src/main/java/com/alipay/sofa/registry/util/VersionsMapUtils.java b/server/common/util/src/main/java/com/alipay/sofa/registry/util/VersionsMapUtils.java new file mode 100644 index 000000000..2c09283af --- /dev/null +++ b/server/common/util/src/main/java/com/alipay/sofa/registry/util/VersionsMapUtils.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import java.util.Map; + +/** + * @author xuanbei + * @since 2019/2/12 + */ +public class VersionsMapUtils { + public static boolean checkAndUpdateVersions(Map versionsMap, String versionKey, + Long version) { + while (true) { + Long oldValue = versionsMap.get(versionKey); + if (oldValue == null) { + // Add firstly + if (versionsMap.putIfAbsent(versionKey, version) == null) { + return true; + } + } else { + if (version > oldValue) { + if (versionsMap.replace(versionKey, oldValue, version)) { + return true; + } + } else { + return false; + } + } + } + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/converter/ScopeEnumConverterTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/converter/ScopeEnumConverterTest.java new file mode 100644 index 000000000..856110438 --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/converter/ScopeEnumConverterTest.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.converter; + +import com.alipay.sofa.registry.core.model.ScopeEnum; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author xuanbei + * @since 2018/12/28 + */ +public class ScopeEnumConverterTest { + @Test + public void doTest() { + Assert.assertEquals(ScopeEnum.zone, ScopeEnumConverter.convertToScope("zone")); + Assert.assertEquals(ScopeEnum.dataCenter, ScopeEnumConverter.convertToScope("dataCenter")); + Assert.assertEquals(ScopeEnum.global, ScopeEnumConverter.convertToScope("global")); + Assert.assertEquals(ScopeEnum.zone, ScopeEnumConverter.convertToScope("other value")); + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/log/LoggerTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/log/LoggerTest.java new file mode 100644 index 000000000..5f0ab2332 --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/log/LoggerTest.java @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.log; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author xuanbei + * @since 2018/12/29 + */ +public class LoggerTest { + private static final Logger TRACE_LOGGER = LoggerFactory.getLogger("TRACE-LOGGER"); + private static final Logger DEBUG_LOGGER = LoggerFactory.getLogger("DEBUG-LOGGER"); + private static final Logger INFO_LOGGER = LoggerFactory.getLogger("INFO-LOGGER"); + private static final Logger WARN_LOGGER = LoggerFactory.getLogger("WARN-LOGGER"); + private static final Logger ERROR_LOGGER = LoggerFactory.getLogger("ERROR-LOGGER"); + + @Test + public void levelTest() { + Assert.assertTrue(TRACE_LOGGER.isTraceEnabled()); + Assert.assertTrue(TRACE_LOGGER.isDebugEnabled()); + Assert.assertTrue(TRACE_LOGGER.isInfoEnabled()); + Assert.assertTrue(TRACE_LOGGER.isWarnEnabled()); + Assert.assertTrue(TRACE_LOGGER.isErrorEnabled()); + + Assert.assertFalse(DEBUG_LOGGER.isTraceEnabled()); + Assert.assertTrue(DEBUG_LOGGER.isDebugEnabled()); + Assert.assertTrue(DEBUG_LOGGER.isInfoEnabled()); + Assert.assertTrue(DEBUG_LOGGER.isWarnEnabled()); + Assert.assertTrue(DEBUG_LOGGER.isErrorEnabled()); + + Assert.assertFalse(INFO_LOGGER.isTraceEnabled()); + Assert.assertFalse(INFO_LOGGER.isDebugEnabled()); + Assert.assertTrue(INFO_LOGGER.isInfoEnabled()); + Assert.assertTrue(INFO_LOGGER.isWarnEnabled()); + Assert.assertTrue(INFO_LOGGER.isErrorEnabled()); + + Assert.assertFalse(WARN_LOGGER.isTraceEnabled()); + Assert.assertFalse(WARN_LOGGER.isDebugEnabled()); + Assert.assertFalse(WARN_LOGGER.isInfoEnabled()); + Assert.assertTrue(WARN_LOGGER.isWarnEnabled()); + Assert.assertTrue(WARN_LOGGER.isErrorEnabled()); + + Assert.assertFalse(ERROR_LOGGER.isTraceEnabled()); + Assert.assertFalse(ERROR_LOGGER.isDebugEnabled()); + Assert.assertFalse(ERROR_LOGGER.isInfoEnabled()); + Assert.assertFalse(ERROR_LOGGER.isWarnEnabled()); + Assert.assertTrue(ERROR_LOGGER.isErrorEnabled()); + } + + @Test + public void logTest() { + TRACE_LOGGER.trace("First trace log."); + TRACE_LOGGER.trace("trace log with one parameter {}.", "value1"); + TRACE_LOGGER.trace("trace log with two parameter {}, {}.", "value1", "value2"); + TRACE_LOGGER.trace("trace log with three parameter {}, {}, {}.", "value1", "value2", + "value3"); + TRACE_LOGGER.trace("trace log with three parameter {}, {}, {}.", "value1", "value2", + "value3"); + TRACE_LOGGER.trace("trace log with throwable.", new RuntimeException( + "trace log with throwable RuntimeException")); + TRACE_LOGGER.trace("trace log with parameter and throwable {} {} {}.", "value1", "value2", + "value3", new RuntimeException( + "trace log with parameter and throwable RuntimeException")); + + Assert.assertTrue(TestAppender.containsMessage("First trace log.")); + Assert.assertTrue(TestAppender.containsMessage("trace log with one parameter value1.")); + Assert.assertTrue(TestAppender + .containsMessage("trace log with two parameter value1, value2.")); + Assert.assertTrue(TestAppender + .containsMessage("trace log with three parameter value1, value2, value3.")); + Assert.assertTrue(TestAppender.containsMessageAndThrowable("trace log with throwable.", + new RuntimeException("trace log with throwable RuntimeException"))); + Assert.assertTrue(TestAppender.containsMessageAndThrowable( + "trace log with parameter and throwable value1 value2 value3.", new RuntimeException( + "trace log with parameter and throwable RuntimeException"))); + + DEBUG_LOGGER.debug("First debug log."); + DEBUG_LOGGER.debug("debug log with one parameter {}.", "value1"); + DEBUG_LOGGER.debug("debug log with two parameter {}, {}.", "value1", "value2"); + DEBUG_LOGGER.debug("debug log with three parameter {}, {}, {}.", "value1", "value2", + "value3"); + DEBUG_LOGGER.debug("debug log with three parameter {}, {}, {}.", "value1", "value2", + "value3"); + DEBUG_LOGGER.debug("debug log with throwable.", new RuntimeException( + "debug log with throwable RuntimeException")); + DEBUG_LOGGER.debug("debug log with parameter and throwable {} {} {}.", "value1", "value2", + "value3", new RuntimeException( + "debug log with parameter and throwable RuntimeException")); + + Assert.assertTrue(TestAppender.containsMessage("First debug log.")); + Assert.assertTrue(TestAppender.containsMessage("debug log with one parameter value1.")); + Assert.assertTrue(TestAppender + .containsMessage("debug log with two parameter value1, value2.")); + Assert.assertTrue(TestAppender + .containsMessage("debug log with three parameter value1, value2, value3.")); + Assert.assertTrue(TestAppender.containsMessageAndThrowable("debug log with throwable.", + new RuntimeException("debug log with throwable RuntimeException"))); + Assert.assertTrue(TestAppender.containsMessageAndThrowable( + "debug log with parameter and throwable value1 value2 value3.", new RuntimeException( + "debug log with parameter and throwable RuntimeException"))); + + INFO_LOGGER.info("First info log."); + INFO_LOGGER.info("info log with one parameter {}.", "value1"); + INFO_LOGGER.info("info log with two parameter {}, {}.", "value1", "value2"); + INFO_LOGGER.info("info log with three parameter {}, {}, {}.", "value1", "value2", "value3"); + INFO_LOGGER.info("info log with three parameter {}, {}, {}.", "value1", "value2", "value3"); + INFO_LOGGER.info("info log with throwable.", new RuntimeException( + "info log with throwable RuntimeException")); + INFO_LOGGER.info("info log with parameter and throwable {} {} {}.", "value1", "value2", + "value3", + new RuntimeException("info log with parameter and throwable RuntimeException")); + + Assert.assertTrue(TestAppender.containsMessage("First info log.")); + Assert.assertTrue(TestAppender.containsMessage("info log with one parameter value1.")); + Assert.assertTrue(TestAppender + .containsMessage("info log with two parameter value1, value2.")); + Assert.assertTrue(TestAppender + .containsMessage("info log with three parameter value1, value2, value3.")); + Assert.assertTrue(TestAppender.containsMessageAndThrowable("info log with throwable.", + new RuntimeException("info log with throwable RuntimeException"))); + Assert.assertTrue(TestAppender.containsMessageAndThrowable( + "info log with parameter and throwable value1 value2 value3.", new RuntimeException( + "info log with parameter and throwable RuntimeException"))); + + WARN_LOGGER.warn("First warn log."); + WARN_LOGGER.warn("warn log with one parameter {}.", "value1"); + WARN_LOGGER.warn("warn log with two parameter {}, {}.", "value1", "value2"); + WARN_LOGGER.warn("warn log with three parameter {}, {}, {}.", "value1", "value2", "value3"); + WARN_LOGGER.warn("warn log with three parameter {}, {}, {}.", "value1", "value2", "value3"); + WARN_LOGGER.warn("warn log with throwable.", new RuntimeException( + "warn log with throwable RuntimeException")); + WARN_LOGGER.warn("warn log with parameter and throwable {} {} {}.", "value1", "value2", + "value3", + new RuntimeException("warn log with parameter and throwable RuntimeException")); + + Assert.assertTrue(TestAppender.containsMessage("First warn log.")); + Assert.assertTrue(TestAppender.containsMessage("warn log with one parameter value1.")); + Assert.assertTrue(TestAppender + .containsMessage("warn log with two parameter value1, value2.")); + Assert.assertTrue(TestAppender + .containsMessage("warn log with three parameter value1, value2, value3.")); + Assert.assertTrue(TestAppender.containsMessageAndThrowable("warn log with throwable.", + new RuntimeException("warn log with throwable RuntimeException"))); + Assert.assertTrue(TestAppender.containsMessageAndThrowable( + "warn log with parameter and throwable value1 value2 value3.", new RuntimeException( + "warn log with parameter and throwable RuntimeException"))); + + ERROR_LOGGER.error("First error log."); + ERROR_LOGGER.error("error log with one parameter {}.", "value1"); + ERROR_LOGGER.error("error log with two parameter {}, {}.", "value1", "value2"); + ERROR_LOGGER.error("error log with three parameter {}, {}, {}.", "value1", "value2", + "value3"); + ERROR_LOGGER.error("error log with three parameter {}, {}, {}.", "value1", "value2", + "value3"); + ERROR_LOGGER.error("error log with throwable.", new RuntimeException( + "error log with throwable RuntimeException")); + ERROR_LOGGER.error("error log with parameter and throwable {} {} {}.", "value1", "value2", + "value3", new RuntimeException( + "error log with parameter and throwable RuntimeException")); + + Assert.assertTrue(TestAppender.containsMessage("First error log.")); + Assert.assertTrue(TestAppender.containsMessage("error log with one parameter value1.")); + Assert.assertTrue(TestAppender + .containsMessage("error log with two parameter value1, value2.")); + Assert.assertTrue(TestAppender + .containsMessage("error log with three parameter value1, value2, value3.")); + Assert.assertTrue(TestAppender.containsMessageAndThrowable("error log with throwable.", + new RuntimeException("error log with throwable RuntimeException"))); + Assert.assertTrue(TestAppender.containsMessageAndThrowable( + "error log with parameter and throwable value1 value2 value3.", new RuntimeException( + "error log with parameter and throwable RuntimeException"))); + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/log/TestAppender.java b/server/common/util/src/test/java/com/alipay/sofa/registry/log/TestAppender.java new file mode 100644 index 000000000..0a765cffb --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/log/TestAppender.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.log; + +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.AppenderBase; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author xuanbei + * @since 2018/12/29 + */ +public class TestAppender extends AppenderBase { + public static List events = new ArrayList<>(); + + @Override + protected void append(LoggingEvent e) { + events.add(e); + } + + public static boolean containsMessage(String message) { + for (LoggingEvent loggingEvent : events) { + if (loggingEvent.getFormattedMessage().contains(message)) { + return true; + } + } + + return false; + } + + public static boolean containsMessageAndThrowable(String message, Throwable throwable) { + for (LoggingEvent loggingEvent : events) { + if (loggingEvent.getFormattedMessage().contains(message) + && loggingEvent.getThrowableProxy().getMessage().equals(throwable.getMessage())) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/task/listener/TaskListenerTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/task/listener/TaskListenerTest.java new file mode 100644 index 000000000..9443f5d44 --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/task/listener/TaskListenerTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.task.listener; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import static com.alipay.sofa.registry.task.listener.TaskEvent.TaskType.CANCEL_DATA_TASK; +import static com.alipay.sofa.registry.task.listener.TaskEvent.TaskType.DATA_PUSH_TASK; +import static com.alipay.sofa.registry.task.listener.TaskEvent.TaskType.WATCHER_REGISTER_FETCH_TASK; + +/** + * @author xuanbei + * @since 2018/12/28 + */ +public class TaskListenerTest { + private static final TaskListenerManager taskListenerManager = new DefaultTaskListenerManager(); + private static volatile boolean watcherRegisterFetchTaskListenerCalled = false; + private static volatile boolean cancelDataTaskListenerCalled = false; + private static volatile boolean dataPushTaskListenerCalled = false; + + @BeforeClass + public static void beforeClass() { + taskListenerManager.addTaskListener(new CancelDataTaskListener()); + taskListenerManager.addTaskListener(new DataPushTaskListener()); + taskListenerManager.addTaskListener(new WatcherRegisterFetchTaskListener()); + } + + @Test + public void doTest() { + Assert.assertEquals(3, taskListenerManager.getTaskListeners().size()); + taskListenerManager.sendTaskEvent(new TaskEvent(DATA_PUSH_TASK)); + Assert.assertTrue(dataPushTaskListenerCalled); + Assert.assertFalse(cancelDataTaskListenerCalled); + Assert.assertFalse(watcherRegisterFetchTaskListenerCalled); + dataPushTaskListenerCalled = false; + + taskListenerManager.sendTaskEvent(new TaskEvent(CANCEL_DATA_TASK)); + Assert.assertFalse(dataPushTaskListenerCalled); + Assert.assertTrue(cancelDataTaskListenerCalled); + Assert.assertFalse(watcherRegisterFetchTaskListenerCalled); + cancelDataTaskListenerCalled = false; + + taskListenerManager.sendTaskEvent(new TaskEvent(WATCHER_REGISTER_FETCH_TASK)); + Assert.assertFalse(dataPushTaskListenerCalled); + Assert.assertFalse(cancelDataTaskListenerCalled); + Assert.assertTrue(watcherRegisterFetchTaskListenerCalled); + watcherRegisterFetchTaskListenerCalled = false; + } + + private static class DataPushTaskListener implements TaskListener { + @Override + public boolean support(TaskEvent event) { + return DATA_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + dataPushTaskListenerCalled = true; + } + } + + private static class CancelDataTaskListener implements TaskListener { + @Override + public boolean support(TaskEvent event) { + return TaskEvent.TaskType.CANCEL_DATA_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + cancelDataTaskListenerCalled = true; + } + } + + private static class WatcherRegisterFetchTaskListener implements TaskListener { + @Override + public boolean support(TaskEvent event) { + return TaskEvent.TaskType.WATCHER_REGISTER_FETCH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + watcherRegisterFetchTaskListenerCalled = true; + } + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/util/CollectionUtilsTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/util/CollectionUtilsTest.java new file mode 100644 index 000000000..7605a553d --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/util/CollectionUtilsTest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +/** + * @author xuanbei + * @since 2018/12/28 + */ +public class CollectionUtilsTest { + Collection stringCollection = new ArrayList<>(Arrays.asList("zhangsan", "lisi", + "wangwu", "zhaoliu", "sunqi", "zhouba")); + + @Test + public void testGetRandom() { + boolean allValueSame = true; + String firstValue = null; + for (int i = 0; i < 10; i++) { + String radomeValue = CollectionUtils.getRandom(stringCollection).get(); + Assert.assertTrue(stringCollection.contains(radomeValue)); + if (firstValue == null) { + firstValue = radomeValue; + } else if (!radomeValue.equals(firstValue)) { + allValueSame = false; + } + } + Assert.assertFalse(allValueSame); + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/util/FileUtilsTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/util/FileUtilsTest.java new file mode 100644 index 000000000..25b56cccb --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/util/FileUtilsTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @author xuanbei + * @since 2019/1/16 + */ +public class FileUtilsTest { + @Test + public void doTest() throws Exception { + File dir = new File(System.getProperty("user.home") + File.separator + "FileUtilsTestDir"); + File file = new File(dir, "FileUtilsTest"); + FileUtils.forceDelete(dir); + + String data = "FileUtilsTest"; + FileUtils.writeByteArrayToFile(file, data.getBytes(), true); + byte[] readByte = FileUtils.readFileToByteArray(file); + assertEquals(data, new String(readByte)); + + boolean throwException = false; + try { + FileUtils.forceMkdir(file); + } catch (Exception e) { + throwException = true; + assertTrue(e.getClass() == IOException.class); + assertTrue(e.getMessage().contains( + "FileUtilsTest exists and is not a directory. Unable to create directory.")); + } + if (!throwException) { + fail("should throw Exception."); + } + FileUtils.forceDelete(file); + FileUtils.forceDelete(dir); + + FileUtils.forceMkdir(dir); + assertTrue(dir.exists()); + assertTrue(dir.isDirectory()); + FileUtils.forceDelete(dir); + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/util/ParaCheckUtilTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/util/ParaCheckUtilTest.java new file mode 100644 index 000000000..930ee7e79 --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/util/ParaCheckUtilTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +import static junit.framework.TestCase.fail; + +/** + * @author xuanbei + * @since 2018/12/28 + */ +public class ParaCheckUtilTest { + @Test + public void testCheckNotNull() { + ParaCheckUtil.checkNotNull("zhangsan", "name"); + try { + ParaCheckUtil.checkNotNull(null, "name"); + fail("cannot access here."); + } catch (Exception e) { + Assert.assertTrue(e instanceof RuntimeException); + Assert.assertEquals("name is not allowed to be null", e.getMessage()); + } + } + + @Test + public void testCheckNotBlank() { + ParaCheckUtil.checkNotBlank("zhangsan", "name"); + try { + ParaCheckUtil.checkNotBlank("", "name"); + fail("cannot access here."); + } catch (Exception e) { + Assert.assertTrue(e instanceof RuntimeException); + Assert.assertEquals("name is not allowed to be blank", e.getMessage()); + } + } + + @Test + public void testCheckNotEmpty() { + ParaCheckUtil.checkNotEmpty(Arrays.asList("zhangsan", "lisi"), "names"); + try { + ParaCheckUtil.checkNotEmpty(new ArrayList<>(), "names"); + fail("cannot access here."); + } catch (Exception e) { + Assert.assertTrue(e instanceof RuntimeException); + Assert.assertEquals("names is not allowed to be empty", e.getMessage()); + } + } +} diff --git a/server/common/util/src/test/java/com/alipay/sofa/registry/util/PropertySplitterTest.java b/server/common/util/src/test/java/com/alipay/sofa/registry/util/PropertySplitterTest.java new file mode 100644 index 000000000..93c1d70f5 --- /dev/null +++ b/server/common/util/src/test/java/com/alipay/sofa/registry/util/PropertySplitterTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +/** + * @author xuanbei + * @since 2018/12/28 + */ +public class PropertySplitterTest { + private PropertySplitter propertySplitter = new PropertySplitter(); + + @Test + public void testMap() { + Assert.assertEquals(0, propertySplitter.map(null).size()); + Assert.assertEquals(0, propertySplitter.map("").size()); + Assert.assertEquals(2, propertySplitter.map("KEY1:VALUE1,KEY2:VALUE2").size()); + Assert.assertEquals("VALUE1", propertySplitter.map("KEY1:VALUE1,KEY2:VALUE2").get("KEY1")); + Assert.assertEquals("VALUE2", propertySplitter.map("KEY1:VALUE1,KEY2:VALUE2").get("KEY2")); + } + + @Test + public void testMapOfList() { + Assert.assertEquals(0, propertySplitter.mapOfList(null).size()); + Assert.assertEquals(0, propertySplitter.mapOfList("|").size()); + Assert.assertEquals(2, + propertySplitter.mapOfList("KEY1:VALUE1.1,VALUE1.2|KEY2:VALUE2.1,VALUE2.2").size()); + Assert.assertTrue(propertySplitter.map("KEY1:VALUE1,KEY2:VALUE2").get("KEY1") + .contains("VALUE1")); + Assert.assertTrue(propertySplitter.map("KEY1:VALUE1,KEY2:VALUE2").get("KEY2") + .contains("VALUE2")); + } + + @Test + public void testList() { + Assert.assertEquals(0, propertySplitter.list(null).size()); + Assert.assertEquals(0, propertySplitter.list("").size()); + Assert.assertEquals(4, propertySplitter.list("VALUE1,VALUE2,VALUE3,VALUE4").size()); + Assert.assertTrue(propertySplitter.list("VALUE1,VALUE2,VALUE3,VALUE4").contains("VALUE1")); + Assert.assertTrue(propertySplitter.list("VALUE1,VALUE2,VALUE3,VALUE4").contains("VALUE2")); + Assert.assertTrue(propertySplitter.list("VALUE1,VALUE2,VALUE3,VALUE4").contains("VALUE3")); + Assert.assertTrue(propertySplitter.list("VALUE1,VALUE2,VALUE3,VALUE4").contains("VALUE4")); + } + + @Test + public void testGroupedList() { + Assert.assertEquals(0, propertySplitter.groupedList(null).size()); + Assert.assertEquals(0, propertySplitter.groupedList("").size()); + Assert.assertEquals(2, propertySplitter.groupedList("VALUE1.1,VALUE1.2|VALUE2.1,VALUE2.2") + .size()); + Assert.assertTrue(((List) (((List) propertySplitter + .groupedList("VALUE1.1,VALUE1.2|VALUE2.1,VALUE2.2")).get(0))).contains("VALUE1.1")); + Assert.assertTrue(((List) (((List) propertySplitter + .groupedList("VALUE1.1,VALUE1.2|VALUE2.1,VALUE2.2")).get(0))).contains("VALUE1.1")); + Assert.assertTrue(((List) (((List) propertySplitter + .groupedList("VALUE1.1,VALUE1.2|VALUE2.1,VALUE2.2")).get(1))).contains("VALUE2.1")); + Assert.assertTrue(((List) (((List) propertySplitter + .groupedList("VALUE1.1,VALUE1.2|VALUE2.1,VALUE2.2")).get(1))).contains("VALUE2.2")); + } +} diff --git a/server/common/util/src/test/resources/logback-test.xml b/server/common/util/src/test/resources/logback-test.xml new file mode 100644 index 000000000..6c3ccdf3e --- /dev/null +++ b/server/common/util/src/test/resources/logback-test.xml @@ -0,0 +1,31 @@ + + + + + + + + %m%n + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/consistency/pom.xml b/server/consistency/pom.xml new file mode 100644 index 000000000..7e8855042 --- /dev/null +++ b/server/consistency/pom.xml @@ -0,0 +1,38 @@ + + + + com.alipay.sofa + registry-server-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-consistency + + + ../../ + + + + + junit + junit + test + + + org.slf4j + slf4j-api + test + + + ch.qos.logback + logback-classic + test + + + + + diff --git a/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/ConsistentHash.java b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/ConsistentHash.java new file mode 100644 index 000000000..3c6949236 --- /dev/null +++ b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/ConsistentHash.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * Consistent hash implementation, use {@link HashNode} as physical node. + * @param hash node + * @author zhuoyu.sjw + * @version $Id : ConsistentHash.java, v 0.1 2016-08-24 11:10 zhuoyu.sjw Exp $$ + */ +public class ConsistentHash { + + /** character used to separate virtual nodes */ + private static final char SIGN = '#'; + + /** number of virtual nodes for one real node */ + private final int numberOfReplicas; + + /** real nodes */ + private Set realNodes; + + /** hash function */ + private final HashFunction hashFunction; + + /** */ + private final SortedMap circle = new TreeMap<>(); + + /** + * Instantiates a new Consistent hash. + * + * @param numberOfReplicas the number of replicas + * @param nodes the nodes + */ + public ConsistentHash(int numberOfReplicas, Collection nodes) { + this(new MD5HashFunction(), numberOfReplicas, nodes); + } + + /** + * Instantiates a new Consistent hash. + * + * @param hashFunction the hash function + * @param numberOfReplicas the number of replicas + * @param nodes the nodes + */ + public ConsistentHash(HashFunction hashFunction, int numberOfReplicas, Collection nodes) { + this.realNodes = new HashSet<>(); + this.hashFunction = hashFunction; + this.numberOfReplicas = numberOfReplicas; + for (T node : nodes) { + addNode(node); + } + } + + /** + * Add a new node to the consistent hash + * + * This is not thread safe. + * @param node the node + */ + private void addNode(T node) { + realNodes.add(node); + for (int i = 0; i < numberOfReplicas; i++) { + // The string addition forces each replica to have different hash + circle.put(hashFunction.hash(node.getNodeName() + SIGN + i), node); + } + } + + /** + * This returns the closest node for the object. If the object is the node it + * should be an exact hit, but if it is a value traverse to find closest + * subsequent node. + * @param key the key + * @return node for + */ + public T getNodeFor(Object key) { + if (circle.isEmpty()) { + return null; + } + int hash = hashFunction.hash(key); + T node = circle.get(hash); + + if (node == null) { + // inexact match -- find the next value in the circle + SortedMap tailMap = circle.tailMap(hash); + hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey(); + node = circle.get(hash); + } + return node; + } + + /** + * This returns the closest n unique nodes in order for the object. + * + * This will return a list that has all nodes if n > number of nodes. + * + * @param key the key + * @param n the n + * @return the n unique nodes for + */ + public List getNUniqueNodesFor(Object key, int n) { + if (circle.isEmpty()) { + return Collections.emptyList(); + } + + if (n > realNodes.size()) { + n = realNodes.size(); + } + + List list = new ArrayList<>(n); + int hash = hashFunction.hash(key); + for (int i = 0; i < n; i++) { + if (!circle.containsKey(hash)) { + // go to next element. + SortedMap tailMap = circle.tailMap(hash); + hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey(); + } + T candidate = circle.get(hash); + if (!list.contains(candidate)) { + list.add(candidate); + } else { + i--; // try again. + } + // find the next element in the circle + hash++; + } + return list; + } +} diff --git a/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashFunction.java b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashFunction.java new file mode 100644 index 000000000..204376705 --- /dev/null +++ b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashFunction.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +/** + * Hash Function + * @author zhuoyu.sjw + * @version $Id: HashFunction.java, v 0.1 2016-11-01 15:19 zhuoyu.sjw Exp $$ + */ +public interface HashFunction { + + /** + * return object's int hashCode + * @param o object + * @return int hashCode + */ + int hash(Object o); +} diff --git a/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashNode.java b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashNode.java new file mode 100644 index 000000000..684f8541b --- /dev/null +++ b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/HashNode.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +/** + * The interface Hash node. + * @author zhuoyu.sjw + * @version $Id : HashNode.java, v 0.1 2016-11-01 15:30 zhuoyu.sjw Exp $$ + */ +public interface HashNode { + + /** + * Gets node name. + * + * @return node name + */ + String getNodeName(); +} diff --git a/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MD5HashFunction.java b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MD5HashFunction.java new file mode 100644 index 000000000..0959c621b --- /dev/null +++ b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MD5HashFunction.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +import java.nio.charset.Charset; + +/** + * MD5 hash function + * @author zhuoyu.sjw + * @version $Id: MD5HashFunction.java, v 0.1 2016-11-01 15:19 zhuoyu.sjw Exp $$ + */ +public class MD5HashFunction implements HashFunction { + + /** + * Default charset of UTF-8 + */ + private static final Charset UTF8 = Charset.forName("UTF-8"); + + /** + * Instantiates a new MD5 hash function. + */ + public MD5HashFunction() { + } + + /** + * @see HashFunction#hash(Object) + */ + @Override + public int hash(Object s) { + byte[] hash = MessageDigests.md5().digest(s.toString().getBytes(UTF8)); + + // HACK just take the first 4 digits and make it an integer. + // apparently this is what other algorithms use to turn it into an int + // value. + + int h0 = (hash[0] & 0xFF); + int h1 = (hash[1] & 0xFF) << 8; + int h2 = (hash[2] & 0xFF) << 16; + int h3 = (hash[3] & 0xFF) << 24; + + return h0 + h1 + h2 + h3; + } + +} diff --git a/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MessageDigests.java b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MessageDigests.java new file mode 100644 index 000000000..34621abcd --- /dev/null +++ b/server/consistency/src/main/java/com/alipay/sofa/registry/consistency/hash/MessageDigests.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * This MessageDigests class provides convenience methods for obtaining + * thread local {@link MessageDigest} instances for MD5, SHA-1, and + * SHA-256 message digests. + * + * @author zhuoyu.sjw + * @version $Id: MessageDigests.java, v 0.1 2016-11-01 16:29 zhuoyu.sjw Exp $$ + */ +public final class MessageDigests { + + /** MD5 */ + private static final ThreadLocal MD5_DIGEST = createThreadLocalMessageDigest("MD5"); + /** SHA_1 */ + private static final ThreadLocal SHA_1_DIGEST = createThreadLocalMessageDigest("SHA-1"); + /** SHA_256 */ + private static final ThreadLocal SHA_256_DIGEST = createThreadLocalMessageDigest("SHA-256"); + /** */ + private static final char[] HEX_DIGITS = "0123456789abcdef" + .toCharArray(); + + /** + * Create thread local message digest thread local. + * + * @param digest the digest + * @return thread local + */ + private static ThreadLocal createThreadLocalMessageDigest(final String digest) { + return ThreadLocal.withInitial(() -> { + try { + return MessageDigest.getInstance(digest); + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException( + "unexpected exception creating MessageDigest instance for [" + digest + "]", + e); + } + }); + } + + /** + * + * @return a thread local MD5 {@link MessageDigest} instance + */ + public static MessageDigest md5() { + return get(MD5_DIGEST); + } + + /** + * + * @return a thread local SHA_1 {@link MessageDigest} instance + */ + public static MessageDigest sha1() { + return get(SHA_1_DIGEST); + } + + /** + * + * @return a thread local SHA_256 {@link MessageDigest} instance + */ + public static MessageDigest sha256() { + return get(SHA_256_DIGEST); + } + + /** + * get and reset thread local {@link MessageDigest} instance + * @param messageDigest threadLocalMessageDigest + * @return a thread local {@link MessageDigest} instance + */ + private static MessageDigest get(ThreadLocal messageDigest) { + MessageDigest instance = messageDigest.get(); + instance.reset(); + return instance; + } + + /** + * Format a byte array as a hex string. + * + * @param bytes the input to be represented as hex. + * @return a hex representation of the input as a String. + */ + public static String toHexString(byte[] bytes) { + StringBuilder sb = new StringBuilder(2 * bytes.length); + + for (byte b : bytes) { + sb.append(HEX_DIGITS[b >> 4 & 0xf]).append(HEX_DIGITS[b & 0xf]); + } + + return sb.toString(); + } + +} diff --git a/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/BackupTest.java b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/BackupTest.java new file mode 100644 index 000000000..8ce57af6f --- /dev/null +++ b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/BackupTest.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: BackupTest.java, v 0.1 2018-03-20 12:12 shangyu.wh Exp $ + */ +public class BackupTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConsistentHashTest.class); + + /** + * Sets up. + * + * @throws Exception the exception + */ + @Before + public void setUp() { + List testNodes = new ArrayList<>(); + testNodes.add(new TestNode("A")); + testNodes.add(new TestNode("B")); + testNodes.add(new TestNode("C")); + testNodes.add(new TestNode("D")); + testNodes.add(new TestNode("E")); + testNodes.add(new TestNode("F")); + } + + @Test + public void getNodeFor() { + String key1 = "test"; + String key2 = "dataID"; + Map> map = new HashMap<>(); + map.put(key1, Arrays.asList("1,2,3,4,5,6".split(","))); + map.put(key2, Arrays.asList("5,6,7,8,9,0".split(","))); + + List list1 = Arrays.asList(new TestNode("A"), new TestNode("B"), + new TestNode("C"), new TestNode("D"), new TestNode("E"), new TestNode("F")); + + List list2 = Arrays.asList(new TestNode("A"), new TestNode("B"), + new TestNode("C"), new TestNode("E"), new TestNode("F")); + + printTest(list1, list2, key2, map.get(key2)); + } + + private void printTest(List before, List after, String dataId, + List dataList) { + List testNodes1 = getCalculateTestNodes(before, dataId, before.size()); + List testNodes2 = getCalculateTestNodes(after, dataId, after.size()); + + Map> testNodeMap = bindData(dataList, + getCalculateTestNodes(before, dataId, 3)); + + LOGGER.info("data map {}", testNodeMap); + + binddataDec(testNodes1, testNodes2, testNodeMap); + } + + private void binddataDec(List before, List after, + Map> testNodeMap) { + List subTestNodesBefore = new ArrayList<>(before.subList(0, 3)); + List subTestNodesAfter = new ArrayList<>(after.subList(0, 3)); + TestNode master = subTestNodesBefore.get(0); + if (subTestNodesAfter.contains(master)) { + master = subTestNodesBefore.get(0); + } else { + master = subTestNodesAfter.get(0); + } + if (subTestNodesAfter.removeAll(subTestNodesBefore)) { + List dataMaster = testNodeMap.get(master); + for (TestNode testNode : subTestNodesAfter) { + if (testNodeMap.get(testNode) == null) { + testNodeMap.put(testNode, dataMaster); + } else { + throw new RuntimeException("data error!"); + } + } + } + List newBefore = new ArrayList<>(before); + if (newBefore.removeAll(after)) { + for (TestNode testNode : newBefore) { + + testNodeMap.remove(testNode); + } + } + LOGGER.info("after map:{}", testNodeMap); + + } + + private List getCalculateTestNodes(List in, String dataId, int num) { + ConsistentHash consistentHash = new ConsistentHash<>(100, in); + List ret; + if (num > 0) { + ret = consistentHash.getNUniqueNodesFor(dataId, num); + } else { + ret = Arrays.asList(consistentHash.getNodeFor(dataId)); + } + + LOGGER.info("getNUniqueNodesFor dataId: {}, result: {}", dataId, ret); + return ret; + } + + private Map> bindData(List dataList, List nodelist) { + Map> map = new LinkedHashMap<>(); + nodelist.forEach((testNode) -> map.put(testNode, dataList)); + return map; + } +} \ No newline at end of file diff --git a/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/ConsistentHashTest.java b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/ConsistentHashTest.java new file mode 100644 index 000000000..8c9e8250b --- /dev/null +++ b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/ConsistentHashTest.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * The type Consistent hash test. + * @author zhuoyu.sjw + * @version $Id : ConsistentHashTest.java, v 0.1 2018-03-07 11:24 zhuoyu.sjw Exp $$ + */ +public class ConsistentHashTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ConsistentHashTest.class); + + private ConsistentHash consistentHash; + + private List testNodes; + + /** + * Sets up. + * + * @throws Exception the exception + */ + @Before + public void setUp() throws Exception { + testNodes = new ArrayList<>(); + testNodes.add(new TestNode("10.10.10.1")); + testNodes.add(new TestNode("10.10.10.2")); + testNodes.add(new TestNode("10.10.10.3")); + testNodes.add(new TestNode("10.10.10.4")); + testNodes.add(new TestNode("10.10.10.5")); + consistentHash = new ConsistentHash(100, testNodes); + } + + /** + * Gets node for. + */ + @Test + public void getNodeFor() { + String key = "test"; + TestNode testNode = consistentHash.getNodeFor(key); + + LOGGER.info("getNodeFor key: {}, result: {}", key, testNode); + + assertNotNull(testNode); + assertTrue(testNodes.contains(testNode)); + } + + /** + * Gets n unique nodes for. + */ + @Test + public void getNUniqueNodesFor() { + String key = "test"; + List uniqueNodes = consistentHash.getNUniqueNodesFor(key, 3); + + LOGGER.info("getNUniqueNodesFor key: {}, result: {}", key, uniqueNodes); + + assertNotNull(uniqueNodes); + assertEquals(uniqueNodes.size(), new HashSet<>(uniqueNodes).size()); + } + + /** + * Gets n unique nodes for real nodes size. + */ + @Test + public void getNUniqueNodesForRealNodesSize() { + String key = "test"; + List uniqueNodes = consistentHash.getNUniqueNodesFor(key, testNodes.size()); + + LOGGER.info("getNUniqueNodesForRealNodesSize key: {}, result: {}", key, uniqueNodes); + + assertNotNull(uniqueNodes); + assertEquals(testNodes.size(), new HashSet<>(uniqueNodes).size()); + } + + /** + * Gets n unique nodes for more than real nodes size. + */ + @Test + public void getNUniqueNodesForMoreThanRealNodesSize() { + String key = "test"; + List uniqueNodes = consistentHash.getNUniqueNodesFor(key, testNodes.size() + 1); + + LOGGER + .info("getNUniqueNodesForMoreThanRealNodesSize key: {}, result: {}", key, uniqueNodes); + + assertNotNull(uniqueNodes); + assertEquals(testNodes.size(), new HashSet<>(uniqueNodes).size()); + } + + /** + * Gets n unique nodes for zero. + */ + @Test + public void getNUniqueNodesForZero() { + String key = "test"; + List uniqueNodes = consistentHash.getNUniqueNodesFor(key, 0); + + LOGGER.info("getNUniqueNodesForZero key: {}, result: {}", key, uniqueNodes); + + assertNotNull(uniqueNodes); + assertTrue(uniqueNodes.isEmpty()); + } +} \ No newline at end of file diff --git a/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/MessageDigestsTest.java b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/MessageDigestsTest.java new file mode 100644 index 000000000..8fd823dd5 --- /dev/null +++ b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/MessageDigestsTest.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +import org.junit.Test; + +import java.security.MessageDigest; + +import static org.junit.Assert.assertEquals; + +/** + * The type Message digests test. + * @author zhuoyu.sjw + * @version $Id : MessageDigestsTest.java, v 0.1 2018-03-07 11:19 zhuoyu.sjw Exp $$ + */ +public class MessageDigestsTest { + + /** + * Md 5. + */ + @Test + public void md5() { + assertHash("d41d8cd98f00b204e9800998ecf8427e", "", MessageDigests.md5()); + assertHash("900150983cd24fb0d6963f7d28e17f72", "abc", MessageDigests.md5()); + assertHash("8215ef0796a20bcaaae116d3876c664a", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", MessageDigests.md5()); + assertHash("7707d6ae4e027c70eea2a935c2296f21", + new String(new char[1000000]).replace("\0", "a"), MessageDigests.md5()); + assertHash("9e107d9d372bb6826bd81d3542a419d6", + "The quick brown fox jumps over the lazy dog", MessageDigests.md5()); + assertHash("1055d3e698d289f2af8663725127bd4b", + "The quick brown fox jumps over the lazy cog", MessageDigests.md5()); + } + + /** + * Sha 1. + */ + @Test + public void sha1() { + assertHash("da39a3ee5e6b4b0d3255bfef95601890afd80709", "", MessageDigests.sha1()); + assertHash("a9993e364706816aba3e25717850c26c9cd0d89d", "abc", MessageDigests.sha1()); + assertHash("84983e441c3bd26ebaae4aa1f95129e5e54670f1", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", MessageDigests.sha1()); + assertHash("34aa973cd4c4daa4f61eeb2bdbad27316534016f", + new String(new char[1000000]).replace("\0", "a"), MessageDigests.sha1()); + assertHash("2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + "The quick brown fox jumps over the lazy dog", MessageDigests.sha1()); + assertHash("de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", + "The quick brown fox jumps over the lazy cog", MessageDigests.sha1()); + } + + /** + * Sha 256. + */ + @Test + public void sha256() { + assertHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "", + MessageDigests.sha256()); + assertHash("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc", + MessageDigests.sha256()); + assertHash("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", MessageDigests.sha256()); + assertHash("cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", new String( + new char[1000000]).replace("\0", "a"), MessageDigests.sha256()); + assertHash("d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + "The quick brown fox jumps over the lazy dog", MessageDigests.sha256()); + assertHash("e4c4d8f3bf76b692de791a173e05321150f7a345b46484fe427f6acc7ecc81be", + "The quick brown fox jumps over the lazy cog", MessageDigests.sha256()); + } + + private void assertHash(String expected, String test, MessageDigest messageDigest) { + String actual = MessageDigests.toHexString(messageDigest.digest(test.getBytes())); + assertEquals(expected, actual); + } +} \ No newline at end of file diff --git a/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/TestNode.java b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/TestNode.java new file mode 100644 index 000000000..513b5af28 --- /dev/null +++ b/server/consistency/src/test/java/com/alipay/sofa/registry/consistency/hash/TestNode.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.consistency.hash; + +/** + * The type Test node. + * @author zhuoyu.sjw + * @version $Id : TestNode.java, v 0.1 2018-03-07 11:23 zhuoyu.sjw Exp $$ + */ +public class TestNode implements HashNode { + + private String nodeName; + + /** + * Instantiates a new Test node. + * + * @param nodeName the node name + */ + public TestNode(String nodeName) { + this.nodeName = nodeName; + } + + /** + * Gets node name. + * + * @return the node name + */ + @Override + public String getNodeName() { + return nodeName; + } + + /** + * Equals boolean. + * + * @param o the o + * @return the boolean + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TestNode)) { + return false; + } + + TestNode testNode = (TestNode) o; + + return nodeName != null ? nodeName.equals(testNode.nodeName) : testNode.nodeName == null; + } + + /** + * Hash code int. + * + * @return the int + */ + @Override + public int hashCode() { + return nodeName != null ? nodeName.hashCode() : 0; + } + + /** + * To string string. + * + * @return the string + */ + @Override + public String toString() { + return "TestNode{" + "nodeName='" + nodeName + '\'' + '}'; + } +} diff --git a/server/distribution/data/bin/shutdown.bat b/server/distribution/data/bin/shutdown.bat new file mode 100755 index 000000000..ad188d974 --- /dev/null +++ b/server/distribution/data/bin/shutdown.bat @@ -0,0 +1,21 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +echo killing registry-data server... + +for /f "tokens=1" %%i in ('jps -m ^| find "registry-data"') do ( taskkill /F /PID %%i ) + +echo Done! diff --git a/server/distribution/data/bin/shutdown.sh b/server/distribution/data/bin/shutdown.sh new file mode 100644 index 000000000..a8019eb7f --- /dev/null +++ b/server/distribution/data/bin/shutdown.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo "killing registry-data server..." +pids=`ps aux | grep java | grep registry-data | awk '{print $2;}'` +for pid in "${pids[@]}" +do + if [ -z "$pid" ]; then + continue; + fi +kill $pid +done +echo "Done!" \ No newline at end of file diff --git a/server/distribution/data/bin/startup.bat b/server/distribution/data/bin/startup.bat new file mode 100755 index 000000000..69e1c2213 --- /dev/null +++ b/server/distribution/data/bin/startup.bat @@ -0,0 +1,53 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +rem constants +set APP_NAME=data +set BASE_DIR=%~dp0 +set BASE_DIR=%BASE_DIR:~0,-5% +set APP_JAR=%BASE_DIR%\registry-%APP_NAME%.jar + +rem app conf +set "JAVA_OPT=%JAVA_OPT% -Dregistry.%APP_NAME%.home=%BASE_DIR%" +set "JAVA_OPT=%JAVA_OPT% -Dspring.config.location=%BASE_DIR%\conf\application.properties" + +rem set user.home +set "JAVA_OPT=%JAVA_OPT% -Duser.home=%BASE_DIR%" + +rem springboot conf +set "SPRINGBOOT_OPTS=%SPRINGBOOT_OPTS% --logging.config=%BASE_DIR%\conf\logback-spring.xml" + +rem heap size +set HEAP_MAX=512 +set HEAP_NEW=256 +set "JAVA_OPT=%JAVA_OPT% -server -Xms%HEAP_MAX%m -Xmx%HEAP_MAX%m -Xmn%HEAP_NEW%m -Xss256k" + +rem gc option +if not exist %BASE_DIR%\logs md %BASE_DIR%\logs +set "JAVA_OPTS=%JAVA_OPT% -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:%BASE_DIR%\logs\registry-%APP_NAME%-gc.log -verbose:gc" +set "JAVA_OPTS=%JAVA_OPT% -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%BASE_DIR%\logs -XX:ErrorFile=%BASE_DIR%\logs\registry-%APP_NAME%-hs_err_pid%p.log" +set "JAVA_OPTS=%JAVA_OPT% -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +set "JAVA_OPTS=%JAVA_OPT% -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +rem rm raftData +if exist %BASE_DIR%\raftData rd /s /Q %BASE_DIR%\raftData + +rem start +set STD_OUT=%BASE_DIR%\logs\registry-%APP_NAME%-std.out +if exist %STD_OUT% del %STD_OUT% +echo registry-%APP_NAME% is starting, you can check the %STD_OUT% for more details +echo "Command: java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS%" > %STD_OUT% +java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS% >> %STD_OUT% 2>&1 diff --git a/server/distribution/data/bin/startup.sh b/server/distribution/data/bin/startup.sh new file mode 100644 index 000000000..c59697da0 --- /dev/null +++ b/server/distribution/data/bin/startup.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +# Copyright 1999-2018 Alibaba Group Holding Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# constants +APP_NAME="data" +BASE_DIR=`cd $(dirname $0)/..; pwd` +APP_JAR="${BASE_DIR}/registry-${APP_NAME}.jar" + +# app conf +JAVA_OPTS="$JAVA_OPTS -Dregistry.${APP_NAME}.home=${BASE_DIR}" +JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=${BASE_DIR}/conf/application.properties" + +# set user.home +JAVA_OPTS="$JAVA_OPTS -Duser.home=${BASE_DIR}" + +# springboot conf +SPRINGBOOT_OPTS="${SPRINGBOOT_OPTS} --logging.config=${BASE_DIR}/conf/logback-spring.xml" + +# heap size +HEAP_MAX=512 +HEAP_NEW=256 +JAVA_OPTS="$JAVA_OPTS -server -Xms${HEAP_MAX}m -Xmx${HEAP_MAX}m -Xmn${HEAP_NEW}m -Xss256k" + +# gc option +mkdir -p "${BASE_DIR}/logs" +JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${BASE_DIR}/logs/registry-${APP_NAME}-gc.log -verbose:gc" +JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs -XX:ErrorFile=${BASE_DIR}/logs/registry-${APP_NAME}-hs_err_pid%p.log" +JAVA_OPTS="$JAVA_OPTS -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +JAVA_OPTS="$JAVA_OPTS -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +# start +STD_OUT="${BASE_DIR}/logs/registry-${APP_NAME}-std.out" +rm -f $STD_OUT +echo "Command: java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS}" > $STD_OUT +java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS} >> "$STD_OUT" 2>&1 & +PID=$! +echo "registry-${APP_NAME}(pid is $PID) is starting, you can check the $STD_OUT for more details" \ No newline at end of file diff --git a/server/distribution/data/conf/application.properties b/server/distribution/data/conf/application.properties new file mode 100644 index 000000000..f5ed68c49 --- /dev/null +++ b/server/distribution/data/conf/application.properties @@ -0,0 +1,3 @@ +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter +data.server.numberOfReplicas=1 \ No newline at end of file diff --git a/server/distribution/data/conf/application.properties.example b/server/distribution/data/conf/application.properties.example new file mode 100644 index 000000000..055d17ff6 --- /dev/null +++ b/server/distribution/data/conf/application.properties.example @@ -0,0 +1,17 @@ +spring.main.banner-mode=LOG +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter + +data.server.logging.level=INFO +data.server.logging.home=/home/admin/logs/registry/data +data.server.port=9620 +data.server.syncDataPort=9621 +data.server.httpServerPort=9622 +data.server.queueCount=4 +data.server.queueSize=10240 +data.server.notifyIntervalMs=500 +data.server.rpcTimeout=3000 +data.server.metaServerPort=9611 +data.server.storeNodes=3 +data.server.numberOfReplicas=1000 + diff --git a/server/distribution/data/distribution-data.xml b/server/distribution/data/distribution-data.xml new file mode 100644 index 000000000..b6a029b0e --- /dev/null +++ b/server/distribution/data/distribution-data.xml @@ -0,0 +1,48 @@ + + + registry-data + false + + dir + tgz + + + + + conf/** + + + + + bin/* + + 0755 + + + + + ../../server/data/target/registry-server-data-executable.jar + / + registry-data.jar + + + ../../server/data/src/main/resources/logback-spring.xml + /conf + logback-spring.xml + + + ../version + / + version_${project.version} + + + + + + true + + com.alipay.sofa:registry-server-data + + + + \ No newline at end of file diff --git a/server/distribution/data/pom.xml b/server/distribution/data/pom.xml new file mode 100644 index 000000000..7888667d2 --- /dev/null +++ b/server/distribution/data/pom.xml @@ -0,0 +1,52 @@ + + + + com.alipay.sofa + registry-distribution + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-distribution-data + pom + + + ../../../ + + + + + com.alipay.sofa + registry-server-data + + + + + + + maven-assembly-plugin + 3.0.0 + + + distribution-data + package + + single + + + false + + distribution-data.xml + + + + + + + registry-data + + + diff --git a/server/distribution/integration/bin/shutdown.bat b/server/distribution/integration/bin/shutdown.bat new file mode 100755 index 000000000..f53707f05 --- /dev/null +++ b/server/distribution/integration/bin/shutdown.bat @@ -0,0 +1,21 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +echo killing registry-integration server... + +for /f "tokens=1" %%i in ('jps -m ^| find "registry-integration"') do ( taskkill /F /PID %%i ) + +echo Done! diff --git a/server/distribution/integration/bin/shutdown.sh b/server/distribution/integration/bin/shutdown.sh new file mode 100644 index 000000000..5be5f1333 --- /dev/null +++ b/server/distribution/integration/bin/shutdown.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo "killing registry-integration server..." +pids=`ps aux | grep java | grep registry-integration | awk '{print $2;}'` +for pid in "${pids[@]}" +do + if [ -z "$pid" ]; then + continue; + fi +kill $pid +done +echo "Done!" \ No newline at end of file diff --git a/server/distribution/integration/bin/startup.bat b/server/distribution/integration/bin/startup.bat new file mode 100755 index 000000000..f8992ec00 --- /dev/null +++ b/server/distribution/integration/bin/startup.bat @@ -0,0 +1,53 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +rem constants +set APP_NAME=integration +set BASE_DIR=%~dp0 +set BASE_DIR=%BASE_DIR:~0,-5% +set APP_JAR=%BASE_DIR%\registry-%APP_NAME%.jar + +rem app conf +set "JAVA_OPT=%JAVA_OPT% -Dregistry.%APP_NAME%.home=%BASE_DIR%" +set "JAVA_OPT=%JAVA_OPT% -Dspring.config.location=%BASE_DIR%\conf\application.properties" + +rem set user.home +set "JAVA_OPT=%JAVA_OPT% -Duser.home=%BASE_DIR%" + +rem springboot conf +set "SPRINGBOOT_OPTS=%SPRINGBOOT_OPTS% --logging.config=%BASE_DIR%\conf\logback-spring.xml" + +rem heap size +set HEAP_MAX=512 +set HEAP_NEW=256 +set "JAVA_OPT=%JAVA_OPT% -server -Xms%HEAP_MAX%m -Xmx%HEAP_MAX%m -Xmn%HEAP_NEW%m -Xss256k" + +rem gc option +if not exist %BASE_DIR%\logs md %BASE_DIR%\logs +set "JAVA_OPTS=%JAVA_OPT% -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:%BASE_DIR%\logs\registry-%APP_NAME%-gc.log -verbose:gc" +set "JAVA_OPTS=%JAVA_OPT% -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%BASE_DIR%\logs -XX:ErrorFile=%BASE_DIR%\logs\registry-%APP_NAME%-hs_err_pid%p.log" +set "JAVA_OPTS=%JAVA_OPT% -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +set "JAVA_OPTS=%JAVA_OPT% -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +rem rm raftData +if exist %BASE_DIR%\raftData rd /s /Q %BASE_DIR%\raftData + +rem start +set STD_OUT=%BASE_DIR%\logs\registry-%APP_NAME%-std.out +if exist %STD_OUT% del %STD_OUT% +echo registry-%APP_NAME% is starting, you can check the %STD_OUT% for more details +echo "Command: java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS%" > %STD_OUT% +java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS% >> %STD_OUT% 2>&1 diff --git a/server/distribution/integration/bin/startup.sh b/server/distribution/integration/bin/startup.sh new file mode 100644 index 000000000..653e4b55e --- /dev/null +++ b/server/distribution/integration/bin/startup.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Copyright 1999-2018 Alibaba Group Holding Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# constants +APP_NAME="integration" +BASE_DIR=`cd $(dirname $0)/..; pwd` +APP_JAR="${BASE_DIR}/registry-${APP_NAME}.jar" + +# app conf +JAVA_OPTS="$JAVA_OPTS -Dregistry.${APP_NAME}.home=${BASE_DIR}" +JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=${BASE_DIR}/conf/application.properties" + +# set user.home +JAVA_OPTS="$JAVA_OPTS -Duser.home=${BASE_DIR}" + +# springboot conf +SPRINGBOOT_OPTS="${SPRINGBOOT_OPTS} --logging.config=${BASE_DIR}/conf/logback-spring.xml" + +# heap size +HEAP_MAX=512 +HEAP_NEW=256 +JAVA_OPTS="$JAVA_OPTS -server -Xms${HEAP_MAX}m -Xmx${HEAP_MAX}m -Xmn${HEAP_NEW}m -Xss256k" + +# gc option +mkdir -p "${BASE_DIR}/logs" +JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${BASE_DIR}/logs/registry-${APP_NAME}-gc.log -verbose:gc" +JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs -XX:ErrorFile=${BASE_DIR}/logs/registry-${APP_NAME}-hs_err_pid%p.log" +JAVA_OPTS="$JAVA_OPTS -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +JAVA_OPTS="$JAVA_OPTS -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +# rm raftData +rm -rf ${BASE_DIR}/raftData/ + +# start +STD_OUT="${BASE_DIR}/logs/registry-${APP_NAME}-std.out" +rm -f $STD_OUT +echo "Command: java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS}" > $STD_OUT +java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS} >> "$STD_OUT" 2>&1 & +PID=$! +echo "registry-${APP_NAME}(pid is $PID) is starting, you can check the $STD_OUT for more details" \ No newline at end of file diff --git a/server/distribution/integration/conf/application.properties b/server/distribution/integration/conf/application.properties new file mode 100644 index 000000000..8f8502ca8 --- /dev/null +++ b/server/distribution/integration/conf/application.properties @@ -0,0 +1,3 @@ +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter +nodes.localRegion=DEFAULT_ZONE diff --git a/server/distribution/integration/conf/application.properties.example b/server/distribution/integration/conf/application.properties.example new file mode 100644 index 000000000..3ecb93291 --- /dev/null +++ b/server/distribution/integration/conf/application.properties.example @@ -0,0 +1,53 @@ +spring.main.banner-mode=LOG +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter +nodes.localRegion=DEFAULT_ZONE +server.logging.home=/home/admin/logs/registry + +meta.server.logging.level=INFO +meta.server.logging.home=/home/admin/logs/registry/meta +meta.server.sessionServerPort=9610 +meta.server.dataServerPort=9611 +meta.server.metaServerPort=9612 +meta.server.raftServerPort=9614 +meta.server.httpServerPort=9615 +meta.server.raftGroup=MetaServerRaftGroup + +data.server.logging.level=INFO +data.server.logging.home=/home/admin/logs/registry/data +data.server.port=9620 +data.server.syncDataPort=9621 +data.server.httpServerPort=9622 +data.server.queueCount=4 +data.server.queueSize=10240 +data.server.notifyIntervalMs=500 +data.server.rpcTimeout=3000 +data.server.metaServerPort=9611 +data.server.storeNodes=3 +data.server.numberOfReplicas=1000 + +session.server.logging.level=INFO +session.server.logging.home=/home/admin/logs/registry/session +session.server.serverPort=9600 +session.server.serverSyncPort=9601 +session.server.httpServerPort=9603 +session.server.metaServerPort=9610 +session.server.dataServerPort=9620 +session.server.serverDescription=dev session server +session.server.sessionServerRegion=DEFAULT_ZONE +session.server.sessionServerDataCenter=DefaultDataCenter +session.server.syncHeartbeat.fixedDelay=30000 +session.server.syncExceptionData.fixedDelay=30000 +session.server.printTask.fixedDelay=30000 +session.server.schedulerCheckVersionTimeout=3 +session.server.schedulerCheckVersionFirstDelay=3 +session.server.schedulerCheckVersionExpBackOffBound=10 +session.server.schedulerHeartbeatTimeout=30 +session.server.schedulerHeartbeatFirstDelay=30 +session.server.schedulerHeartbeatExpBackOffBound=10 +session.server.schedulerFetchDataTimeout=3 +session.server.schedulerFetchDataFirstDelay=3 +session.server.schedulerFetchDataExpBackOffBound=10 +session.server.invalidForeverZones=; +session.server.invalidIgnoreDataidRegex= +session.server.pushEmptyDataDataIdPrefixes= \ No newline at end of file diff --git a/server/distribution/integration/distribution-integration.xml b/server/distribution/integration/distribution-integration.xml new file mode 100644 index 000000000..effdaf0fd --- /dev/null +++ b/server/distribution/integration/distribution-integration.xml @@ -0,0 +1,48 @@ + + + registry-integration + false + + dir + tgz + + + + + conf/** + + + + + bin/* + + 0755 + + + + + ../../server/integration/target/registry-server-integration-executable.jar + / + registry-integration.jar + + + ../../server/integration/src/main/resources/logback-spring.xml + /conf + logback-spring.xml + + + ../version + / + version_${project.version} + + + + + + true + + com.alipay.sofa:registry-server-integration + + + + \ No newline at end of file diff --git a/server/distribution/integration/pom.xml b/server/distribution/integration/pom.xml new file mode 100644 index 000000000..bd78f2390 --- /dev/null +++ b/server/distribution/integration/pom.xml @@ -0,0 +1,51 @@ + + + + com.alipay.sofa + registry-distribution + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + registry-distribution-integration + pom + + + ../../../ + + + + + com.alipay.sofa + registry-server-integration + + + + + + + maven-assembly-plugin + 3.0.0 + + + distribution-integration + package + + single + + + false + + distribution-integration.xml + + + + + + + registry-integration + + + diff --git a/server/distribution/meta/bin/shutdown.bat b/server/distribution/meta/bin/shutdown.bat new file mode 100755 index 000000000..526acd4cd --- /dev/null +++ b/server/distribution/meta/bin/shutdown.bat @@ -0,0 +1,21 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +echo killing registry-meta server... + +for /f "tokens=1" %%i in ('jps -m ^| find "registry-meta"') do ( taskkill /F /PID %%i ) + +echo Done! diff --git a/server/distribution/meta/bin/shutdown.sh b/server/distribution/meta/bin/shutdown.sh new file mode 100644 index 000000000..73a9300e9 --- /dev/null +++ b/server/distribution/meta/bin/shutdown.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo "killing registry-meta server..." +pids=`ps aux | grep java | grep registry-meta | awk '{print $2;}'` +for pid in "${pids[@]}" +do + if [ -z "$pid" ]; then + continue; + fi +kill $pid +done +echo "Done!" \ No newline at end of file diff --git a/server/distribution/meta/bin/startup.bat b/server/distribution/meta/bin/startup.bat new file mode 100755 index 000000000..ff3ca84ff --- /dev/null +++ b/server/distribution/meta/bin/startup.bat @@ -0,0 +1,53 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +rem constants +set APP_NAME=meta +set BASE_DIR=%~dp0 +set BASE_DIR=%BASE_DIR:~0,-5% +set APP_JAR=%BASE_DIR%\registry-%APP_NAME%.jar + +rem app conf +set "JAVA_OPT=%JAVA_OPT% -Dregistry.%APP_NAME%.home=%BASE_DIR%" +set "JAVA_OPT=%JAVA_OPT% -Dspring.config.location=%BASE_DIR%\conf\application.properties" + +rem set user.home +set "JAVA_OPT=%JAVA_OPT% -Duser.home=%BASE_DIR%" + +rem springboot conf +set "SPRINGBOOT_OPTS=%SPRINGBOOT_OPTS% --logging.config=%BASE_DIR%\conf\logback-spring.xml" + +rem heap size +set HEAP_MAX=512 +set HEAP_NEW=256 +set "JAVA_OPT=%JAVA_OPT% -server -Xms%HEAP_MAX%m -Xmx%HEAP_MAX%m -Xmn%HEAP_NEW%m -Xss256k" + +rem gc option +if not exist %BASE_DIR%\logs md %BASE_DIR%\logs +set "JAVA_OPTS=%JAVA_OPT% -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:%BASE_DIR%\logs\registry-%APP_NAME%-gc.log -verbose:gc" +set "JAVA_OPTS=%JAVA_OPT% -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%BASE_DIR%\logs -XX:ErrorFile=%BASE_DIR%\logs\registry-%APP_NAME%-hs_err_pid%p.log" +set "JAVA_OPTS=%JAVA_OPT% -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +set "JAVA_OPTS=%JAVA_OPT% -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +rem rm raftData +if exist %BASE_DIR%\raftData rd /s /Q %BASE_DIR%\raftData + +rem start +set STD_OUT=%BASE_DIR%\logs\registry-%APP_NAME%-std.out +if exist %STD_OUT% del %STD_OUT% +echo registry-%APP_NAME% is starting, you can check the %STD_OUT% for more details +echo "Command: java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS%" > %STD_OUT% +java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS% >> %STD_OUT% 2>&1 diff --git a/server/distribution/meta/bin/startup.sh b/server/distribution/meta/bin/startup.sh new file mode 100644 index 000000000..4eb27fa74 --- /dev/null +++ b/server/distribution/meta/bin/startup.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +# Copyright 1999-2018 Alibaba Group Holding Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# constants +APP_NAME="meta" +BASE_DIR=`cd $(dirname $0)/..; pwd` +APP_JAR="${BASE_DIR}/registry-${APP_NAME}.jar" + +# app conf +JAVA_OPTS="$JAVA_OPTS -Dregistry.${APP_NAME}.home=${BASE_DIR}" +JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=${BASE_DIR}/conf/application.properties" + +# set user.home +JAVA_OPTS="$JAVA_OPTS -Duser.home=${BASE_DIR}" + +# springboot conf +SPRINGBOOT_OPTS="${SPRINGBOOT_OPTS} --logging.config=${BASE_DIR}/conf/logback-spring.xml" + +# heap size +HEAP_MAX=512 +HEAP_NEW=256 +JAVA_OPTS="$JAVA_OPTS -server -Xms${HEAP_MAX}m -Xmx${HEAP_MAX}m -Xmn${HEAP_NEW}m -Xss256k" + +# gc option +mkdir -p "${BASE_DIR}/logs" +JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${BASE_DIR}/logs/registry-${APP_NAME}-gc.log -verbose:gc" +JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs -XX:ErrorFile=${BASE_DIR}/logs/registry-${APP_NAME}-hs_err_pid%p.log" +JAVA_OPTS="$JAVA_OPTS -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +JAVA_OPTS="$JAVA_OPTS -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +# rm raftData +rm -rf ${BASE_DIR}/raftData/ + +# start +STD_OUT="${BASE_DIR}/logs/registry-${APP_NAME}-std.out" +rm -f $STD_OUT +echo "Command: java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS}" > $STD_OUT +java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS} >> "$STD_OUT" 2>&1 & +PID=$! +echo "registry-${APP_NAME}(pid is $PID) is starting, you can check the $STD_OUT for more details" \ No newline at end of file diff --git a/server/distribution/meta/conf/application.properties b/server/distribution/meta/conf/application.properties new file mode 100644 index 000000000..28027cb25 --- /dev/null +++ b/server/distribution/meta/conf/application.properties @@ -0,0 +1,2 @@ +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter \ No newline at end of file diff --git a/server/distribution/meta/conf/application.properties.example b/server/distribution/meta/conf/application.properties.example new file mode 100644 index 000000000..6580a80d6 --- /dev/null +++ b/server/distribution/meta/conf/application.properties.example @@ -0,0 +1,12 @@ +spring.main.banner-mode=LOG +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter + +meta.server.logging.level=INFO +meta.server.logging.home=/home/admin/logs/registry/meta +meta.server.sessionServerPort=9610 +meta.server.dataServerPort=9611 +meta.server.metaServerPort=9612 +meta.server.raftServerPort=9614 +meta.server.httpServerPort=9615 +meta.server.raftGroup=MetaServerRaftGroup diff --git a/server/distribution/meta/distribution-meta.xml b/server/distribution/meta/distribution-meta.xml new file mode 100644 index 000000000..29cf277c4 --- /dev/null +++ b/server/distribution/meta/distribution-meta.xml @@ -0,0 +1,48 @@ + + + registry-meta + false + + dir + tgz + + + + + conf/** + + + + + bin/* + + 0755 + + + + + ../../server/meta/target/registry-server-meta-executable.jar + / + registry-meta.jar + + + ../../server/meta/src/main/resources/logback-spring.xml + /conf + logback-spring.xml + + + ../version + / + version_${project.version} + + + + + + true + + com.alipay.sofa:registry-server-meta + + + + \ No newline at end of file diff --git a/server/distribution/meta/pom.xml b/server/distribution/meta/pom.xml new file mode 100644 index 000000000..d041961eb --- /dev/null +++ b/server/distribution/meta/pom.xml @@ -0,0 +1,52 @@ + + + + com.alipay.sofa + registry-distribution + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-distribution-meta + pom + + + ../../../ + + + + + com.alipay.sofa + registry-server-meta + + + + + + + maven-assembly-plugin + 3.0.0 + + + distribution-meta + package + + single + + + false + + distribution-meta.xml + + + + + + + registry-meta + + + diff --git a/server/distribution/pom.xml b/server/distribution/pom.xml new file mode 100644 index 000000000..773f6b8ff --- /dev/null +++ b/server/distribution/pom.xml @@ -0,0 +1,28 @@ + + + + + com.alipay.sofa + registry-server-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-distribution + pom + + + ../../ + + + + session + data + meta + integration + + + diff --git a/server/distribution/session/bin/shutdown.bat b/server/distribution/session/bin/shutdown.bat new file mode 100755 index 000000000..61429e0af --- /dev/null +++ b/server/distribution/session/bin/shutdown.bat @@ -0,0 +1,21 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +echo killing registry-session server... + +for /f "tokens=1" %%i in ('jps -m ^| find "registry-session"') do ( taskkill /F /PID %%i ) + +echo Done! diff --git a/server/distribution/session/bin/shutdown.sh b/server/distribution/session/bin/shutdown.sh new file mode 100644 index 000000000..1aee4f450 --- /dev/null +++ b/server/distribution/session/bin/shutdown.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +echo "killing registry-session server..." +pids=`ps aux | grep java | grep registry-session | awk '{print $2;}'` +for pid in "${pids[@]}" +do + if [ -z "$pid" ]; then + continue; + fi +kill $pid +done +echo "Done!" \ No newline at end of file diff --git a/server/distribution/session/bin/startup.bat b/server/distribution/session/bin/startup.bat new file mode 100755 index 000000000..7bf30ea7f --- /dev/null +++ b/server/distribution/session/bin/startup.bat @@ -0,0 +1,53 @@ +@echo off +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +rem constants +set APP_NAME=session +set BASE_DIR=%~dp0 +set BASE_DIR=%BASE_DIR:~0,-5% +set APP_JAR=%BASE_DIR%\registry-%APP_NAME%.jar + +rem app conf +set "JAVA_OPT=%JAVA_OPT% -Dregistry.%APP_NAME%.home=%BASE_DIR%" +set "JAVA_OPT=%JAVA_OPT% -Dspring.config.location=%BASE_DIR%\conf\application.properties" + +rem set user.home +set "JAVA_OPT=%JAVA_OPT% -Duser.home=%BASE_DIR%" + +rem springboot conf +set "SPRINGBOOT_OPTS=%SPRINGBOOT_OPTS% --logging.config=%BASE_DIR%\conf\logback-spring.xml" + +rem heap size +set HEAP_MAX=512 +set HEAP_NEW=256 +set "JAVA_OPT=%JAVA_OPT% -server -Xms%HEAP_MAX%m -Xmx%HEAP_MAX%m -Xmn%HEAP_NEW%m -Xss256k" + +rem gc option +if not exist %BASE_DIR%\logs md %BASE_DIR%\logs +set "JAVA_OPTS=%JAVA_OPT% -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:%BASE_DIR%\logs\registry-%APP_NAME%-gc.log -verbose:gc" +set "JAVA_OPTS=%JAVA_OPT% -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%BASE_DIR%\logs -XX:ErrorFile=%BASE_DIR%\logs\registry-%APP_NAME%-hs_err_pid%p.log" +set "JAVA_OPTS=%JAVA_OPT% -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +set "JAVA_OPTS=%JAVA_OPT% -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +rem rm raftData +if exist %BASE_DIR%\raftData rd /s /Q %BASE_DIR%\raftData + +rem start +set STD_OUT=%BASE_DIR%\logs\registry-%APP_NAME%-std.out +if exist %STD_OUT% del %STD_OUT% +echo registry-%APP_NAME% is starting, you can check the %STD_OUT% for more details +echo "Command: java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS%" > %STD_OUT% +java %JAVA_OPTS% -jar %APP_JAR% %SPRINGBOOT_OPTS% >> %STD_OUT% 2>&1 diff --git a/server/distribution/session/bin/startup.sh b/server/distribution/session/bin/startup.sh new file mode 100644 index 000000000..32c9a5d6c --- /dev/null +++ b/server/distribution/session/bin/startup.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +# Copyright 1999-2018 Alibaba Group Holding Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# constants +APP_NAME="session" +BASE_DIR=`cd $(dirname $0)/..; pwd` +APP_JAR="${BASE_DIR}/registry-${APP_NAME}.jar" + +# app conf +JAVA_OPTS="$JAVA_OPTS -Dregistry.${APP_NAME}.home=${BASE_DIR}" +JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=${BASE_DIR}/conf/application.properties" + +# set user.home +JAVA_OPTS="$JAVA_OPTS -Duser.home=${BASE_DIR}" + +# springboot conf +SPRINGBOOT_OPTS="${SPRINGBOOT_OPTS} --logging.config=${BASE_DIR}/conf/logback-spring.xml" + +# heap size +HEAP_MAX=512 +HEAP_NEW=256 +JAVA_OPTS="$JAVA_OPTS -server -Xms${HEAP_MAX}m -Xmx${HEAP_MAX}m -Xmn${HEAP_NEW}m -Xss256k" + +# gc option +mkdir -p "${BASE_DIR}/logs" +JAVA_OPTS="$JAVA_OPTS -XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${BASE_DIR}/logs/registry-${APP_NAME}-gc.log -verbose:gc" +JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs -XX:ErrorFile=${BASE_DIR}/logs/registry-${APP_NAME}-hs_err_pid%p.log" +JAVA_OPTS="$JAVA_OPTS -XX:-OmitStackTraceInFastThrow -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4" +JAVA_OPTS="$JAVA_OPTS -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70" + +# start +STD_OUT="${BASE_DIR}/logs/registry-${APP_NAME}-std.out" +rm -f $STD_OUT +echo "Command: java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS}" > $STD_OUT +java ${JAVA_OPTS} -jar ${APP_JAR} ${SPRINGBOOT_OPTS} >> "$STD_OUT" 2>&1 & +PID=$! +echo "registry-${APP_NAME}(pid is $PID) is starting, you can check the $STD_OUT for more details" \ No newline at end of file diff --git a/server/distribution/session/conf/application.properties b/server/distribution/session/conf/application.properties new file mode 100644 index 000000000..77e35dba7 --- /dev/null +++ b/server/distribution/session/conf/application.properties @@ -0,0 +1,3 @@ +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter +nodes.localRegion=DEFAULT_ZONE \ No newline at end of file diff --git a/server/distribution/session/conf/application.properties.example b/server/distribution/session/conf/application.properties.example new file mode 100644 index 000000000..76a5e17f2 --- /dev/null +++ b/server/distribution/session/conf/application.properties.example @@ -0,0 +1,31 @@ +spring.main.banner-mode=LOG +nodes.metaNode=DefaultDataCenter:localhost +nodes.localDataCenter=DefaultDataCenter +nodes.localRegion=DEFAULT_ZONE + +session.server.logging.level=INFO +session.server.logging.home=/home/admin/logs/registry/session +session.server.serverPort=9600 +session.server.serverSyncPort=9601 +session.server.httpServerPort=9603 +session.server.metaServerPort=9610 +session.server.dataServerPort=9620 +session.server.serverDescription=dev session server +session.server.sessionServerRegion=DEFAULT_ZONE +session.server.sessionServerDataCenter=DefaultDataCenter +session.server.syncHeartbeat.fixedDelay=30000 +session.server.syncExceptionData.fixedDelay=30000 +session.server.printTask.fixedDelay=30000 +session.server.schedulerCheckVersionTimeout=3 +session.server.schedulerCheckVersionFirstDelay=3 +session.server.schedulerCheckVersionExpBackOffBound=10 +session.server.schedulerHeartbeatTimeout=30 +session.server.schedulerHeartbeatFirstDelay=30 +session.server.schedulerHeartbeatExpBackOffBound=10 +session.server.schedulerFetchDataTimeout=3 +session.server.schedulerFetchDataFirstDelay=3 +session.server.schedulerFetchDataExpBackOffBound=10 +session.server.invalidForeverZones=; +session.server.invalidIgnoreDataidRegex= +session.server.pushEmptyDataDataIdPrefixes= + diff --git a/server/distribution/session/distribution-session.xml b/server/distribution/session/distribution-session.xml new file mode 100644 index 000000000..81849467b --- /dev/null +++ b/server/distribution/session/distribution-session.xml @@ -0,0 +1,48 @@ + + + registry-session + false + + dir + tgz + + + + + conf/** + + + + + bin/* + + 0755 + + + + + ../../server/session/target/registry-server-session-executable.jar + / + registry-session.jar + + + ../../server/session/src/main/resources/logback-spring.xml + /conf + logback-spring.xml + + + ../version + / + version_${project.version} + + + + + + true + + com.alipay.sofa:registry-server-session + + + + \ No newline at end of file diff --git a/server/distribution/session/pom.xml b/server/distribution/session/pom.xml new file mode 100644 index 000000000..829214830 --- /dev/null +++ b/server/distribution/session/pom.xml @@ -0,0 +1,52 @@ + + + + com.alipay.sofa + registry-distribution + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-distribution-session + pom + + + ../../../ + + + + + com.alipay.sofa + registry-server-session + + + + + + + maven-assembly-plugin + 3.0.0 + + + distribution-session + package + + single + + + false + + distribution-session.xml + + + + + + + registry-session + + + diff --git a/server/distribution/version b/server/distribution/version new file mode 100644 index 000000000..e69de29bb diff --git a/server/pom.xml b/server/pom.xml new file mode 100644 index 000000000..23abe7efe --- /dev/null +++ b/server/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + + com.alipay.sofa + registry-parent + 5.2.0-SNAPSHOT + ../pom.xml + + + registry-server-parent + pom + http://www.antfin.com + [SOFA] Registry. + + + The Ant Financial + http://www.antfin.com/ + + + + remoting + common + store + server + consistency + distribution + + + + 1.8 + 1.8 + UTF-8 + ../ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + + + + + diff --git a/server/remoting/api/pom.xml b/server/remoting/api/pom.xml new file mode 100644 index 000000000..4be3abfe7 --- /dev/null +++ b/server/remoting/api/pom.xml @@ -0,0 +1,38 @@ + + + + com.alipay.sofa + registry-remoting + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-remoting-api + + + ../../../ + + + + + com.alipay.sofa + registry-common-util + + + com.alipay.sofa + registry-common-model + + + org.glassfish.jersey.core + jersey-server + + + junit + junit + test + + + diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/CallbackHandler.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/CallbackHandler.java new file mode 100644 index 000000000..2b32e72a0 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/CallbackHandler.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +/** + * + * @author shangyu.wh + * @version $Id: CallbackHandler.java, v 0.1 2017-11-22 15:16 shangyu.wh Exp $ + */ +public interface CallbackHandler { + + /** + * callback handler + * + * @param channel + * @param message + */ + void onCallback(Channel channel, Object message); + + /** + * callback exception handler + * + * @param channel + * @param exception + */ + void onException(Channel channel, Throwable exception); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Channel.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Channel.java new file mode 100644 index 000000000..4f51ffed2 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Channel.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +import javax.ws.rs.client.WebTarget; +import java.net.InetSocketAddress; + +/** + * + * @author shangyu.wh + * @version $Id: Channel.java, v 0.1 2017-11-20 20:39 shangyu.wh Exp $ + */ +public interface Channel { + + /** + * get remote address. + * + * @return remote address. + */ + InetSocketAddress getRemoteAddress(); + + /** + * get local address. + * + * @return local address. + */ + InetSocketAddress getLocalAddress(); + + /** + * is connected. + * + * @return connected + */ + boolean isConnected(); + + /** + * get attribute. + * + * @param key key. + * @return value. + */ + Object getAttribute(String key); + + /** + * set attribute. + * + * @param key key. + * @param value value. + */ + void setAttribute(String key, Object value); + + /** + * for rest api + * @return + */ + WebTarget getWebTarget(); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/ChannelHandler.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/ChannelHandler.java new file mode 100644 index 000000000..f913ca32b --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/ChannelHandler.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +import java.util.concurrent.Executor; + +/** + * + * @author shangyu.wh + * @version $Id: ChannelHandler.java, v 0.1 2017-11-20 20:45 shangyu.wh Exp $ + */ +public interface ChannelHandler { + + /** + * The enum Handler type. + */ + enum HandlerType { + LISENTER, + PROCESSER + } + + /** + * The enum Invoke type. + */ + enum InvokeType { + SYNC, + ASYNC + } + + /** + * on channel connected. + * + * @param channel + * @throws RemotingException + */ + void connected(Channel channel) throws RemotingException; + + /** + * on channel disconnected. + * + * @param channel channel. + * @throws RemotingException + */ + void disconnected(Channel channel) throws RemotingException; + + /** + * on message received. + * + * @param channel channel. + * @param message message. + * @throws RemotingException + */ + void received(Channel channel, T message) throws RemotingException; + + /** + * on message reply. + * + * @param channel + * @param message + * @return + * @throws RemotingException + */ + Object reply(Channel channel, T message) throws RemotingException; + + /** + * on exception caught. + * @param channel channel. + * @param message message. + * @param exception exception. + * @throws RemotingException + */ + void caught(Channel channel, T message, Throwable exception) throws RemotingException; + + /** + * check handlerType + * + * @return + */ + HandlerType getType(); + + /** + * return processor request class name + * + * @return + */ + Class interest(); + + /** + * Select Sync process by reply or Async process by received + * @return + */ + default InvokeType getInvokeType() { + return InvokeType.SYNC; + } + + /** + * specify executor for processor handler + * @return + */ + default Executor getExecutor() { + return null; + } +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Client.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Client.java new file mode 100644 index 000000000..f19aba5a6 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Client.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; + +import java.net.InetSocketAddress; +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: Client.java, v 0.1 2017-11-20 21:07 shangyu.wh Exp $ + */ +public interface Client extends Endpoint { + + /** + * get channels. + * + * @return channels + */ + Collection getChannels(); + + /** + * get channel. + * + * @param remoteAddress + * @return channel + */ + Channel getChannel(InetSocketAddress remoteAddress); + + /** + * get channel by url. + * + * @param url + * @return channel + */ + Channel getChannel(URL url); + + /** + * client connect target url server + * @param url + * @return + */ + Channel connect(URL url); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Endpoint.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Endpoint.java new file mode 100644 index 000000000..10cff4f22 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Endpoint.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +import java.net.InetSocketAddress; +import java.util.List; + +/** + * The interface Endpoint. + * @author shangyu.wh + * @version $Id : Endpoint.java, v 0.1 2017-11-20 20:03 shangyu.wh Exp $ + */ +public interface Endpoint { + + /** + * get channel handlers. + * + * @return channel handlers + */ + List getChannelHandlers(); + + /** + * get local address. + * + * @return local address. + */ + InetSocketAddress getLocalAddress(); + + /** + * close the channel. + */ + void close(); + + /** + * Close. + * + * @param channel the channel + */ + void close(final Channel channel); + + /** + * is closed. + * + * @return closed boolean + */ + boolean isClosed(); + + /** + * oneway send + * @param channel the channel + * @param message the message + */ + void sendOneway(final Channel channel, final Object message); + + /** + * Sync send + * + * @param channel the channel + * @param message the message + * @param timeoutMillis the timeout millis + * @return object + */ + Object sendSync(final Channel channel, final Object message, final int timeoutMillis); + + /** + * send with callback handler + * + * @param channel the channel + * @param message the message + * @param callbackHandler the callback handler + * @param timeoutMillis the timeout millis + */ + void sendCallback(final Channel channel, final Object message, CallbackHandler callbackHandler, + final int timeoutMillis); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/RemotingException.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/RemotingException.java new file mode 100644 index 000000000..727a4b6c5 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/RemotingException.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +/** + * + * @author shangyu.wh + * @version $Id: RemotingException.java, v 0.1 2017-11-20 20:43 shangyu.wh Exp $ + */ +public class RemotingException extends Exception { + + /** + * constructor + * @param s + */ + public RemotingException(String s) { + super(s); + } +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Server.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Server.java new file mode 100644 index 000000000..7452bb4f4 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/Server.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; + +import java.net.InetSocketAddress; +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: Server.java, v 0.1 2017-11-20 21:05 shangyu.wh Exp $ + */ +public interface Server extends Endpoint { + + /** + * get Server status + * + * @return + */ + boolean isOpen(); + + /** + * get channels. + * + * @return channels + */ + Collection getChannels(); + + /** + * get channel. + * + * @param remoteAddress + * @return channel + */ + Channel getChannel(InetSocketAddress remoteAddress); + + /** + * get channel by url + * + * @param url + * @return channel + */ + Channel getChannel(URL url); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/Exchange.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/Exchange.java new file mode 100644 index 000000000..961167107 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/Exchange.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.exchange; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; + +/** + * + * @author shangyu.wh + * @version $Id: Exchanger.java, v 0.1 2017-11-20 21:25 shangyu.wh Exp $ + */ +public interface Exchange { + + String DATA_SERVER_TYPE = "dataServer"; + String META_SERVER_TYPE = "metaServer"; + + /** + * connect same type server,one server ip one connection + * such as different server on data server,serverOne and serverTwo,different type server must match different channelHandlers, + * so we must connect by serverType,and get Client instance by serverType + * @param serverType + * @param serverUrl + * @param channelHandlers + * @return + */ + Client connect(String serverType, URL serverUrl, T... channelHandlers); + + /** + * bind server by server port in url parameter,one port must by same server type + * @param url + * @param channelHandlers + * @return + */ + Server open(URL url, T... channelHandlers); + + /*** + * get Client instance by serverType,very client instance has different channels match different server ip + * @param serverType + * @return + */ + Client getClient(String serverType); + + /** + * get server instance by port + * @param port + * @return + */ + Server getServer(Integer port); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/NodeExchanger.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/NodeExchanger.java new file mode 100644 index 000000000..5e6a5f3e9 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/NodeExchanger.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.exchange; + +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; + +/** + * + * @author shangyu.wh + * @version $Id: NodeExchanger.java, v 0.1 2017-12-01 11:48 shangyu.wh Exp $ + */ +public interface NodeExchanger { + + /** + * + * @param request + * @return + * @throws RequestException + */ + Response request(Request request) throws RequestException; + + /** + * + * @return + */ + Client connectServer(); +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/RequestException.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/RequestException.java new file mode 100644 index 000000000..3340bbf4b --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/RequestException.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.exchange; + +import com.alipay.sofa.registry.remoting.exchange.message.Request; + +/** + * + * @author shangyu.wh + * @version $Id: RequestException.java, v 0.1 2018-01-15 18:16 shangyu.wh Exp $ + */ +public class RequestException extends Exception { + + private Request request; + + /** + * constructor + * @param message + * @param request + */ + public RequestException(String message, Request request) { + super(message); + this.request = request; + } + + /** + * constructor + * @param message + * @param request + * @param cause + */ + public RequestException(String message, Request request, Throwable cause) { + super(message, cause); + this.request = request; + } + + /** + * constructor + * @param message + */ + public RequestException(String message) { + super(message); + } + + /** + * constructor + * @param message + * @param cause + */ + public RequestException(String message, Throwable cause) { + super(message, cause); + } + + /** + * constructor + * @param cause + */ + public RequestException(Throwable cause) { + super(cause); + } + + /** + * get requestInfo from Request + * @return + */ + public String getRequestMessage() { + StringBuilder sb = new StringBuilder(); + if (request != null) { + sb.append("Request url:").append(request.getRequestUrl()).append(" body:") + .append(request.getRequestBody()); + } else { + sb.append("Request data can not be null!"); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Request.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Request.java new file mode 100644 index 000000000..7bf15fff0 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Request.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.exchange.message; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.CallbackHandler; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * The interface Request. + * + * @param the type parameter + * @author shangyu.wh + * @version $Id : Request.java, v 0.1 2017-11-30 17:33 shangyu.wh Exp $ + */ +public interface Request { + + /** + * Gets request body. + * + * @return the request body + */ + T getRequestBody(); + + /** + * Gets request url. + * + * @return the request url + */ + URL getRequestUrl(); + + /** + * Gets call back handler. + * + * @return the call back handler + */ + default CallbackHandler getCallBackHandler() { + return null; + } + + /** + * request send by retry some times + * @return + */ + default AtomicInteger getRetryTimes() { + return new AtomicInteger(); + } +} \ No newline at end of file diff --git a/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Response.java b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Response.java new file mode 100644 index 000000000..83b3ec5a1 --- /dev/null +++ b/server/remoting/api/src/main/java/com/alipay/sofa/registry/remoting/exchange/message/Response.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.exchange.message; + +/** + * + * @author shangyu.wh + * @version $Id: Response.java, v 0.1 2017-11-30 17:39 shangyu.wh Exp $ + */ +public interface Response { + + /** + * The enum for response status + */ + enum ResultStatus { + SUCCESSFUL, FAILED + } + + /** + * Get response result + * @return + */ + T getResult(); + +} \ No newline at end of file diff --git a/server/remoting/api/src/test/java/com/alipay/sofa/registry/remoting/RequestExceptionTest.java b/server/remoting/api/src/test/java/com/alipay/sofa/registry/remoting/RequestExceptionTest.java new file mode 100644 index 000000000..7f98cc690 --- /dev/null +++ b/server/remoting/api/src/test/java/com/alipay/sofa/registry/remoting/RequestExceptionTest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import org.junit.Assert; +import org.junit.Test; + +/** + * @author xuanbei + * @since 2019/1/16 + */ +public class RequestExceptionTest { + @Test + public void doTest() { + RequestException exception = new RequestException("error message"); + Assert.assertEquals("error message", exception.getMessage()); + Assert.assertEquals("Request data can not be null!", exception.getRequestMessage()); + + RuntimeException runtimeException = new RuntimeException("error message"); + exception = new RequestException(runtimeException); + Assert.assertEquals("java.lang.RuntimeException: error message", exception.getMessage()); + Assert.assertEquals(runtimeException, exception.getCause()); + Assert.assertEquals("Request data can not be null!", exception.getRequestMessage()); + + exception = new RequestException("error message", runtimeException); + Assert.assertEquals("error message", exception.getMessage()); + Assert.assertEquals(runtimeException, exception.getCause()); + Assert.assertEquals("Request data can not be null!", exception.getRequestMessage()); + + Request request = new Request() { + @Override + public Object getRequestBody() { + return "request body"; + } + + @Override + public URL getRequestUrl() { + return null; + } + }; + exception = new RequestException("error message", request); + Assert.assertEquals("error message", exception.getMessage()); + Assert.assertEquals("Request url:null body:request body", exception.getRequestMessage()); + + exception = new RequestException("error message", request, runtimeException); + Assert.assertEquals("error message", exception.getMessage()); + Assert.assertEquals("Request url:null body:request body", exception.getRequestMessage()); + } +} diff --git a/server/remoting/bolt/pom.xml b/server/remoting/bolt/pom.xml new file mode 100644 index 000000000..88d09dcd8 --- /dev/null +++ b/server/remoting/bolt/pom.xml @@ -0,0 +1,50 @@ + + + + com.alipay.sofa + registry-remoting + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-remoting-bolt + + + ../../../ + + + + + com.alipay.sofa + registry-remoting-api + + + com.alipay.sofa + registry-common-util + + + com.alipay.sofa + bolt + + + org.slf4j + slf4j-api + provided + + + com.alipay.sofa + hessian + + + com.alipay.sofa + registry-common-model + + + junit + junit + + + diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/AsyncUserProcessorAdapter.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/AsyncUserProcessorAdapter.java new file mode 100644 index 000000000..94aa4657a --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/AsyncUserProcessorAdapter.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.AsyncContext; +import com.alipay.remoting.BizContext; +import com.alipay.remoting.rpc.protocol.AsyncUserProcessor; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +import java.util.concurrent.Executor; + +/** + * + * @author shangyu.wh + * @version $Id: AsyncUserProcessorAdapter.java, v 0.1 2018-01-18 21:24 shangyu.wh Exp $ + */ +public class AsyncUserProcessorAdapter extends AsyncUserProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncUserProcessorAdapter.class); + + private ChannelHandler userProcessorHandler; + + /** + * constructor + * @param userProcessorHandler + */ + public AsyncUserProcessorAdapter(ChannelHandler userProcessorHandler) { + this.userProcessorHandler = userProcessorHandler; + } + + @Override + public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, Object request) { + + BoltChannel boltChannel = new BoltChannel(); + boltChannel.setAsyncContext(asyncCtx); + boltChannel.setConnection(bizCtx.getConnection()); + try { + if (userProcessorHandler != null) { + userProcessorHandler.received(boltChannel, request); + } + } catch (Exception e) { + LOGGER.error("Handle request error!", e); + throw new RuntimeException("Handle request error!", e); + } + } + + @Override + public Object handleRequest(BizContext bizCtx, Object request) throws Exception { + return super.handleRequest(bizCtx, request); + } + + @Override + public String interest() { + if (userProcessorHandler != null && userProcessorHandler.interest() != null) { + return userProcessorHandler.interest().getName(); + } + + return null; + } + + @Override + public Executor getExecutor() { + return userProcessorHandler.getExecutor(); + } +} \ No newline at end of file diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannel.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannel.java new file mode 100644 index 000000000..0e857268d --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannel.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.AsyncContext; +import com.alipay.remoting.BizContext; +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.remoting.Channel; + +import javax.ws.rs.client.WebTarget; +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: BoltChannel.java, v 0.1 2017-11-24 16:46 shangyu.wh Exp $ + */ +public class BoltChannel implements Channel { + + private Connection connection; + + private AsyncContext asyncContext; + + private BizContext bizContext; + + private final Map attributes = new ConcurrentHashMap<>(); + + @Override + public InetSocketAddress getRemoteAddress() { + if (connection != null) { + return connection.getRemoteAddress(); + } + return null; + } + + @Override + public InetSocketAddress getLocalAddress() { + if (connection != null) { + return connection.getLocalAddress(); + } + return null; + } + + @Override + public boolean isConnected() { + if (connection != null) { + return connection.isFine(); + } + return false; + } + + @Override + public Object getAttribute(String key) { + return attributes.get(key); + } + + @Override + public void setAttribute(String key, Object value) { + if (value == null) { // The null value unallowed in the ConcurrentHashMap. + attributes.remove(key); + } else { + attributes.put(key, value); + } + } + + @Override + public WebTarget getWebTarget() { + return null; + } + + /** + * Getter method for property connection. + * + * @return property value of connection + */ + public Connection getConnection() { + return connection; + } + + /** + * Setter method for property connection. + * + * @param connection value to be assigned to property connection + */ + public void setConnection(Connection connection) { + this.connection = connection; + } + + /** + * Getter method for property asyncContext. + * + * @return property value of asyncContext + */ + public AsyncContext getAsyncContext() { + return asyncContext; + } + + /** + * Setter method for property asyncContext. + * + * @param asyncContext value to be assigned to property asyncContext + */ + public void setAsyncContext(AsyncContext asyncContext) { + this.asyncContext = asyncContext; + } + + /** + * Getter method for property bizContext. + * + * @return property value of bizContext + */ + public BizContext getBizContext() { + return bizContext; + } + + /** + * Setter method for property bizContext. + * + * @param bizContext value to be assigned to property bizContext + */ + public void setBizContext(BizContext bizContext) { + this.bizContext = bizContext; + } +} \ No newline at end of file diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannelUtil.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannelUtil.java new file mode 100644 index 000000000..aeb81a629 --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltChannelUtil.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.InvokeContext; +import com.alipay.sofa.registry.remoting.Channel; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class BoltChannelUtil { + public static Byte getBoltCustomSerializer(Channel channel) { + if (channel instanceof BoltChannel) { + BoltChannel boltChannel = (BoltChannel) channel; + InvokeContext invokeContext = boltChannel.getBizContext().getInvokeContext(); + + if (null != invokeContext) { + // set client custom codec for request command if not null + Object clientCustomCodec = invokeContext.get(InvokeContext.BOLT_CUSTOM_SERIALIZER); + if (null != clientCustomCodec) { + try { + return (Byte) clientCustomCodec; + } catch (ClassCastException e) { + throw new IllegalArgumentException( + "Illegal custom codec [" + clientCustomCodec + + "], the type of value should be [byte], but now is [" + + clientCustomCodec.getClass().getName() + "]."); + } + } + } + } + return null; + } +} diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltClient.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltClient.java new file mode 100644 index 000000000..ad09d9b31 --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltClient.java @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.InvokeCallback; +import com.alipay.remoting.exception.RemotingException; +import com.alipay.remoting.rpc.RpcClient; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.ChannelHandler.HandlerType; +import com.alipay.sofa.registry.remoting.ChannelHandler.InvokeType; +import com.alipay.sofa.registry.remoting.Client; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The type Bolt client. + * @author shangyu.wh + * @version $Id : BoltClient.java, v 0.1 2017-11-27 14:46 shangyu.wh Exp $ + */ +public class BoltClient implements Client { + + private static final Logger LOGGER = LoggerFactory.getLogger(BoltClient.class); + private RpcClient boltClient; + private List channelHandlers = new ArrayList<>(); + private Map channels = new HashMap<>(); + private AtomicBoolean initHandler = new AtomicBoolean(false); + + /** + * Instantiates a new Bolt client. + */ + public BoltClient() { + boltClient = new RpcClient(); + boltClient.init(); + } + + @Override + public Channel connect(URL targetUrl) { + + if (targetUrl == null) { + throw new IllegalArgumentException("Create connection targetUrl can not be null!"); + } + InetSocketAddress address = URL.toInetSocketAddress(targetUrl); + Channel c = getChannel(address); + if (c != null && c.isConnected()) { + LOGGER.info("Target url:" + targetUrl + " has been connected!", targetUrl); + return c; + } + + initHandler(); + + try { + Connection connection = boltClient + .getConnection(NetUtil.toAddressString(address), 1000); + if (connection != null) { + BoltChannel channel = new BoltChannel(); + channel.setConnection(connection); + channels.put(connection.getUrl().getOriginUrl(), channel); + return channel; + } else { + throw new RuntimeException("Bolt client connect server get none connection!"); + } + + } catch (RemotingException e) { + LOGGER.error("Bolt client connect server got a RemotingException! target url:" + + targetUrl, e); + throw new RuntimeException("Bolt client connect server got a RemotingException!", e); + } catch (InterruptedException e) { + LOGGER.error("Bolt client connect server has been Interrupted!", e); + throw new RuntimeException("Bolt client connect server has been Interrupted!", e); + } + } + + private void initHandler() { + + if (initHandler.compareAndSet(false, true)) { + boltClient.addConnectionEventProcessor(ConnectionEventType.CONNECT, + new ConnectionEventAdapter(ConnectionEventType.CONNECT, + getConnectionEventHandler(), null)); + boltClient.addConnectionEventProcessor(ConnectionEventType.CLOSE, + new ConnectionEventAdapter(ConnectionEventType.CLOSE, getConnectionEventHandler(), + null)); + boltClient.addConnectionEventProcessor(ConnectionEventType.EXCEPTION, + new ConnectionEventAdapter(ConnectionEventType.EXCEPTION, + getConnectionEventHandler(), null)); + + registerUserProcessorHandler(); + } + } + + private void registerUserProcessorHandler() { + if (channelHandlers != null) { + for (ChannelHandler channelHandler : channelHandlers) { + if (HandlerType.PROCESSER.equals(channelHandler.getType())) { + if (InvokeType.SYNC.equals(channelHandler.getInvokeType())) { + boltClient.registerUserProcessor(new SyncUserProcessorAdapter( + channelHandler)); + } else { + boltClient.registerUserProcessor(new AsyncUserProcessorAdapter( + channelHandler)); + } + } + } + } + } + + @Override + public Collection getChannels() { + + Collection chs = new HashSet<>(); + for (Channel channel : this.channels.values()) { + if (channel.isConnected()) { + chs.add(channel); + } else { + channels.remove(NetUtil.toAddressString(channel.getRemoteAddress())); + } + } + return chs; + } + + @Override + public Channel getChannel(InetSocketAddress remoteAddress) { + Channel c = channels.get(NetUtil.toAddressString(remoteAddress)); + if (c == null || !c.isConnected()) { + return null; + } + return c; + } + + @Override + public Channel getChannel(URL url) { + Channel c = channels.get(url.getAddressString()); + if (c == null || !c.isConnected()) { + return null; + } + return c; + } + + @Override + public List getChannelHandlers() { + return channelHandlers; + } + + /** + * Setter method for property channelHandlers. + * + * @param channelHandlers value to be assigned to property channelHandlers + */ + public void setChannelHandlers(List channelHandlers) { + this.channelHandlers = channelHandlers; + } + + @Override + public InetSocketAddress getLocalAddress() { + return NetUtil.getLocalSocketAddress(); + } + + /** + * Gets connection event handler. + * + * @return the connection event handler + */ + public ChannelHandler getConnectionEventHandler() { + if (channelHandlers != null) { + for (ChannelHandler channelHandler : channelHandlers) { + if (HandlerType.LISENTER.equals(channelHandler.getType())) { + return channelHandler; + } + } + } + return null; + } + + @Override + public void close() { + Collection chs = getChannels(); + if (chs != null && chs.size() > 0) { + for (Channel ch : chs) { + if (ch != null) { + boltClient.closeStandaloneConnection(((BoltChannel) ch).getConnection()); + } + } + } + } + + @Override + public void close(Channel channel) { + if (channel != null) { + Connection connection = ((BoltChannel) channel).getConnection(); + if (null != connection.getUrl() && null != connection.getUrl().getOriginUrl()) { + channels.remove(connection.getUrl().getOriginUrl()); + } + boltClient.closeStandaloneConnection(connection); + } + } + + @Override + public boolean isClosed() { + boolean ret = false; + Collection chs = getChannels(); + if (chs != null && chs.size() > 0) { + for (Channel ch : chs) { + if (ch != null && !ch.isConnected()) { + ret = true; + break; + } + } + } else { + //has no channels + return true; + } + return ret; + } + + @Override + public void sendOneway(Channel channel, Object message) { + if (channel != null && channel.isConnected()) { + if (channel instanceof BoltChannel) { + BoltChannel boltChannel = (BoltChannel) channel; + try { + boltClient.oneway(boltChannel.getConnection(), message); + } catch (RemotingException e) { + LOGGER.error("Bolt Client oneway request RemotingException! target url: {}", + boltChannel.getRemoteAddress(), e); + } + } + } + } + + @Override + public Object sendSync(Channel channel, Object message, int timeoutMillis) { + + if (channel != null && channel.isConnected()) { + if (channel instanceof BoltChannel) { + BoltChannel boltChannel = (BoltChannel) channel; + try { + return boltClient.invokeSync(boltChannel.getConnection(), message, + timeoutMillis); + } catch (RemotingException e) { + LOGGER.error("Bolt Client sendSync message RemotingException! target url:" + + boltChannel.getRemoteAddress(), e); + throw new RuntimeException("Bolt Client sendSync message RemotingException!", e); + } catch (InterruptedException e) { + LOGGER.error("Bolt Client sendSync message InterruptedException! target url:" + + boltChannel.getRemoteAddress(), e); + throw new RuntimeException( + "Bolt Client sendSync message InterruptedException!", e); + } + } else { + throw new IllegalArgumentException("Input channel instance error! instance class:" + + channel.getClass().getName()); + } + } + throw new IllegalArgumentException( + "Input channel: " + channel + + " error! channel cannot be null,or channel must be connected!"); + } + + @Override + public void sendCallback(Channel channel, Object message, CallbackHandler callbackHandler, + int timeoutMillis) { + if (channel != null && channel.isConnected()) { + if (channel instanceof BoltChannel) { + BoltChannel boltChannel = (BoltChannel) channel; + try { + boltClient.invokeWithCallback(boltChannel.getConnection(), message, + new InvokeCallback() { + + @Override + public void onResponse(Object result) { + callbackHandler.onCallback(channel, result); + } + + @Override + public void onException(Throwable e) { + callbackHandler.onException(channel, e); + } + + @Override + public Executor getExecutor() { + return null; + } + }, timeoutMillis); + return; + } catch (RemotingException e) { + LOGGER.error("Bolt Client sendSync message RemotingException! target url:" + + boltChannel.getRemoteAddress(), e); + throw new RuntimeException("Bolt Client sendSync message RemotingException!", e); + } + } else { + throw new IllegalArgumentException("Input channel instance error! instance class:" + + channel.getClass().getName()); + } + } + throw new IllegalArgumentException( + "Input channel: " + channel + + " error! channel cannot be null,or channel must be connected!"); + } + +} \ No newline at end of file diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltServer.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltServer.java new file mode 100644 index 000000000..e9fc9ed38 --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/BoltServer.java @@ -0,0 +1,345 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.InvokeCallback; +import com.alipay.remoting.Url; +import com.alipay.remoting.exception.RemotingException; +import com.alipay.remoting.rpc.RpcServer; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.ChannelHandler.HandlerType; +import com.alipay.sofa.registry.remoting.ChannelHandler.InvokeType; +import com.alipay.sofa.registry.remoting.Server; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author shangyu.wh + * @version $Id: BoltServer.java, v 0.1 2017-11-24 18:05 shangyu.wh Exp $ + */ +public class BoltServer implements Server { + + private static final Logger LOGGER = LoggerFactory.getLogger(BoltServer.class); + + private static final Logger PUSH_LOGGER = LoggerFactory.getLogger("SESSION-PUSH", + "[Server]"); + /** + * accoding server port + * can not be null + */ + private final URL url; + private final List channelHandlers; + /** + * bolt server + */ + private RpcServer boltServer; + /** + * started status + */ + private AtomicBoolean isStarted = new AtomicBoolean(false); + private Map channels = new ConcurrentHashMap<>(); + + private AtomicBoolean initHandler = new AtomicBoolean(false); + + /** + * constructor + * @param url + * @param channelHandlers + */ + public BoltServer(URL url, List channelHandlers) { + this.channelHandlers = channelHandlers; + this.url = url; + } + + /** + * start bolt server + */ + public void startServer() { + if (isStarted.compareAndSet(false, true)) { + try { + boltServer = new RpcServer(url.getPort(), true); + initHandler(); + boltServer.start(); + + } catch (Exception e) { + isStarted.set(false); + LOGGER.error("Start bolt server error!", e); + throw new RuntimeException("Start bolt server error!", e); + } + } + } + + private void stopServer() { + if (boltServer != null && isStarted.get()) { + try { + boltServer.stop(); + } catch (Exception e) { + LOGGER.error("Stop bolt server error!", e); + throw new RuntimeException("Stop bolt server error!", e); + } + } + } + + /** + * just init cant start + */ + public void initServer() { + try { + boltServer = new RpcServer(url.getPort(), true); + initHandler(); + } catch (Exception e) { + LOGGER.error("Init bolt server error!", e); + throw new RuntimeException("Init bolt server error!", e); + } + } + + private void initHandler() { + if (initHandler.compareAndSet(false, true)) { + boltServer.addConnectionEventProcessor(ConnectionEventType.CONNECT, + new ConnectionEventAdapter(ConnectionEventType.CONNECT, + getConnectionEventHandler(), this)); + boltServer.addConnectionEventProcessor(ConnectionEventType.CLOSE, + new ConnectionEventAdapter(ConnectionEventType.CLOSE, getConnectionEventHandler(), + this)); + boltServer.addConnectionEventProcessor(ConnectionEventType.EXCEPTION, + new ConnectionEventAdapter(ConnectionEventType.EXCEPTION, + getConnectionEventHandler(), this)); + + registerUserProcessorHandler(); + } + } + + private ChannelHandler getConnectionEventHandler() { + if (channelHandlers != null) { + for (ChannelHandler channelHandler : channelHandlers) { + if (HandlerType.LISENTER.equals(channelHandler.getType())) { + return channelHandler; + } + } + } + return null; + } + + private void registerUserProcessorHandler() { + if (channelHandlers != null) { + for (ChannelHandler channelHandler : channelHandlers) { + if (HandlerType.PROCESSER.equals(channelHandler.getType())) { + if (InvokeType.SYNC.equals(channelHandler.getInvokeType())) { + boltServer.registerUserProcessor(new SyncUserProcessorAdapter( + channelHandler)); + } else { + boltServer.registerUserProcessor(new AsyncUserProcessorAdapter( + channelHandler)); + } + } + } + } + } + + @Override + public boolean isOpen() { + return isStarted.get(); + } + + @Override + public Collection getChannels() { + Collection chs = new HashSet<>(); + if (!this.channels.isEmpty()) { + for (Iterator it = this.channels.values().iterator(); it.hasNext();) { + Channel channel = it.next(); + if (channel.isConnected()) { + chs.add(channel); + } else { + it.remove(); + } + } + } + return chs; + } + + @Override + public Channel getChannel(InetSocketAddress remoteAddress) { + Channel channel = channels.get(NetUtil.toAddressString(remoteAddress)); + if (channel != null && channel.isConnected()) { + return channel; + } + return null; + } + + @Override + public Channel getChannel(URL url) { + Channel channel = channels.get(url.getAddressString()); + if (channel != null && channel.isConnected()) { + return channel; + } + return null; + } + + @Override + public List getChannelHandlers() { + return channelHandlers; + } + + @Override + public InetSocketAddress getLocalAddress() { + return new InetSocketAddress(url.getPort()); + } + + @Override + public void close() { + if (isStarted.compareAndSet(true, false)) { + stopServer(); + } + } + + @Override + public void close(Channel channel) { + if (null != channel) { + channels.remove(NetUtil.toAddressString(channel.getRemoteAddress())); + BoltChannel boltChannel = (BoltChannel) channel; + Connection connection = boltChannel.getConnection(); + if (null != connection && connection.isFine()) { + connection.close(); + } + } + } + + @Override + public boolean isClosed() { + return !isStarted.get(); + } + + @Override + public void sendOneway(Channel channel, Object message) { + if (channel != null && channel.isConnected()) { + try { + Url url = new Url(channel.getRemoteAddress().getAddress().getHostAddress(), channel + .getRemoteAddress().getPort()); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Bolt Server one way message:{} , target url:{}", message, url); + } + boltServer.oneway(url, message); + } catch (RemotingException e) { + LOGGER.error("Bolt Server one way message RemotingException! target url:" + url, e); + throw new RuntimeException("Bolt Server one way message RemotingException!", e); + } catch (InterruptedException e) { + LOGGER.error("Bolt Server one way message InterruptedException! target url:" + url, + e); + throw new RuntimeException("Bolt Server one way message InterruptedException!", e); + } + } + throw new IllegalArgumentException( + "Send message connection can not be null or connection not be connected!"); + } + + @Override + public Object sendSync(Channel channel, Object message, int timeoutMillis) { + if (channel != null && channel.isConnected()) { + try { + Url url = new Url(channel.getRemoteAddress().getAddress().getHostAddress(), channel + .getRemoteAddress().getPort()); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Bolt Server sendSync message:{} , target url:{}", message, url); + } + + return boltServer.invokeSync(url, message, timeoutMillis); + } catch (RemotingException e) { + LOGGER + .error("Bolt Server sendSync message RemotingException! target url:" + url, e); + throw new RuntimeException("Bolt Server sendSync message RemotingException!", e); + } catch (InterruptedException e) { + LOGGER.error( + "Bolt Server sendSync message InterruptedException! target url:" + url, e); + throw new RuntimeException("Bolt Server sendSync message InterruptedException!", e); + } + } + throw new IllegalArgumentException( + "Send message connection can not be null or connection not be connected!"); + } + + @Override + public void sendCallback(Channel channel, Object message, CallbackHandler callbackHandler, + int timeoutMillis) { + if (channel != null && channel.isConnected()) { + try { + Url url = new Url(channel.getRemoteAddress().getAddress().getHostAddress(), channel + .getRemoteAddress().getPort()); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Bolt Server sendSync message:{} , target url:{}", message, url); + } + boltServer.invokeWithCallback(url, message, new InvokeCallback() { + @Override + public void onResponse(Object result) { + callbackHandler.onCallback(channel, result); + } + + @Override + public void onException(Throwable e) { + callbackHandler.onException(channel, e); + } + + @Override + public Executor getExecutor() { + return null; + } + }, timeoutMillis); + return; + } catch (RemotingException e) { + throw new RuntimeException("Bolt Server invoke with callback RemotingException!", e); + } catch (InterruptedException e) { + PUSH_LOGGER.error( + "Bolt Server invoke with callback InterruptedException! target url:" + url, e); + throw new RuntimeException( + "Bolt Server invoke with callback InterruptedException!", e); + } + } + throw new IllegalArgumentException( + "Send message connection can not be null or connection not be connected!"); + } + + public void addChannel(Channel channel) { + channels.putIfAbsent(NetUtil.toAddressString(channel.getRemoteAddress()), channel); + } + + public void removeChannel(Channel channel) { + channels.remove(NetUtil.toAddressString(channel.getRemoteAddress())); + } + + public RpcServer getRpcServer() { + return boltServer; + } +} \ No newline at end of file diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/ConnectionEventAdapter.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/ConnectionEventAdapter.java new file mode 100644 index 000000000..65b01c73f --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/ConnectionEventAdapter.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.ConnectionEventProcessor; +import com.alipay.remoting.ConnectionEventType; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +/** + * The type Connection event adapter. + * @author shangyu.wh + * @version $Id : ConnectionEventAdapter.java, v 0.1 2017-11-22 21:01 shangyu.wh Exp $ + */ +public class ConnectionEventAdapter implements ConnectionEventProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionEventAdapter.class); + + private ConnectionEventType connectionEventType; + + private ChannelHandler connectionEventHandler; + + private BoltServer boltServer; + + /** + * Instantiates a new Connection event adapter. + * + * @param connectionEventType the connection event type + * @param connectionEventHandler the connection event handler + * @param boltServer the bolt server + */ + public ConnectionEventAdapter(ConnectionEventType connectionEventType, + ChannelHandler connectionEventHandler, BoltServer boltServer) { + this.connectionEventType = connectionEventType; + this.connectionEventHandler = connectionEventHandler; + this.boltServer = boltServer; + } + + /** + * @see ConnectionEventProcessor#onEvent(String, Connection) + */ + @Override + public void onEvent(String remoteAddr, Connection conn) { + try { + if (connectionEventHandler != null) { + switch (connectionEventType) { + case CONNECT: + BoltChannel boltChannel = new BoltChannel(); + boltChannel.setConnection(conn); + if (boltServer != null) { + boltServer.addChannel(boltChannel); + } + connectionEventHandler.connected(boltChannel); + break; + + case CLOSE: + BoltChannel boltChannelClose = new BoltChannel(); + boltChannelClose.setConnection(conn); + if (boltServer != null) { + boltServer.removeChannel(boltChannelClose); + } + connectionEventHandler.disconnected(boltChannelClose); + break; + + case EXCEPTION: + BoltChannel boltChannelException = new BoltChannel(); + boltChannelException.setConnection(conn); + connectionEventHandler.caught(boltChannelException, null, null); + break; + default: + break; + } + } + } catch (Exception e) { + LOGGER.error("Connection process " + connectionEventType + " error!", e); + throw new RuntimeException("Connection process " + connectionEventType + " error!", e); + } + } +} \ No newline at end of file diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/SyncUserProcessorAdapter.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/SyncUserProcessorAdapter.java new file mode 100644 index 000000000..5a312b5a2 --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/SyncUserProcessorAdapter.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.remoting.AsyncContext; +import com.alipay.remoting.BizContext; +import com.alipay.remoting.rpc.protocol.SyncUserProcessor; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +import java.util.concurrent.Executor; + +/** + * + * @author shangyu.wh + * @version $Id: UserProcessorAdapter.java, v 0.1 2017-11-24 17:10 shangyu.wh Exp $ + */ +public class SyncUserProcessorAdapter extends SyncUserProcessor { + + private ChannelHandler userProcessorHandler; + + /** + * constructor + * @param userProcessorHandler + */ + public SyncUserProcessorAdapter(ChannelHandler userProcessorHandler) { + this.userProcessorHandler = userProcessorHandler; + } + + @Override + public void handleRequest(BizContext bizCtx, AsyncContext asyncCtx, Object request) { + super.handleRequest(bizCtx, asyncCtx, request); + } + + @Override + public Object handleRequest(BizContext bizCtx, Object request) throws Exception { + BoltChannel boltChannel = new BoltChannel(); + boltChannel.setBizContext(bizCtx); + boltChannel.setConnection(bizCtx.getConnection()); + if (userProcessorHandler != null) { + return userProcessorHandler.reply(boltChannel, request); + } + return null; + } + + @Override + public String interest() { + if (userProcessorHandler != null && userProcessorHandler.interest() != null) { + return userProcessorHandler.interest().getName(); + } + + return null; + } + + @Override + public Executor getExecutor() { + return userProcessorHandler.getExecutor(); + } +} \ No newline at end of file diff --git a/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/exchange/BoltExchange.java b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/exchange/BoltExchange.java new file mode 100644 index 000000000..701729786 --- /dev/null +++ b/server/remoting/bolt/src/main/java/com/alipay/sofa/registry/remoting/bolt/exchange/BoltExchange.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt.exchange; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.bolt.BoltClient; +import com.alipay.sofa.registry.remoting.bolt.BoltServer; +import com.alipay.sofa.registry.remoting.exchange.Exchange; + +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: BoltExchange.java, v 0.1 2017-11-27 15:47 shangyu.wh Exp $ + */ +public class BoltExchange implements Exchange { + + private Map clients = new ConcurrentHashMap<>(); + + private ConcurrentHashMap serverMap = new ConcurrentHashMap<>(); + + @Override + public Client connect(String serverType, URL serverUrl, ChannelHandler... channelHandlers) { + + if (channelHandlers == null) { + throw new IllegalArgumentException("channelHandlers cannot be null!"); + } + Client client = clients.get(serverType); + if (client == null) { + BoltClient boltClient = new BoltClient(); + boltClient.setChannelHandlers(Arrays.asList(channelHandlers)); + boltClient.connect(serverUrl); + client = clients.putIfAbsent(serverType, boltClient); + if (client == null) { + client = boltClient; + } + } else { + Channel channel = client.getChannel(serverUrl); + if (channel == null) { + BoltClient boltClient = (BoltClient) client; + boltClient.setChannelHandlers(Arrays.asList(channelHandlers)); + boltClient.connect(serverUrl); + } + } + return client; + } + + @Override + public Server open(URL url, ChannelHandler... channelHandlers) { + + if (channelHandlers == null) { + throw new IllegalArgumentException("channelHandlers cannot be null!"); + } + + BoltServer server = new BoltServer(url, Arrays.asList(channelHandlers)); + setServer(server, url); + server.startServer(); + return server; + } + + @Override + public Client getClient(String serverType) { + return clients.get(serverType); + } + + @Override + public Server getServer(Integer port) { + return serverMap.get(port); + } + + /** + * add server into serverMap + * @param server + * @param url + */ + public void setServer(Server server, URL url) { + serverMap.putIfAbsent(url.getPort(), server); + } +} \ No newline at end of file diff --git a/server/remoting/bolt/src/test/java/com/alipay/sofa/registry/remoting/bolt/BoltServerTest.java b/server/remoting/bolt/src/test/java/com/alipay/sofa/registry/remoting/bolt/BoltServerTest.java new file mode 100644 index 000000000..36e8e3830 --- /dev/null +++ b/server/remoting/bolt/src/test/java/com/alipay/sofa/registry/remoting/bolt/BoltServerTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.bolt; + +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.bolt.BoltServer; +import org.junit.Assert; +import org.junit.Test; + +import javax.ws.rs.client.WebTarget; +import java.net.InetSocketAddress; + +/** + * + * @author shangyu.wh + * @version $Id: BoltServerTest.java, v 0.1 2018-05-14 19:34 shangyu.wh Exp $ + */ +public class BoltServerTest { + + @Test + public void testGetChannel() { + BoltServer sessionServer = new BoltServer(null, null); + for (int i = 0; i < 30; i++) { + + int finalI = i; + sessionServer.addChannel(new Channel() { + @Override + public InetSocketAddress getRemoteAddress() { + return new InetSocketAddress("192.168.1." + finalI, 9000); + } + + @Override + public InetSocketAddress getLocalAddress() { + return null; + } + + @Override + public boolean isConnected() { + return finalI % 2 == 0; + } + + @Override + public Object getAttribute(String key) { + return null; + } + + @Override + public void setAttribute(String key, Object value) { + + } + + @Override + public WebTarget getWebTarget() { + return null; + } + }); + } + sessionServer.getChannels(); + Channel channel = sessionServer.getChannel(new InetSocketAddress("192.168.1.1", 9000)); + Assert.assertNull(channel); + + channel = sessionServer.getChannel(new InetSocketAddress("192.168.1.18", 9000)); + Assert.assertNotNull(channel); + } +} \ No newline at end of file diff --git a/server/remoting/http/pom.xml b/server/remoting/http/pom.xml new file mode 100644 index 000000000..fb69761dd --- /dev/null +++ b/server/remoting/http/pom.xml @@ -0,0 +1,79 @@ + + + + com.alipay.sofa + registry-remoting + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-remoting-http + + + ../../../ + + + + + com.alipay.sofa + registry-remoting-api + + + com.alipay.sofa + registry-common-util + + + com.alipay.sofa + registry-common-model + + + org.slf4j + slf4j-api + provided + + + io.netty + netty-all + + + org.glassfish.jersey.core + jersey-server + + + org.glassfish.jersey.containers + jersey-container-netty-http + + + org.glassfish.jersey.containers + jersey-container-jdk-http + + + org.glassfish.jersey.containers + jersey-container-jetty-http + + + org.glassfish.jersey.inject + jersey-hk2 + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + + org.eclipse.jetty + jetty-server + + + org.eclipse.jetty + jetty-util + + + org.eclipse.jetty + jetty-continuation + + + diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyChannel.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyChannel.java new file mode 100644 index 000000000..dc7b95750 --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyChannel.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey; + +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.WebTarget; +import java.net.InetSocketAddress; +import java.net.URI; + +/** + * + * @author shangyu.wh + * @version $Id: JerseyChannel.java, v 0.1 2018-02-01 11:35 shangyu.wh Exp $ + */ +public class JerseyChannel implements Channel { + + private WebTarget webTarget; + + private Client client; + + @Override + public InetSocketAddress getRemoteAddress() { + if (webTarget != null) { + URI uri = webTarget.getUri(); + return new InetSocketAddress(uri.getHost(), uri.getPort()); + } + return null; + } + + @Override + public InetSocketAddress getLocalAddress() { + return NetUtil.getLocalSocketAddress(); + } + + @Override + public boolean isConnected() { + if (client instanceof org.glassfish.jersey.client.JerseyClient) { + return ((org.glassfish.jersey.client.JerseyClient) client).isClosed(); + } + return false; + } + + @Override + public Object getAttribute(String key) { + return null; + } + + @Override + public void setAttribute(String key, Object value) { + + } + + /** + * Getter method for property webTarget. + * + * @return property value of webTarget + */ + @Override + public WebTarget getWebTarget() { + return webTarget; + } + + /** + * Setter method for property webTarget. + * + * @param webTarget value to be assigned to property webTarget + */ + public void setWebTarget(WebTarget webTarget) { + this.webTarget = webTarget; + } + + /** + * Setter method for property client. + * + * @param client value to be assigned to property client + */ + public void setClient(Client client) { + this.client = client; + } +} \ No newline at end of file diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyClient.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyClient.java new file mode 100644 index 000000000..825a7dd51 --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyClient.java @@ -0,0 +1,199 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.HttpUrlConnectorProvider; +import org.glassfish.jersey.jackson.JacksonFeature; + +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.UriBuilder; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +/** + * + * @author shangyu.wh + * @version $Id: JerseyClient.java, v 0.1 2018-01-30 11:13 shangyu.wh Exp $ + */ +public class JerseyClient implements Client { + + private static final Logger LOGGER = LoggerFactory + .getLogger(JerseyClient.class); + private volatile static JerseyClient instance; + private final AtomicReference client = new AtomicReference<>(null); + private Map channels = new HashMap<>(); + + /** + * constructor + */ + public JerseyClient() { + setClient(getClient(null)); + } + + /** + * get instance of jerseyClient + * @return + */ + public static JerseyClient getInstance() { + if (instance == null) { + synchronized (JerseyClient.class) { + if (instance == null) { + instance = new JerseyClient(); + } + } + } + return instance; + } + + @Override + public Channel connect(URL url) { + try { + + JerseyChannel channel = new JerseyChannel(); + channel.setWebTarget(getTarget(url)); + channel.setClient(getClient()); + channels.put(url.getAddressString(), channel); + return channel; + } catch (Exception e) { + LOGGER.error("Create jersey connect:" + url + " error!", e); + throw new RuntimeException("Create jersey connect:" + url + " error!", e); + } + } + + private WebTarget getTarget(URL targetUrl) { + return getClient().target(getBaseUri(targetUrl)); + } + + private javax.ws.rs.client.Client getClient(ClientConfig clientConfig) { + if (clientConfig == null) { + clientConfig = new ClientConfig(); + } + + clientConfig.connectorProvider(new HttpUrlConnectorProvider()); + + clientConfig.register(JacksonFeature.class); + + return ClientBuilder.newClient(clientConfig); + } + + public javax.ws.rs.client.Client getClient() { + return client.get(); + } + + public void setClient(final javax.ws.rs.client.Client clientIn) { + client.getAndSet(clientIn); + } + + public URI getBaseUri(URL targetUrl) { + URI uri; + try { + uri = UriBuilder.fromUri("http://" + targetUrl.getIpAddress() + "/") + .port(targetUrl.getPort()).build(); + } catch (Exception e) { + LOGGER.error("get server URI error!", e); + throw new RuntimeException("get server URI error!", e); + } + return uri; + } + + @Override + public Collection getChannels() { + return null; + } + + @Override + public Channel getChannel(InetSocketAddress remoteAddress) { + Channel c = channels.get(NetUtil.toAddressString(remoteAddress)); + if (c == null) { + return null; + } else { + if (!c.isConnected()) { + connect(new URL(remoteAddress)); + } + } + return c; + } + + @Override + public Channel getChannel(URL url) { + Channel c = channels.get(url.getAddressString()); + if (c == null) { + return null; + } else { + if (!c.isConnected()) { + connect(url); + } + } + return c; + } + + @Override + public List getChannelHandlers() { + return null; + } + + @Override + public InetSocketAddress getLocalAddress() { + return NetUtil.getLocalSocketAddress(); + } + + @Override + public void close() { + + } + + @Override + public void close(Channel channel) { + + } + + @Override + public boolean isClosed() { + return false; + } + + @Override + public void sendOneway(Channel channel, Object message) { + + } + + @Override + public Object sendSync(Channel channel, Object message, int timeoutMillis) { + return null; + } + + @Override + public void sendCallback(Channel channel, Object message, CallbackHandler callbackHandler, + int timeoutMillis) { + + } +} \ No newline at end of file diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyJettyServer.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyJettyServer.java new file mode 100644 index 000000000..680384881 --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/JerseyJettyServer.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.jersey.jetty.server.HttpConnectionCustomFactory; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.glassfish.jersey.internal.guava.ThreadFactoryBuilder; +import org.glassfish.jersey.jetty.JettyHttpContainer; +import org.glassfish.jersey.jetty.internal.LocalizationMessages; +import org.glassfish.jersey.process.JerseyProcessingUncaughtExceptionHandler; +import org.glassfish.jersey.server.ContainerFactory; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.server.spi.Container; + +import javax.ws.rs.ProcessingException; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author shangyu.wh + * @version $Id: Jersey.java, v 0.1 2018-01-29 17:57 shangyu.wh Exp $ + */ +public class JerseyJettyServer implements Server { + + private static final Logger LOGGER = LoggerFactory + .getLogger(JerseyJettyServer.class); + + private final ResourceConfig resourceConfig; + + private final URI baseUri; + + private org.eclipse.jetty.server.Server server; + /** + * started status + */ + private AtomicBoolean isStarted = new AtomicBoolean(false); + + /** + * constructor + * @param resourceConfig + * @param baseUri + */ + public JerseyJettyServer(ResourceConfig resourceConfig, URI baseUri) { + this.resourceConfig = resourceConfig; + this.baseUri = baseUri; + } + + /** + * start jersey server + */ + public void startServer() { + if (isStarted.compareAndSet(false, true)) { + try { + + server = createServer(getBaseUri(), resourceConfig, true); + + } catch (Exception e) { + isStarted.set(false); + LOGGER.error("Start Jetty jersey server error!", e); + throw new RuntimeException("Start Jetty jersey server error!", e); + } + } + } + + public static org.eclipse.jetty.server.Server createServer(final URI uri, + final ResourceConfig resourceConfig, + final boolean start) { + if (uri == null) { + throw new IllegalArgumentException(LocalizationMessages.URI_CANNOT_BE_NULL()); + } + + JettyHttpContainer handler = ContainerFactory.createContainer(JettyHttpContainer.class, + resourceConfig); + + int defaultPort = Container.DEFAULT_HTTP_PORT; + + final int port = (uri.getPort() == -1) ? defaultPort : uri.getPort(); + + final org.eclipse.jetty.server.Server server = new org.eclipse.jetty.server.Server( + new JettyConnectorThreadPool()); + + final ServerConnector http = new ServerConnector(server, new HttpConnectionCustomFactory()); + http.setPort(port); + server.setConnectors(new Connector[] { http }); + + if (handler != null) { + server.setHandler(handler); + } + + if (start) { + try { + // Start the server. + server.start(); + } catch (final Exception e) { + throw new ProcessingException(LocalizationMessages.ERROR_WHEN_CREATING_SERVER(), e); + } + } + return server; + } + + private static final class JettyConnectorThreadPool extends QueuedThreadPool { + private final ThreadFactory threadFactory = new ThreadFactoryBuilder() + .setNameFormat("jetty-http-server-%d") + .setUncaughtExceptionHandler( + new JerseyProcessingUncaughtExceptionHandler()) + .build(); + + @Override + protected Thread newThread(Runnable runnable) { + return threadFactory.newThread(runnable); + } + } + + @Override + public boolean isOpen() { + if (server != null) { + return server.isStarted(); + } + return false; + } + + @Override + public Collection getChannels() { + return null; + } + + @Override + public Channel getChannel(InetSocketAddress remoteAddress) { + return null; + } + + @Override + public Channel getChannel(URL url) { + return null; + } + + @Override + public List getChannelHandlers() { + return null; + } + + @Override + public InetSocketAddress getLocalAddress() { + return new InetSocketAddress(getBaseUri().getPort()); + } + + @Override + public void close() { + if (server != null) { + try { + server.stop(); + } catch (Exception e) { + LOGGER.error("Jersey Jetty Server stop error!", e); + throw new RuntimeException("Jersey Jetty Server stop error!", e); + } + return; + } + throw new RuntimeException("Jersey Server has not started!Server Channel has not created!"); + } + + @Override + public void close(Channel channel) { + throw new UnsupportedOperationException("Jersey Server don't support close Channel."); + } + + @Override + public boolean isClosed() { + if (server != null) { + return server.isStopped(); + } + return true; + } + + @Override + public void sendOneway(Channel channel, Object message) { + + } + + @Override + public Object sendSync(Channel channel, Object message, int timeoutMillis) { + return null; + } + + @Override + public void sendCallback(Channel channel, Object message, CallbackHandler callbackHandler, + int timeoutMillis) { + + } + + /** + * Getter method for property baseUri. + * + * @return property value of baseUri + */ + public URI getBaseUri() { + return baseUri; + } + +} \ No newline at end of file diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/exchange/JerseyExchange.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/exchange/JerseyExchange.java new file mode 100644 index 000000000..be001a92b --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/exchange/JerseyExchange.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey.exchange; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.jersey.JerseyClient; +import com.alipay.sofa.registry.remoting.jersey.JerseyJettyServer; +import org.glassfish.jersey.server.ResourceConfig; + +import javax.ws.rs.core.UriBuilder; +import java.net.URI; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: JerseyExchange.java, v 0.1 2018-01-29 19:49 shangyu.wh Exp $ + */ +public class JerseyExchange implements Exchange { + + private static final Logger LOGGER = LoggerFactory + .getLogger(JerseyExchange.class); + + private ConcurrentHashMap serverMap = new ConcurrentHashMap<>(); + + private Client client; + + @Override + public Client connect(String serverType, URL serverUrl, ResourceConfig... channelHandlers) { + JerseyClient jerseyClient = JerseyClient.getInstance(); + setClient(jerseyClient); + return jerseyClient; + } + + @Override + public Server open(URL url, ResourceConfig... resources) { + + URI uri; + try { + uri = UriBuilder.fromUri("http://" + url.getIpAddress() + "/").port(url.getPort()) + .build(); + } catch (Exception e) { + LOGGER.error("get server URI error!", e); + throw new RuntimeException("get server URI error!", e); + } + JerseyJettyServer jerseyServer = new JerseyJettyServer(resources[0], uri); + setServer(jerseyServer, url); + jerseyServer.startServer(); + + return jerseyServer; + } + + @Override + public Client getClient(String serverType) { + if (null == client) { + synchronized (JerseyExchange.class) { + if (null == client) { + JerseyClient jerseyClient = JerseyClient.getInstance(); + setClient(jerseyClient); + } + } + } + return client; + } + + /** + * Setter method for property client. + * + * @param client value to be assigned to property client + */ + public void setClient(Client client) { + this.client = client; + } + + @Override + public Server getServer(Integer port) { + return serverMap.get(port); + } + + /** + * add server into serverMap + * @param server + * @param url + */ + public void setServer(Server server, URL url) { + serverMap.putIfAbsent(url.getPort(), server); + } +} \ No newline at end of file diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpChannelOverHttpCustom.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpChannelOverHttpCustom.java new file mode 100644 index 000000000..c45bf7c4c --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpChannelOverHttpCustom.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey.jetty.server; + +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpChannelOverHttp; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnection; +import org.eclipse.jetty.server.HttpTransport; + +/** + * + * @author shangyu.wh + * @version $Id: HttpChannelOverHttpHack.java, v 0.1 2018-09-26 17:00 shangyu.wh Exp $ + */ +public class HttpChannelOverHttpCustom extends HttpChannelOverHttp { + private static final char QUESTION_MARK = '?'; + + public HttpChannelOverHttpCustom(HttpConnection httpConnection, Connector connector, + HttpConfiguration config, EndPoint endPoint, + HttpTransport transport) { + super(httpConnection, connector, config, endPoint, transport); + } + + @Override + public boolean startRequest(String method, String uri, HttpVersion version) { + + if (uri != null && !uri.isEmpty() && uri.charAt(0) == QUESTION_MARK) { + /* HTTP/1.1 spec says in 5.1.2. about Request-URI: + * "Note that the absolute path cannot be empty; if + * none is present in the original URI, it MUST be + * given as "/" (the server root)." So if the file + * name here has only a query string, the path is + * empty and we also have to add a "/". + */ + uri = "/" + uri; + } + return super.startRequest(method, uri, version); + } +} \ No newline at end of file diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustom.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustom.java new file mode 100644 index 000000000..e6cc4b0e0 --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustom.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey.jetty.server; + +import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpChannelOverHttp; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnection; + +/** + * + * @author shangyu.wh + * @version $Id: HttpConnectionOver.java, v 0.1 2018-09-26 16:46 shangyu.wh Exp $ + */ +public class HttpConnectionCustom extends HttpConnection { + + public HttpConnectionCustom(HttpConfiguration config, Connector connector, EndPoint endPoint, + HttpCompliance compliance, boolean recordComplianceViolations) { + super(config, connector, endPoint, compliance, recordComplianceViolations); + } + + @Override + protected HttpChannelOverHttp newHttpChannel() { + return new HttpChannelOverHttpCustom(this, getConnector(), getHttpConfiguration(), + getEndPoint(), this); + } +} \ No newline at end of file diff --git a/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustomFactory.java b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustomFactory.java new file mode 100644 index 000000000..bdc0e8e8b --- /dev/null +++ b/server/remoting/http/src/main/java/com/alipay/sofa/registry/remoting/jersey/jetty/server/HttpConnectionCustomFactory.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.remoting.jersey.jetty.server; + +import org.eclipse.jetty.io.Connection; +import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; + +/** + * + * @author shangyu.wh + * @version $Id: HttpConnectionOverFactory.java, v 0.1 2018-09-26 16:40 shangyu.wh Exp $ + */ +public class HttpConnectionCustomFactory extends HttpConnectionFactory { + + public HttpConnectionCustomFactory() { + super(new HttpConfiguration()); + } + + @Override + public Connection newConnection(Connector connector, EndPoint endPoint) { + HttpConnectionCustom conn = new HttpConnectionCustom(getHttpConfiguration(), connector, + endPoint, getHttpCompliance(), isRecordHttpComplianceViolations()); + return configure(conn, connector, endPoint); + } + +} \ No newline at end of file diff --git a/server/remoting/pom.xml b/server/remoting/pom.xml new file mode 100644 index 000000000..a42a1f779 --- /dev/null +++ b/server/remoting/pom.xml @@ -0,0 +1,25 @@ + + + + com.alipay.sofa + registry-server-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + pom + + + ../../ + + + + api + bolt + http + + + registry-remoting + diff --git a/server/server/data/pom.xml b/server/server/data/pom.xml new file mode 100644 index 000000000..4e2428f0c --- /dev/null +++ b/server/server/data/pom.xml @@ -0,0 +1,111 @@ + + + + com.alipay.sofa + registry-server + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-server-data + + + ../../../ + + + + + org.springframework.boot + spring-boot-starter + + + registry-common-model + com.alipay.sofa + + + registry-common-util + com.alipay.sofa + + + registry-consistency + com.alipay.sofa + + + com.alipay.sofa + bolt + + + io.netty + netty-all + + + org.slf4j + slf4j-api + + + com.alipay.sofa.common + sofa-common-tools + + + com.alipay.sofa + hessian + + + com.google.guava + guava + + + com.alipay.sofa + registry-store-jraft + + + com.alipay.sofa + registry-remoting-http + + + org.hibernate + hibernate-validator + + + commons-lang + commons-lang + + + junit + junit + test + + + org.mockito + mockito-core + test + + + + + registry-server-data + + + org.springframework.boot + spring-boot-maven-plugin + + ./target + executable + + + + + repackage + + + false + + + + + + + diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/DataApplication.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/DataApplication.java new file mode 100644 index 000000000..54079bb12 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/DataApplication.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.bootstrap.EnableDataServer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * + * @author zhuoyu.sjw + * @version $Id: DataApplication.java, v 0.1 2017-11-13 19:04 zhuoyu.sjw Exp $$ + */ +@EnableDataServer +@SpringBootApplication +public class DataApplication { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataApplication.class); + + public static void main(String[] args) { + // setup DefaultUncaughtExceptionHandler + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { + LOGGER.error(String.format("UncaughtException in Thread(%s): %s", t.getName(), e.getMessage()), e); + }); + SpringApplication.run(DataApplication.class, args); + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/CommonConfig.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/CommonConfig.java new file mode 100644 index 000000000..ccb1436a9 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/CommonConfig.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.bootstrap; + +import org.springframework.beans.factory.annotation.Value; + +import java.util.Collection; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: CommonConfig.java, v 0.1 2018-05-05 15:16 shangyu.wh Exp $ + */ +public class CommonConfig { + + /** + * server local data center, get from System Property + * example: nodes.localDataCenter=DefaultDataCenter + */ + @Value("${nodes.localDataCenter}") + private String localDataCenter; + + public static final String LOCAL_REGION = System + .getProperty("nodes.localRegion"); + + @Value("#{PropertySplitter.mapOfList('${nodes.metaNode}')}") + private Map> metaNode; + + /** + * Getter method for property metaNode. + * + * @return property value of metaNode + */ + public Map> getMetaNode() { + return metaNode; + } + + /** + * Setter method for property metaNode. + * + * @param metaNode value to be assigned to property metaNode + */ + public void setMetaNode(Map> metaNode) { + this.metaNode = metaNode; + } + + /** + * Getter method for property localDataCenter. + * + * @return property value of localDataCenter + */ + public String getLocalDataCenter() { + return localDataCenter; + } + + /** + * Getter method for property localRegion. + * + * @return property value of localRegion + */ + public String getLocalRegion() { + return LOCAL_REGION; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBeanConfiguration.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBeanConfiguration.java new file mode 100644 index 000000000..5087a451b --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBeanConfiguration.java @@ -0,0 +1,452 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.bootstrap; + +import com.alipay.sofa.registry.remoting.bolt.exchange.BoltExchange; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.jersey.exchange.JerseyExchange; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.change.DataChangeHandler; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.change.notify.BackUpNotifier; +import com.alipay.sofa.registry.server.data.change.notify.IDataChangeNotifier; +import com.alipay.sofa.registry.server.data.change.notify.SessionServerNotifier; +import com.alipay.sofa.registry.server.data.change.notify.TempPublisherNotifier; +import com.alipay.sofa.registry.server.data.correction.LocalDataServerCleanHandler; +import com.alipay.sofa.registry.server.data.datasync.AcceptorStore; +import com.alipay.sofa.registry.server.data.datasync.SyncDataService; +import com.alipay.sofa.registry.server.data.datasync.sync.LocalAcceptorStore; +import com.alipay.sofa.registry.server.data.datasync.sync.Scheduler; +import com.alipay.sofa.registry.server.data.datasync.sync.StoreServiceFactory; +import com.alipay.sofa.registry.server.data.datasync.sync.SyncDataServiceImpl; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.event.handler.DataServerChangeEventHandler; +import com.alipay.sofa.registry.server.data.event.handler.LocalDataServerChangeEventHandler; +import com.alipay.sofa.registry.server.data.event.handler.MetaServerChangeEventHandler; +import com.alipay.sofa.registry.server.data.event.handler.StartTaskEventHandler; +import com.alipay.sofa.registry.server.data.node.DataNodeStatus; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.MetaNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.dataserver.GetSyncDataHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.DataSyncServerConnectionHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.FetchDataHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.NotifyDataSyncHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.NotifyFetchDatumHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.NotifyOnlineHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.SyncDataHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.task.AbstractTask; +import com.alipay.sofa.registry.server.data.remoting.dataserver.task.ConnectionRefreshTask; +import com.alipay.sofa.registry.server.data.remoting.dataserver.task.ReNewNodeTask; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.metaserver.DefaultMetaServiceImpl; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import com.alipay.sofa.registry.server.data.remoting.metaserver.MetaServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.metaserver.handler.ServerChangeHandler; +import com.alipay.sofa.registry.server.data.remoting.metaserver.handler.StatusConfirmHandler; +import com.alipay.sofa.registry.server.data.remoting.metaserver.task.ConnectionRefreshMetaTask; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect.DisconnectEventHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.forward.ForwardService; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.forward.ForwardServiceImpl; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.ClientOffHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.DataServerConnectionHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.GetDataHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.GetDataVersionsHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.PublishDataHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.SessionServerRegisterHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.handler.UnPublishDataHandler; +import com.alipay.sofa.registry.server.data.resource.DataDigestResource; +import com.alipay.sofa.registry.server.data.resource.HealthResource; +import com.alipay.sofa.registry.util.PropertySplitter; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * + * @author qian.lqlq + * @version $Id: DataServerBeanConfiguration.java, v 0.1 2018-01-11 15:08 qian.lqlq Exp $ + */ +@Configuration +@Import(DataServerInitializer.class) +@EnableConfigurationProperties +public class DataServerBeanConfiguration { + + @Bean + @ConditionalOnMissingBean + public DataServerBootstrap dataServerBootstrap() { + return new DataServerBootstrap(); + } + + @Configuration + protected static class DataServerBootstrapConfigConfiguration { + + @Bean + public CommonConfig commonConfig() { + return new CommonConfig(); + } + + @Bean + public DataServerConfig dataServerBootstrapConfig(CommonConfig commonConfig) { + return new DataServerConfig(commonConfig); + } + + @Bean + public DataNodeStatus dataNodeStatus() { + return new DataNodeStatus(); + } + + @Bean(name = "PropertySplitter") + public PropertySplitter propertySplitter() { + return new PropertySplitter(); + } + } + + @Configuration + public static class SessionRemotingConfiguration { + @Bean + public Exchange jerseyExchange() { + return new JerseyExchange(); + } + + @Bean + public Exchange boltExchange() { + return new BoltExchange(); + } + + @Bean + public MetaNodeExchanger metaNodeExchanger() { + return new MetaNodeExchanger(); + } + + @Bean + public DataNodeExchanger dataNodeExchanger() { + return new DataNodeExchanger(); + } + + @Bean + public DataServerCache dataServerCache() { + return new DataServerCache(); + } + + @Bean + public ForwardService forwardService() { + return new ForwardServiceImpl(); + } + + @Bean + public SessionServerConnectionFactory sessionServerConnectionFactory() { + return new SessionServerConnectionFactory(); + } + + @Bean + public DataServerConnectionFactory dataServerConnectionFactory() { + return new DataServerConnectionFactory(); + } + + @Bean + public MetaServerConnectionFactory metaServerConnectionFactory() { + return new MetaServerConnectionFactory(); + } + + @Bean(name = "serverHandlers") + public Collection serverHandlers(DataServerConfig dataServerBootstrapConfig) { + Collection list = new ArrayList<>(); + list.add(getDataHandler()); + list.add(clientOffHandler()); + list.add(getDataVersionsHandler()); + list.add(publishDataProcessor(dataServerBootstrapConfig)); + list.add(sessionServerRegisterHandler()); + list.add(unPublishDataHandler()); + list.add(dataServerConnectionHandler()); + return list; + } + + @Bean(name = "serverSyncHandlers") + public Collection serverSyncHandlers(DataServerConfig dataServerBootstrapConfig) { + Collection list = new ArrayList<>(); + list.add(getDataHandler()); + list.add(publishDataProcessor(dataServerBootstrapConfig)); + list.add(unPublishDataHandler()); + list.add(notifyFetchDatumHandler()); + list.add(notifyOnlineHandler()); + list.add(syncDataHandler()); + list.add(dataSyncServerConnectionHandler()); + return list; + } + + @Bean(name = "dataClientHandlers") + public Collection dataClientHandlers() { + Collection list = new ArrayList<>(); + list.add(notifyDataSyncHandler()); + list.add(fetchDataHandler()); + return list; + } + + @Bean(name = "metaClientHandlers") + public Collection metaClientHandlers() { + Collection list = new ArrayList<>(); + list.add(serverChangeHandler()); + list.add(statusConfirmHandler()); + return list; + } + + @Bean + public AbstractServerHandler dataServerConnectionHandler() { + return new DataServerConnectionHandler(); + } + + @Bean + public AbstractServerHandler dataSyncServerConnectionHandler() { + return new DataSyncServerConnectionHandler(); + } + + @Bean + public AbstractServerHandler getDataHandler() { + return new GetDataHandler(); + } + + @Bean + public AbstractServerHandler getDataVersionsHandler() { + return new GetDataVersionsHandler(); + } + + @Bean + public AbstractServerHandler clientOffHandler() { + return new ClientOffHandler(); + } + + @Bean + public AbstractServerHandler publishDataProcessor(DataServerConfig dataServerBootstrapConfig) { + return new PublishDataHandler(dataServerBootstrapConfig); + } + + @Bean + public AbstractServerHandler sessionServerRegisterHandler() { + return new SessionServerRegisterHandler(); + } + + @Bean + public AbstractServerHandler unPublishDataHandler() { + return new UnPublishDataHandler(); + } + + @Bean + public AbstractServerHandler notifyFetchDatumHandler() { + return new NotifyFetchDatumHandler(); + } + + @Bean + public AbstractServerHandler notifyOnlineHandler() { + return new NotifyOnlineHandler(); + } + + @Bean + public AbstractServerHandler syncDataHandler() { + return new SyncDataHandler(); + } + + @Bean + public AbstractClientHandler notifyDataSyncHandler() { + return new NotifyDataSyncHandler(); + } + + @Bean + public AbstractClientHandler fetchDataHandler() { + return new FetchDataHandler(); + } + + @Bean + public AbstractClientHandler serverChangeHandler() { + return new ServerChangeHandler(); + } + + @Bean + public AbstractClientHandler statusConfirmHandler() { + return new StatusConfirmHandler(); + } + } + + @Configuration + public static class DataServerNotifyBeanConfiguration { + @Bean + public DataChangeHandler dataChangeHandler() { + return new DataChangeHandler(); + } + + @Bean + public SessionServerNotifier sessionServerNotifier() { + return new SessionServerNotifier(); + } + + @Bean + public TempPublisherNotifier tempPublisherNotifier() { + return new TempPublisherNotifier(); + } + + @Bean + public BackUpNotifier backUpNotifier() { + return new BackUpNotifier(); + } + + @Bean(name = "dataChangeNotifiers") + public List dataChangeNotifiers(DataServerConfig dataServerBootstrapConfig) { + List list = new ArrayList<>(); + list.add(sessionServerNotifier()); + list.add(tempPublisherNotifier()); + list.add(backUpNotifier()); + return list; + } + } + + @Configuration + public static class DataServerSyncBeanConfiguration { + + @Bean + public SyncDataService syncDataService() { + return new SyncDataServiceImpl(); + } + + @Bean + public AcceptorStore localAcceptorStore() { + return new LocalAcceptorStore(); + } + + @Bean + public Scheduler syncDataScheduler() { + return new Scheduler(); + } + + @Bean + public StoreServiceFactory storeServiceFactory() { + return new StoreServiceFactory(); + } + } + + @Configuration + public static class DataServerEventBeanConfiguration { + + @Bean + public DataServerChangeEventHandler dataServerChangeEventHandler() { + return new DataServerChangeEventHandler(); + } + + @Bean + public LocalDataServerChangeEventHandler localDataServerChangeEventHandler() { + return new LocalDataServerChangeEventHandler(); + } + + @Bean + public MetaServerChangeEventHandler metaServerChangeEventHandler() { + return new MetaServerChangeEventHandler(); + } + + @Bean + public StartTaskEventHandler startTaskEventHandler() { + return new StartTaskEventHandler(); + } + + @Bean + public LocalDataServerCleanHandler localDataServerCleanHandler() { + return new LocalDataServerCleanHandler(); + } + + @Bean + public GetSyncDataHandler getSyncDataHandler() { + return new GetSyncDataHandler(); + } + + @Bean + public DisconnectEventHandler disconnectEventHandler() { + return new DisconnectEventHandler(); + } + + @Bean + public EventCenter eventCenter() { + return new EventCenter(); + } + + @Bean + public DataChangeEventCenter dataChangeEventCenter() { + return new DataChangeEventCenter(); + } + } + + @Configuration + public static class DataServerRemotingBeanConfiguration { + + @Bean + public ConnectionRefreshTask connectionRefreshTask() { + return new ConnectionRefreshTask(); + } + + @Bean + public ConnectionRefreshMetaTask connectionRefreshMetaTask() { + return new ConnectionRefreshMetaTask(); + } + + @Bean + public ReNewNodeTask reNewNodeTask() { + return new ReNewNodeTask(); + } + + @Bean(name = "tasks") + public List tasks() { + List list = new ArrayList<>(); + list.add(connectionRefreshTask()); + list.add(connectionRefreshMetaTask()); + list.add(reNewNodeTask()); + return list; + } + + @Bean + public IMetaServerService metaServerService() { + return new DefaultMetaServiceImpl(); + } + } + + @Configuration + public static class ResourceConfiguration { + + @Bean + public ResourceConfig jerseyResourceConfig() { + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.register(JacksonFeature.class); + return resourceConfig; + } + + @Bean + public HealthResource healthResource() { + return new HealthResource(); + } + + @Bean + public DataDigestResource dataDigestResource() { + return new DataDigestResource(); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBootstrap.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBootstrap.java new file mode 100644 index 000000000..02bec192f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerBootstrap.java @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.bootstrap; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.data.datasync.sync.Scheduler; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.event.MetaServerChangeEvent; +import com.alipay.sofa.registry.server.data.event.StartTaskEvent; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; + +import javax.annotation.Resource; +import javax.ws.rs.Path; +import javax.ws.rs.ext.Provider; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * + * @author qian.lqlq + * @version $Id: DataServerBootstrap.java, v 0.1 2017-12-06 20:50 qian.lqlq Exp $ + */ +@EnableConfigurationProperties +public class DataServerBootstrap { + private static final Logger LOGGER = LoggerFactory + .getLogger(DataServerBootstrap.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private IMetaServerService metaServerService; + + @Autowired + private Scheduler syncDataScheduler; + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private ResourceConfig jerseyResourceConfig; + + @Autowired + private Exchange jerseyExchange; + + @Autowired + private Exchange boltExchange; + + @Autowired + private EventCenter eventCenter; + + @Resource(name = "serverHandlers") + private Collection serverHandlers; + + @Resource(name = "serverSyncHandlers") + private Collection serverSyncHandlers; + + private Server server; + + private Server dataSyncServer; + + private Server httpServer; + + private AtomicBoolean httpServerStarted = new AtomicBoolean(false); + + private AtomicBoolean schedulerStarted = new AtomicBoolean(false); + + private AtomicBoolean serverForSessionStarted = new AtomicBoolean(false); + + private AtomicBoolean serverForDataSyncStarted = new AtomicBoolean(false); + + /** + * start dataserver + */ + public void start() { + try { + LOGGER.info("[DataServerBootstrap] begin start server"); + + openDataServer(); + + openDataSyncServer(); + + openHttpServer(); + + startRaftClient(); + + startScheduler(); + + Runtime.getRuntime().addShutdownHook(new Thread(this::doStop)); + + LOGGER.info("[DataServerBootstrap] start server success"); + } catch (Exception e) { + throw new RuntimeException("[DataServerBootstrap] start server error", e); + } + } + + private void openDataServer() { + try { + if (serverForSessionStarted.compareAndSet(false, true)) { + server = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(), + dataServerBootstrapConfig.getPort()), serverHandlers + .toArray(new ChannelHandler[serverHandlers.size()])); + LOGGER.info("Data server for session started! port:{}", + dataServerBootstrapConfig.getPort()); + } + } catch (Exception e) { + serverForSessionStarted.set(false); + LOGGER + .error("Data server start error! port:{}", dataServerBootstrapConfig.getPort(), e); + throw new RuntimeException("Data server start error!", e); + } + } + + private void openDataSyncServer() { + try { + if (serverForDataSyncStarted.compareAndSet(false, true)) { + dataSyncServer = boltExchange.open(new URL(NetUtil.getLocalAddress() + .getHostAddress(), dataServerBootstrapConfig.getSyncDataPort()), + serverSyncHandlers.toArray(new ChannelHandler[serverSyncHandlers.size()])); + LOGGER.info("Data server for sync started! port:{}", + dataServerBootstrapConfig.getSyncDataPort()); + } + } catch (Exception e) { + serverForDataSyncStarted.set(false); + LOGGER.error("Data sync server start error! port:{}", + dataServerBootstrapConfig.getSyncDataPort(), e); + throw new RuntimeException("Data sync server start error!", e); + } + } + + private void openHttpServer() { + try { + if (httpServerStarted.compareAndSet(false, true)) { + bindResourceConfig(); + httpServer = jerseyExchange.open( + new URL(NetUtil.getLocalAddress().getHostAddress(), dataServerBootstrapConfig + .getHttpServerPort()), new ResourceConfig[] { jerseyResourceConfig }); + LOGGER.info("Open http server port {} success!", + dataServerBootstrapConfig.getHttpServerPort()); + } + } catch (Exception e) { + httpServerStarted.set(false); + LOGGER.error("Open http server port {} error!", + dataServerBootstrapConfig.getHttpServerPort(), e); + throw new RuntimeException("Open http server error!", e); + } + } + + private void startRaftClient() { + metaServerService.startRaftClient(); + eventCenter.post(new MetaServerChangeEvent(metaServerService.getMetaServerMap())); + LOGGER.info("[DataServerBootstrap] raft client started!Leader is {}", + metaServerService.getLeader()); + } + + private void startScheduler() { + try { + if (schedulerStarted.compareAndSet(false, true)) { + syncDataScheduler.startScheduler(); + eventCenter.post(StartTaskEvent.getInstance()); + } + } catch (Exception e) { + schedulerStarted.set(false); + LOGGER.error("Data Scheduler start error!", e); + throw new RuntimeException("Data Scheduler start error!", e); + } + } + + public void destroy() { + doStop(); + } + + private void doStop() { + try { + LOGGER.info("{} Shutting down Data Server..", new Date().toString()); + + if (httpServer != null && httpServer.isOpen()) { + httpServer.close(); + } + + if (server != null && server.isOpen()) { + server.close(); + } + + if (dataSyncServer != null && dataSyncServer.isOpen()) { + dataSyncServer.close(); + } + + if (syncDataScheduler != null) { + syncDataScheduler.stopScheduler(); + } + } catch (Throwable e) { + LOGGER.error("Shutting down Data Server error!", e); + } + LOGGER.info("{} Data server is now shutdown...", new Date().toString()); + } + + private void bindResourceConfig() { + registerInstances(Path.class); + registerInstances(Provider.class); + } + + private void registerInstances(Class annotationType) { + Map beans = applicationContext.getBeansWithAnnotation(annotationType); + if (beans != null && !beans.isEmpty()) { + beans.forEach((beanName, bean) -> jerseyResourceConfig.registerInstances(bean)); + } + } + + public AtomicBoolean getHttpServerStarted() { + return httpServerStarted; + } + + public AtomicBoolean getSchedulerStarted() { + return schedulerStarted; + } + + public AtomicBoolean getServerForSessionStarted() { + return serverForSessionStarted; + } + + public AtomicBoolean getServerForDataSyncStarted() { + return serverForDataSyncStarted; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerConfig.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerConfig.java new file mode 100644 index 000000000..4d801b711 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerConfig.java @@ -0,0 +1,602 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.bootstrap; + +import com.alipay.sofa.registry.net.NetUtil; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * + * + * @author qian.lqlq + * @version $Id: DataServerBootstrapConfig.java, v 0.1 2017-12-06 20:50 qian.lqlq Exp $ + */ +@ConfigurationProperties(prefix = DataServerConfig.PRE_FIX) +public class DataServerConfig { + + public static final String PRE_FIX = "data.server"; + + public static final String IP = NetUtil.getLocalAddress() + .getHostAddress(); + + private int port; + + private int syncDataPort; + + private int metaServerPort; + + private int httpServerPort; + + private int queueCount; + + private int queueSize; + + private int notifyIntervalMs; + + private int clientOffDelayMs; + + private int rpcTimeout; + + private CommonConfig commonConfig; + + private Set metaIps = null; + + private int storeNodes = 3; + + private int numberOfReplicas = 1000; + + private long localDataServerCleanDelay = 1000 * 60 * 30; + + private int getDataExecutorMinPoolSize = 80; + + private int getDataExecutorMaxPoolSize = 400; + + private int getDataExecutorQueueSize = 10000; + + private long getDataExecutorKeepAliveTime = 60; + + private int notifyDataSyncExecutorMinPoolSize = 80; + + private int notifyDataSyncExecutorMaxPoolSize = 400; + + private int notifyDataSyncExecutorQueueSize = 700; + + private long notifyDataSyncExecutorKeepAliveTime = 60; + + private long notifySessionRetryFirstDelay = 1000; + + private long notifySessionRetryIncrementDelay = 1000; + + private int notifySessionRetryTimes = 10; + + private int publishExecutorMinPoolSize = 80; + + private int publishExecutorMaxPoolSize = 400; + + private int publishExecutorQueueSize = 10000; + + /** + * constructor + * @param commonConfig + */ + public DataServerConfig(CommonConfig commonConfig) { + this.commonConfig = commonConfig; + } + + public String getLocalDataCenter() { + return commonConfig.getLocalDataCenter(); + } + + /** + * Getter method for property port. + * + * @return property value of port + */ + public int getPort() { + return port; + } + + /** + * Setter method for property port. + * + * @param port value to be assigned to property port + */ + public void setPort(int port) { + this.port = port; + } + + /** + * Getter method for property syncDataPort. + * + * @return property value of syncDataPort + */ + public int getSyncDataPort() { + return syncDataPort; + } + + /** + * Setter method for property syncDataPort. + * + * @param syncDataPort value to be assigned to property syncDataPort + */ + public void setSyncDataPort(int syncDataPort) { + this.syncDataPort = syncDataPort; + } + + /** + * Getter method for property metaServerPort. + * + * @return property value of metaServerPort + */ + public int getMetaServerPort() { + return metaServerPort; + } + + /** + * Setter method for property metaServerPort. + * + * @param metaServerPort value to be assigned to property metaServerPort + */ + public void setMetaServerPort(int metaServerPort) { + this.metaServerPort = metaServerPort; + } + + /** + * Getter method for property httpServerPort. + * + * @return property value of httpServerPort + */ + public int getHttpServerPort() { + return httpServerPort; + } + + /** + * Setter method for property httpServerPort. + * + * @param httpServerPort value to be assigned to property httpServerPort + */ + public void setHttpServerPort(int httpServerPort) { + this.httpServerPort = httpServerPort; + } + + /** + * Getter method for property queueCount. + * + * @return property value of queueCount + */ + public int getQueueCount() { + return queueCount; + } + + /** + * Setter method for property queueCount. + * + * @param queueCount value to be assigned to property queueCount + */ + public void setQueueCount(int queueCount) { + this.queueCount = queueCount; + } + + /** + * Getter method for property queueSize. + * + * @return property value of queueSize + */ + public int getQueueSize() { + return queueSize; + } + + /** + * Setter method for property queueSize. + * + * @param queueSize value to be assigned to property queueSize + */ + public void setQueueSize(int queueSize) { + this.queueSize = queueSize; + } + + /** + * Getter method for property notifyIntervalMs. + * + * @return property value of notifyIntervalMs + */ + public int getNotifyIntervalMs() { + return notifyIntervalMs; + } + + /** + * Setter method for property notifyIntervalMs. + * + * @param notifyIntervalMs value to be assigned to property notifyIntervalMs + */ + public void setNotifyIntervalMs(int notifyIntervalMs) { + this.notifyIntervalMs = notifyIntervalMs; + } + + /** + * Getter method for property rpcTimeout. + * + * @return property value of rpcTimeout + */ + public int getRpcTimeout() { + return rpcTimeout; + } + + /** + * Setter method for property rpcTimeout. + * + * @param rpcTimeout value to be assigned to property rpcTimeout + */ + public void setRpcTimeout(int rpcTimeout) { + this.rpcTimeout = rpcTimeout; + } + + /** + * Getter method for property storeNodes. + * + * @return property value of storeNodes + */ + public int getStoreNodes() { + return storeNodes; + } + + /** + * Setter method for property storeNodes. + * + * @param storeNodes value to be assigned to property storeNodes + */ + public void setStoreNodes(int storeNodes) { + this.storeNodes = storeNodes; + } + + /** + * Getter method for property numberOfReplicas. + * + * @return property value of numberOfReplicas + */ + public int getNumberOfReplicas() { + return numberOfReplicas; + } + + /** + * Setter method for property numberOfReplicas. + * + * @param numberOfReplicas value to be assigned to property numberOfReplicas + */ + public void setNumberOfReplicas(int numberOfReplicas) { + this.numberOfReplicas = numberOfReplicas; + } + + /** + * Getter method for property localDataServerCleanDelay. + * + * @return property value of localDataServerCleanDelay + */ + public long getLocalDataServerCleanDelay() { + return localDataServerCleanDelay; + } + + /** + * Setter method for property localDataServerCleanDelay. + * + * @param localDataServerCleanDelay value to be assigned to property localDataServerCleanDelay + */ + public void setLocalDataServerCleanDelay(long localDataServerCleanDelay) { + this.localDataServerCleanDelay = localDataServerCleanDelay; + } + + /** + * Getter method for property getDataExecutorMinPoolSize. + * + * @return property value of getDataExecutorMinPoolSize + */ + public int getGetDataExecutorMinPoolSize() { + return getDataExecutorMinPoolSize; + } + + /** + * Getter method for property getDataExecutorMaxPoolSize. + * + * @return property value of getDataExecutorMaxPoolSize + */ + public int getGetDataExecutorMaxPoolSize() { + return getDataExecutorMaxPoolSize; + } + + /** + * Getter method for property getDataExecutorQueueSize. + * + * @return property value of getDataExecutorQueueSize + */ + public int getGetDataExecutorQueueSize() { + return getDataExecutorQueueSize; + } + + /** + * Getter method for property getDataExecutorKeepAliveTime. + * + * @return property value of getDataExecutorKeepAliveTime + */ + public long getGetDataExecutorKeepAliveTime() { + return getDataExecutorKeepAliveTime; + } + + /** + * Setter method for property getDataExecutorMinPoolSize. + * + * @param getDataExecutorMinPoolSize value to be assigned to property getDataExecutorMinPoolSize + */ + public void setGetDataExecutorMinPoolSize(int getDataExecutorMinPoolSize) { + this.getDataExecutorMinPoolSize = getDataExecutorMinPoolSize; + } + + /** + * Setter method for property getDataExecutorMaxPoolSize. + * + * @param getDataExecutorMaxPoolSize value to be assigned to property getDataExecutorMaxPoolSize + */ + public void setGetDataExecutorMaxPoolSize(int getDataExecutorMaxPoolSize) { + this.getDataExecutorMaxPoolSize = getDataExecutorMaxPoolSize; + } + + /** + * Setter method for property getDataExecutorQueueSize. + * + * @param getDataExecutorQueueSize value to be assigned to property getDataExecutorQueueSize + */ + public void setGetDataExecutorQueueSize(int getDataExecutorQueueSize) { + this.getDataExecutorQueueSize = getDataExecutorQueueSize; + } + + /** + * Setter method for property getDataExecutorKeepAliveTime. + * + * @param getDataExecutorKeepAliveTime value to be assigned to property getDataExecutorKeepAliveTime + */ + public void setGetDataExecutorKeepAliveTime(long getDataExecutorKeepAliveTime) { + this.getDataExecutorKeepAliveTime = getDataExecutorKeepAliveTime; + } + + /** + * Getter method for property notifyDataSyncExecutorMinPoolSize. + * + * @return property value of notifyDataSyncExecutorMinPoolSize + */ + public int getNotifyDataSyncExecutorMinPoolSize() { + return notifyDataSyncExecutorMinPoolSize; + } + + /** + * Setter method for property notifyDataSyncExecutorMinPoolSize. + * + * @param notifyDataSyncExecutorMinPoolSize value to be assigned to property notifyDataSyncExecutorMinPoolSize + */ + public void setNotifyDataSyncExecutorMinPoolSize(int notifyDataSyncExecutorMinPoolSize) { + this.notifyDataSyncExecutorMinPoolSize = notifyDataSyncExecutorMinPoolSize; + } + + /** + * Getter method for property notifyDataSyncExecutorMaxPoolSize. + * + * @return property value of notifyDataSyncExecutorMaxPoolSize + */ + public int getNotifyDataSyncExecutorMaxPoolSize() { + return notifyDataSyncExecutorMaxPoolSize; + } + + /** + * Setter method for property notifyDataSyncExecutorMaxPoolSize. + * + * @param notifyDataSyncExecutorMaxPoolSize value to be assigned to property notifyDataSyncExecutorMaxPoolSize + */ + public void setNotifyDataSyncExecutorMaxPoolSize(int notifyDataSyncExecutorMaxPoolSize) { + this.notifyDataSyncExecutorMaxPoolSize = notifyDataSyncExecutorMaxPoolSize; + } + + /** + * Getter method for property notifyDataSyncExecutorQueueSize. + * + * @return property value of notifyDataSyncExecutorQueueSize + */ + public int getNotifyDataSyncExecutorQueueSize() { + return notifyDataSyncExecutorQueueSize; + } + + /** + * Setter method for property notifyDataSyncExecutorQueueSize. + * + * @param notifyDataSyncExecutorQueueSize value to be assigned to property notifyDataSyncExecutorQueueSize + */ + public void setNotifyDataSyncExecutorQueueSize(int notifyDataSyncExecutorQueueSize) { + this.notifyDataSyncExecutorQueueSize = notifyDataSyncExecutorQueueSize; + } + + /** + * Getter method for property notifyDataSyncExecutorKeepAliveTime. + * + * @return property value of notifyDataSyncExecutorKeepAliveTime + */ + public long getNotifyDataSyncExecutorKeepAliveTime() { + return notifyDataSyncExecutorKeepAliveTime; + } + + /** + * Setter method for property notifyDataSyncExecutorKeepAliveTime. + * + * @param notifyDataSyncExecutorKeepAliveTime value to be assigned to property notifyDataSyncExecutorKeepAliveTime + */ + public void setNotifyDataSyncExecutorKeepAliveTime(long notifyDataSyncExecutorKeepAliveTime) { + this.notifyDataSyncExecutorKeepAliveTime = notifyDataSyncExecutorKeepAliveTime; + } + + /** + * Getter method for property notifySessionRetryFirstDelay. + * + * @return property value of notifySessionRetryFirstDelay + */ + public long getNotifySessionRetryFirstDelay() { + return notifySessionRetryFirstDelay; + } + + /** + * Setter method for property notifySessionRetryFirstDelay. + * + * @param notifySessionRetryFirstDelay value to be assigned to property notifySessionRetryFirstDelay + */ + public void setNotifySessionRetryFirstDelay(long notifySessionRetryFirstDelay) { + this.notifySessionRetryFirstDelay = notifySessionRetryFirstDelay; + } + + /** + * Getter method for property notifySessionRetryIncrementDelay. + * + * @return property value of notifySessionRetryIncrementDelay + */ + public long getNotifySessionRetryIncrementDelay() { + return notifySessionRetryIncrementDelay; + } + + /** + * Setter method for property notifySessionRetryIncrementDelay. + * + * @param notifySessionRetryIncrementDelay value to be assigned to property notifySessionRetryIncrementDelay + */ + public void setNotifySessionRetryIncrementDelay(long notifySessionRetryIncrementDelay) { + this.notifySessionRetryIncrementDelay = notifySessionRetryIncrementDelay; + } + + /** + * Getter method for property clientOffDelayMs. + * + * @return property value of clientOffDelayMs + */ + public int getClientOffDelayMs() { + return clientOffDelayMs; + } + + /** + * Setter method for property clientOffDelayMs. + * + * @param clientOffDelayMs value to be assigned to property clientOffDelayMs + */ + public void setClientOffDelayMs(int clientOffDelayMs) { + this.clientOffDelayMs = clientOffDelayMs; + } + + /** + * Getter method for property publishExecutorMinPoolSize. + * + * @return property value of publishExecutorMinPoolSize + */ + public int getPublishExecutorMinPoolSize() { + return publishExecutorMinPoolSize; + } + + /** + * Setter method for property publishExecutorMinPoolSize. + * + * @param publishExecutorMinPoolSize value to be assigned to property publishExecutorMinPoolSize + */ + public void setPublishExecutorMinPoolSize(int publishExecutorMinPoolSize) { + this.publishExecutorMinPoolSize = publishExecutorMinPoolSize; + } + + /** + * Getter method for property publishExecutorMaxPoolSize. + * + * @return property value of publishExecutorMaxPoolSize + */ + public int getPublishExecutorMaxPoolSize() { + return publishExecutorMaxPoolSize; + } + + /** + * Setter method for property publishExecutorMaxPoolSize. + * + * @param publishExecutorMaxPoolSize value to be assigned to property publishExecutorMaxPoolSize + */ + public void setPublishExecutorMaxPoolSize(int publishExecutorMaxPoolSize) { + this.publishExecutorMaxPoolSize = publishExecutorMaxPoolSize; + } + + /** + * Getter method for property publishExecutorQueueSize. + * + * @return property value of publishExecutorQueueSize + */ + public int getPublishExecutorQueueSize() { + return publishExecutorQueueSize; + } + + /** + * Setter method for property publishExecutorQueueSize. + * + * @param publishExecutorQueueSize value to be assigned to property publishExecutorQueueSize + */ + public void setPublishExecutorQueueSize(int publishExecutorQueueSize) { + this.publishExecutorQueueSize = publishExecutorQueueSize; + } + + /** + * Getter method for property metaServerIpAddress. + * + * @return property value of metaServerIpAddress + */ + public Set getMetaServerIpAddresses() { + if (metaIps != null && !metaIps.isEmpty()) { + return metaIps; + } + metaIps = new HashSet<>(); + if (commonConfig != null) { + Map> metaMap = commonConfig.getMetaNode(); + if (metaMap != null && !metaMap.isEmpty()) { + String localDataCenter = commonConfig.getLocalDataCenter(); + if (localDataCenter != null && !localDataCenter.isEmpty()) { + Collection metas = metaMap.get(localDataCenter); + if (metas != null && !metas.isEmpty()) { + metaIps = metas.stream().map(NetUtil::getIPAddressFromDomain).collect(Collectors.toSet()); + } + } + } + } + return metaIps; + } + + /** + * Getter method for property notifySessionRetryTimes. + * + * @return property value of notifySessionRetryTimes + */ + public int getNotifySessionRetryTimes() { + return notifySessionRetryTimes; + } + + /** + * Setter method for property notifySessionRetryTimes . + * + * @param notifySessionRetryTimes value to be assigned to property notifySessionRetryTimes + */ + public void setNotifySessionRetryTimes(int notifySessionRetryTimes) { + this.notifySessionRetryTimes = notifySessionRetryTimes; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerInitializer.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerInitializer.java new file mode 100644 index 000000000..3c1fe5b41 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/DataServerInitializer.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.bootstrap; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.SmartLifecycle; + +/** + * + * @author qian.lqlq + * @version $Id: DataServerInitializer.java, v 0.1 2018年01月04日 11:08 qian.lqlq Exp $ + */ +public class DataServerInitializer implements SmartLifecycle { + + @Autowired + private DataServerBootstrap dataServerBootstrap; + + private volatile boolean isRunning; + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void stop(Runnable runnable) { + runnable.run(); + this.isRunning = false; + } + + @Override + public void start() { + dataServerBootstrap.start(); + this.isRunning = true; + } + + @Override + public void stop() { + this.isRunning = false; + } + + @Override + public boolean isRunning() { + return this.isRunning; + } + + @Override + public int getPhase() { + return 0; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/EnableDataServer.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/EnableDataServer.java new file mode 100644 index 000000000..d42b85691 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/bootstrap/EnableDataServer.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.bootstrap; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author shangyu.wh + * @version $Id: EnableSessionServer.java, v 0.1 2017-11-14 11:38 synex Exp $ + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(DataServerBeanConfiguration.class) +public @interface EnableDataServer { +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/BackupTriad.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/BackupTriad.java new file mode 100644 index 000000000..35c49566f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/BackupTriad.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.consistency.hash.ConsistentHash; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: BackupTriad.java, v 0.1 2018-04-28 23:41 qian.lqlq Exp $ + */ +public class BackupTriad { + /** dataInfoId */ + private String dataInfoId; + + /** + * calculate current dataServer list Consistent hash to get dataInfoId belong node and backup node list + * @see ConsistentHash#ConsistentHash(int, java.util.Collection) + * @see com.alipay.sofa.registry.consistency.hash.ConsistentHash#getNUniqueNodesFor(java.lang.Object, int) + */ + private List triad; + + private Set ipSetOfNode = new HashSet<>(); + + /** + * constructor + * @param dataInfoId + * @param triad + */ + public BackupTriad(String dataInfoId, List triad) { + this.dataInfoId = dataInfoId; + this.triad = triad; + for (DataNode node : triad) { + ipSetOfNode.add(node.getIp()); + } + } + + /** + * check contains current node + * @return + */ + public boolean containsSelf() { + return !ipSetOfNode.isEmpty() && ipSetOfNode.contains(DataServerConfig.IP); + } + + /** + * get new joined nodes + * + * @param newTriad + * @return + */ + public List getNewJoined(List newTriad, Set notWorking) { + List list = new ArrayList<>(); + for (DataNode node : newTriad) { + String ip = node.getIp(); + if (!ipSetOfNode.contains(ip) || notWorking.contains(ip)) { + list.add(node); + } + } + return list; + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Setter method for property dataInfoId. + * + * @param dataInfoId value to be assigned to property dataInfoId + */ + public void setDataInfoId(String dataInfoId) { + this.dataInfoId = dataInfoId; + } + + /** + * Getter method for property triad. + * + * @return property value of triad + */ + public List getTriad() { + return triad; + } + + /** + * Setter method for property triad. + * + * @param triad value to be assigned to property triad + */ + public void setTriad(List triad) { + this.triad = triad; + Set ipSetOfNode = new HashSet<>(); + for (DataNode node : triad) { + ipSetOfNode.add(node.getIp()); + } + this.ipSetOfNode = ipSetOfNode; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("BackupTriad{"); + sb.append("dataInfoId='").append(dataInfoId).append('\''); + sb.append(", ipSetOfNode=").append(ipSetOfNode); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/CacheDigestTask.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/CacheDigestTask.java new file mode 100644 index 000000000..5b09ddb31 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/CacheDigestTask.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import org.springframework.util.CollectionUtils; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author qian.lqlq + * @version $Id: CacheDigestTask.java, v 0.1 2018-04-27 17:40 qian.lqlq Exp $ + */ +public class CacheDigestTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(CacheDigestTask.class); + + /** + * + */ + public void start() { + ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("CacheDigestTask")); + executor.scheduleAtFixedRate(() -> { + try { + Map> allMap = DatumCache.getAll(); + if (!allMap.isEmpty()) { + for (Entry> dataCenterEntry : allMap.entrySet()) { + String dataCenter = dataCenterEntry.getKey(); + Map datumMap = dataCenterEntry.getValue(); + LOGGER.info("[CacheDigestTask] size of datum in {} is {}", + dataCenter, datumMap.size()); + for (Entry dataInfoEntry : datumMap.entrySet()) { + String dataInfoId = dataInfoEntry.getKey(); + Datum data = dataInfoEntry.getValue(); + Map pubMap = data.getPubMap(); + StringBuilder pubStr = new StringBuilder(); + if (!CollectionUtils.isEmpty(pubMap)) { + for (Publisher publisher : pubMap.values()) { + pubStr.append(logPublisher(publisher)).append(";"); + } + } + LOGGER.info( + "[Datum] dataInfoId={}, version={}, dataCenter={}, publishers=[{}]", + dataInfoId, data.getVersion(), dataCenter, pubStr.toString()); + } + int pubCount = datumMap.values().stream().map(Datum::getPubMap) + .filter(map -> map != null && !map.isEmpty()).mapToInt(Map::size).sum(); + LOGGER.info("[CacheDigestTask] size of publisher in {} is {}", + dataCenter, pubCount); + } + } else { + LOGGER.info("[CacheDigestTask] datum cache is empty"); + } + + } catch (Throwable t) { + LOGGER.error("[CacheDigestTask] cache digest error", t); + } + }, 30, 300, TimeUnit.SECONDS); + } + + private String logPublisher(Publisher publisher) { + if (publisher != null) { + URL url = publisher.getSourceAddress(); + String urlStr = url != null ? url.getAddressString() : "null"; + return String.format("dataInfoId=%s, version=%s, host=%s, registerId=%s", + publisher.getDataInfoId(), publisher.getVersion(), urlStr, + publisher.getRegisterId()); + } + return ""; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerCache.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerCache.java new file mode 100644 index 000000000..163d633ff --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerCache.java @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.consistency.hash.ConsistentHash; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.node.DataNodeStatus; +import com.alipay.sofa.registry.server.data.util.LocalServerStatusEnum; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; + +/** + * cache of dataservers + * + * @author qian.lqlq + * @version $Id: DataServerCache.java, v 0.1 2018-05-05 17:00 qian.lqlq Exp $ + */ +public class DataServerCache { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataServerCache.class); + + @Autowired + private DataNodeStatus dataNodeStatus; + + @Autowired + private DataServerConfig dataServerConfig; + + private volatile DataServerChangeItem dataServerChangeItem = new DataServerChangeItem(); + + private volatile DataServerChangeItem newDataServerChangeItem = new DataServerChangeItem(); + + private final AtomicBoolean HAS_NOTIFY_ALL = new AtomicBoolean( + false); + + private AtomicLong curVersion = new AtomicLong( + -1L); + + /** version -> Map(serverIp, serverStatus) */ + private Map> nodeStatusMap = new ConcurrentHashMap<>(); + + /** + * compare new infos and cached infos, and return these changed + * + * @param newItem + * @return changedMap(datacenter, serverIp) + */ + public Map> compareAndSet(DataServerChangeItem newItem) { + synchronized (DataServerCache.class) { + // versionMap: datacenter -> version + Map newVersionMap = newItem.getVersionMap(); + //check current run newItem same + Map currentNewVersionMap = newDataServerChangeItem.getVersionMap(); + if (!currentNewVersionMap.isEmpty()) { + AtomicBoolean isTheSame = new AtomicBoolean(true); + if (newVersionMap.size() == currentNewVersionMap.size()) { + for (Entry entry : newVersionMap.entrySet()) { + String dataCenter = entry.getKey(); + Long version = entry.getValue(); + Long currentVersion = currentNewVersionMap.get(dataCenter); + if (currentVersion != null && version != null) { + if (currentVersion.longValue() != version.longValue()) { + isTheSame.set(false); + break; + } + } else { + if (currentVersion != null || version != null) { + isTheSame.set(false); + break; + } + } + } + } else { + isTheSame.set(false); + } + if (isTheSame.get()) { + LOGGER + .info( + "current process map has a same version as change map,this change will be ignored!process version={},get version={}", + currentNewVersionMap, newVersionMap); + return new HashMap<>(); + } + } + + Map> changedMap = new HashMap<>(); + Map oldVersionMap = new HashMap<>(dataServerChangeItem.getVersionMap()); + Map> newServerMap = newItem.getServerMap(); + + for (Entry dataCenterEntry : newVersionMap.entrySet()) { + String dataCenter = dataCenterEntry.getKey(); + if (oldVersionMap.containsKey(dataCenter)) { + Long oldVersion = oldVersionMap.remove(dataCenter); + if (oldVersion >= dataCenterEntry.getValue()) { + continue; + } + } + changedMap.put(dataCenter, newServerMap.get(dataCenter).keySet()); + } + if (!oldVersionMap.isEmpty()) { + for (String dataCenter : oldVersionMap.keySet()) { + changedMap.put(dataCenter, new HashSet<>()); + } + } + if (changedMap.containsKey(dataServerConfig.getLocalDataCenter())) { + init(newVersionMap.get(dataServerConfig.getLocalDataCenter())); + } + if (!changedMap.isEmpty()) { + LOGGER.info("old server map = {}", dataServerChangeItem.getServerMap()); + LOGGER.info("new server map = {}", newServerMap); + LOGGER.info("new server version map = {}", newVersionMap); + LOGGER.info("status map = {}", nodeStatusMap); + LOGGER.info("changed map = {}", changedMap); + newDataServerChangeItem = newItem; + } + return changedMap; + } + } + + private void init(long version) { + if (curVersion.compareAndSet(-1, version)) { + Map map = new ConcurrentHashMap<>(); + map.put(DataServerConfig.IP, LocalServerStatusEnum.INITIAL); + nodeStatusMap.put(version, map); + } else { + //first get dataChange after other data send init message + Map map = nodeStatusMap.get(curVersion.get()); + if (map != null) { + map.putIfAbsent(DataServerConfig.IP, LocalServerStatusEnum.INITIAL); + } + } + } + + private void addStatus(long version, String ip, LocalServerStatusEnum localServerStatusEnum) { + long lastVersion = curVersion.getAndSet(version); + Map map = nodeStatusMap.remove(lastVersion); + if (map != null) { + map.put(ip, localServerStatusEnum); + nodeStatusMap.put(curVersion.get(), map); + } else { + Map newMap = new ConcurrentHashMap<>(); + map = nodeStatusMap.putIfAbsent(curVersion.get(), newMap); + if (map == null) { + map = newMap; + } + map.put(ip, localServerStatusEnum); + } + } + + private void resetStatusMapToWorking() { + Map map = nodeStatusMap.get(curVersion.get()); + if (map != null) { + map.clear(); + map.put(DataServerConfig.IP, LocalServerStatusEnum.WORKING); + } + LOGGER.info("nodeStatusMap has been reset!Result {}", nodeStatusMap); + } + + public boolean removeNotifyNewStatusNode(String ip) { + synchronized (DataServerCache.class) { + Map map = nodeStatusMap.get(curVersion.get()); + if (map != null) { + LocalServerStatusEnum statusEnum = map.get(ip); + if (statusEnum != null && statusEnum == LocalServerStatusEnum.INITIAL) { + if (map.remove(ip) != null) { + LOGGER.info("nodeStatusMap remove init status node {}!Result {}", ip, + nodeStatusMap); + } + } + } + return false; + } + } + + public void synced(long version, String ip) { + synchronized (DataServerCache.class) { + if (version >= curVersion.get()) { + addStatus(version, ip, LocalServerStatusEnum.WORKING); + LOGGER.info("synced working = {}, version={},send ip={}", nodeStatusMap, version, + ip); + updateDataServerStatus(); + } + } + } + + public void addNotWorkingServer(long version, String ip) { + synchronized (DataServerCache.class) { + if (version >= curVersion.get()) { + addStatus(version, ip, LocalServerStatusEnum.INITIAL); + LOGGER.info("add not working = {}, version={},send ip={}", nodeStatusMap, version, + ip); + if (dataNodeStatus.getStatus() != LocalServerStatusEnum.WORKING) { + updateDataServerStatus(); + } + } + } + } + + private void updateDataServerStatus() { + if (dataNodeStatus.getStatus() != LocalServerStatusEnum.WORKING) { + + Long newVersion = newDataServerChangeItem.getVersionMap().get( + dataServerConfig.getLocalDataCenter()); + + if (newVersion == null) { + LOGGER.info("no node change receive from meta about current dataCenter!"); + return; + } + + if (newVersion != curVersion.get()) { + LOGGER.info("version not match,current {} push {}", curVersion.longValue(), + newVersion); + return; + } + + Map map = nodeStatusMap.get(curVersion.get()); + if (map != null) { + Set ips = map.keySet(); + if (!ips.containsAll(newDataServerChangeItem.getServerMap() + .get(dataServerConfig.getLocalDataCenter()).keySet())) { + LOGGER.info( + "nodeStatusMap not contains all push list,nodeStatusMap {} push {}", + nodeStatusMap, + newDataServerChangeItem.getServerMap() + .get(dataServerConfig.getLocalDataCenter()).keySet()); + return; + } + } else { + LOGGER.info("nodeStatusMap has not got other data node status!"); + return; + } + + if (!HAS_NOTIFY_ALL.get()) { + LOGGER.info("Has not notify all!"); + return; + } + + dataNodeStatus.setStatus(LocalServerStatusEnum.WORKING); + + //after working status,must clean this map,because calculate backupTriad need add not working node,see LocalDataServerChangeEventHandler getToBeSyncMap + resetStatusMapToWorking(); + } + } + + public Long getCurVersion() { + return curVersion.get(); + } + + public void notifiedAll() { + if (HAS_NOTIFY_ALL.compareAndSet(false, true)) { + updateDataServerStatus(); + } + } + + public void checkAndUpdateStatus(long version) { + synchronized (DataServerCache.class) { + if (version == curVersion.get()) { + updateDataServerStatus(); + } + } + } + + public Set getNotWorking() { + synchronized (DataServerCache.class) { + Set ret = new HashSet<>(); + Map map = nodeStatusMap.get(curVersion.get()); + if (map != null) { + map.forEach((ip, status) -> { + if (status != LocalServerStatusEnum.WORKING) { + ret.add(ip); + } + }); + } + return ret; + } + } + + public void updateItem(Map localDataNodes, Long version, String dataCenter) { + synchronized (DataServerCache.class) { + Long oldVersion = dataServerChangeItem.getVersionMap().get(dataCenter); + Map oldList = dataServerChangeItem.getServerMap().get(dataCenter); + Set oldIps = oldList == null ? new HashSet<>() : oldList.keySet(); + Set newIps = localDataNodes == null ? new HashSet<>() : localDataNodes.keySet(); + LOGGER.warn("Update DataCenter={} Item version from={} to={},nodeMap from={} to={}", + dataCenter, oldVersion, version, oldIps, newIps); + dataServerChangeItem.getServerMap().put(dataCenter, localDataNodes); + dataServerChangeItem.getVersionMap().put(dataCenter, version); + + } + } + + public Map getDataServers(String dataCenter) { + return getDataServers(dataCenter, dataServerChangeItem); + } + + public Map getDataServers(String dataCenter, + DataServerChangeItem dataServerChangeItem) { + return doGetDataServers(dataCenter, dataServerChangeItem); + } + + public Map getNewDataServerMap(String dataCenter) { + return doGetDataServers(dataCenter, newDataServerChangeItem); + } + + private Map doGetDataServers(String dataCenter, + DataServerChangeItem dataServerChangeItem) { + synchronized (DataServerCache.class) { + Map> dataserverMap = dataServerChangeItem.getServerMap(); + if (dataserverMap.containsKey(dataCenter)) { + return dataserverMap.get(dataCenter); + } else { + return new HashMap<>(); + } + } + } + + public Long getDataCenterNewVersion(String dataCenter) { + synchronized (DataServerCache.class) { + Map versionMap = newDataServerChangeItem.getVersionMap(); + if (versionMap.containsKey(dataCenter)) { + return versionMap.get(dataCenter); + } else { + return null; + } + } + } + + public BackupTriad calculateOldBackupTriad(String dataInfoId, String dataCenter, + DataServerConfig dataServerBootstrapConfig) { + Map> dataServerMap = dataServerChangeItem.getServerMap(); + Map dataNodeMap = dataServerMap.get(dataCenter); + + if (dataNodeMap != null && !dataNodeMap.isEmpty()) { + + Collection dataServerNodes = dataNodeMap.values(); + + ConsistentHash consistentHash = new ConsistentHash<>( + dataServerBootstrapConfig.getNumberOfReplicas(), dataServerNodes); + + List list = consistentHash.getNUniqueNodesFor(dataInfoId, + dataServerBootstrapConfig.getStoreNodes()); + + return new BackupTriad(dataInfoId, list); + } else { + LOGGER.warn("Calculate Old BackupTriad,old dataServer list is empty!"); + return null; + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerChangeItem.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerChangeItem.java new file mode 100644 index 000000000..e65f46c74 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DataServerChangeItem.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; + +import java.util.HashMap; +import java.util.Map; + +/** + * change info of datacenters + * + * @author qian.lqlq + * @version $Id: DataServerChangeItem.java, v 0.1 2018-05-05 17:37 qian.lqlq Exp $ + */ +public class DataServerChangeItem { + + /** datacenter -> Map */ + private Map> serverMap; + + /** datacenter -> version */ + private Map versionMap; + + /** + * constructor + */ + public DataServerChangeItem() { + this(new HashMap<>(), new HashMap<>()); + } + + /** + * constructor + * @param serverMap + * @param versionMap + */ + public DataServerChangeItem(Map> serverMap, + Map versionMap) { + this.serverMap = serverMap; + this.versionMap = versionMap; + } + + /** + * Getter method for property serverMap. + * + * @return property value of serverMap + */ + public Map> getServerMap() { + return serverMap; + } + + /** + * Getter method for property versionMap. + * + * @return property value of versionMap + */ + public Map getVersionMap() { + return versionMap; + } + + @Override + public String toString() { + return "DataServerChangeItem{" + "serverMap=" + serverMap + ", versionMap=" + versionMap + + '}'; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DatumCache.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DatumCache.java new file mode 100644 index 000000000..6b17f7702 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/DatumCache.java @@ -0,0 +1,309 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.server.data.change.DataChangeTypeEnum; +import org.springframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * cache of datum, providing query function to the upper module + * + * @author qian.lqlq + * @version $Id: DatumCache.java, v 0.1 2017-12-06 20:50 qian.lqlq Exp $ + */ +public class DatumCache { + + public static final long ERROR_DATUM_VERSION = -2L; + + /** + * row: dataCenter + * column: dataInfoId + * value: datum + */ + private static final Map> DATUM_MAP = new ConcurrentHashMap<>(); + + /** + * row: ip:port + * column: registerId + * value: publisher + */ + private static final Map> CLIENT_PUB_MAP = new ConcurrentHashMap<>(); + + /** + * get datum by specific dataCenter and dataInfoId + * + * @param dataCenter + * @param dataInfoId + * @return + */ + public static Datum get(String dataCenter, String dataInfoId) { + if (DATUM_MAP.containsKey(dataCenter)) { + Map map = DATUM_MAP.get(dataCenter); + if (map.containsKey(dataInfoId)) { + return map.get(dataInfoId); + } + } + return null; + } + + /** + * get datum of all datercenters by dataInfoId + * + * @param dataInfoId + * @return + */ + public static Map get(String dataInfoId) { + Map datumMap = new HashMap<>(); + DATUM_MAP.forEach((dataCenter, datums) -> { + if (datums.containsKey(dataInfoId)) { + datumMap.put(dataCenter, datums.get(dataInfoId)); + } + }); + + return datumMap; + } + + /** + * get datum group by dataCenter + * + * @param dataCenter + * @param dataInfoId + * @return + */ + public static Map getDatumGroupByDataCenter(String dataCenter, String dataInfoId) { + Map map = new HashMap<>(); + if (StringUtils.isEmpty(dataCenter)) { + map = DatumCache.get(dataInfoId); + } else { + Datum datum = DatumCache.get(dataCenter, dataInfoId); + if (datum != null) { + map.put(dataCenter, datum); + } + } + return map; + } + + /** + * get all datum + * + * @return + */ + public static Map> getAll() { + return DATUM_MAP; + } + + /** + * + * + * @param host + * @return + */ + public static Map getByHost(String host) { + return CLIENT_PUB_MAP.getOrDefault(host, null); + } + + /** + * put datum into cache + * + * @param changeType + * @param datum + * @return the last version before datum changed, if datum is not exist, return null + */ + public static MergeResult putDatum(DataChangeTypeEnum changeType, Datum datum) { + MergeResult mergeResult; + String dataCenter = datum.getDataCenter(); + String dataInfoId = datum.getDataInfoId(); + Map map = DATUM_MAP.get(dataCenter); + if (map == null) { + map = new ConcurrentHashMap<>(); + Map ret = DATUM_MAP.putIfAbsent(dataCenter, map); + if (ret != null) { + map = ret; + } + } + + //first put UnPublisher datum(dataId group instanceId is null),can not add to cache + if (datum.getDataId() == null && map.get(dataInfoId) == null) { + mergeResult = new MergeResult(ERROR_DATUM_VERSION, false); + return mergeResult; + } + + Datum ret = map.putIfAbsent(dataInfoId, datum); + if (ret == null) { + Set> entries = datum.getPubMap().entrySet(); + Iterator> iterator = entries.iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + Publisher publisher = entry.getValue(); + if (!(publisher instanceof UnPublisher)) { + String registerId = publisher.getRegisterId(); + Map clientRegisterMap = new ConcurrentHashMap<>(); + clientRegisterMap.put(registerId, publisher); + Map retMap = CLIENT_PUB_MAP.putIfAbsent(publisher + .getSourceAddress().getAddressString(), clientRegisterMap); + if (retMap != null) { + retMap.putAll(clientRegisterMap); + } + } else { + //first put to cache,UnPublisher data must remove,not so got error pub data exist + iterator.remove(); + } + } + mergeResult = new MergeResult(null, true); + } else { + if (changeType == DataChangeTypeEnum.MERGE) { + mergeResult = mergeDatum(datum); + } else { + Long lastVersion = coverDatum(datum); + mergeResult = new MergeResult(lastVersion, true); + } + } + return mergeResult; + } + + /** + * remove datum ant contains all pub data,and clean all the client map reference + * @param dataCenter + * @param dataInfoId + * @return + */ + public static boolean cleanDatum(String dataCenter, String dataInfoId) { + + Map datumMap = DATUM_MAP.get(dataCenter); + if (datumMap != null) { + Datum cacheDatum = datumMap.remove(dataInfoId); + if (cacheDatum != null) { + Map cachePubMap = cacheDatum.getPubMap(); + + for (Entry cachePubEntry : cachePubMap.entrySet()) { + String registerId = cachePubEntry.getKey(); + Publisher cachePub = cachePubEntry.getValue(); + //remove from cache + if (cachePub != null) { + cachePubMap.remove(registerId); + CLIENT_PUB_MAP.get(cachePub.getSourceAddress().getAddressString()).remove( + registerId); + } + } + return true; + } + } + return false; + } + + /** + * merge datum in cache + * + * @param datum + * @return + */ + private static MergeResult mergeDatum(Datum datum) { + boolean isChanged = false; + Datum cacheDatum = DATUM_MAP.get(datum.getDataCenter()).get(datum.getDataInfoId()); + Map cachePubMap = cacheDatum.getPubMap(); + Map pubMap = datum.getPubMap(); + for (Entry pubEntry : pubMap.entrySet()) { + String registerId = pubEntry.getKey(); + Publisher pub = pubEntry.getValue(); + Publisher cachePub = cachePubMap.get(registerId); + if (pub instanceof UnPublisher) { + //remove from cache + if (cachePub != null + && pub.getRegisterTimestamp() > cachePub.getRegisterTimestamp()) { + cachePubMap.remove(registerId); + CLIENT_PUB_MAP.get(cachePub.getSourceAddress().getAddressString()).remove( + registerId); + isChanged = true; + } + } else { + String pubAddr = pub.getSourceAddress().getAddressString(); + long version = pub.getVersion(); + long cacheVersion = cachePub == null ? 0L : cachePub.getVersion(); + String cachePubAddr = cachePub == null ? "" : cachePub.getSourceAddress() + .getAddressString(); + if (cacheVersion <= version) { + cachePubMap.put(registerId, pub); + if (cacheVersion < version || !pubAddr.equals(cachePubAddr)) { + // if version of both pub and cachePub are not equal, or sourceAddress of both are not equal, update + // eg: sessionserver crash, client reconnect to other sessionserver, sourceAddress changed, version not changed + // eg: client restart, sourceAddress and version are both changed + if (CLIENT_PUB_MAP.containsKey(cachePubAddr)) { + CLIENT_PUB_MAP.get(cachePubAddr).remove(registerId); + } + if (!CLIENT_PUB_MAP.containsKey(pubAddr)) { + CLIENT_PUB_MAP.putIfAbsent(pubAddr, new ConcurrentHashMap<>()); + } + CLIENT_PUB_MAP.get(pubAddr).put(registerId, pub); + isChanged = true; + } + } + } + } + Long lastVersion = cacheDatum.getVersion(); + if (isChanged) { + cacheDatum.setVersion(datum.getVersion()); + } + return new MergeResult(lastVersion, isChanged); + } + + /** + * + * @param datum + * @return + */ + private static Long coverDatum(Datum datum) { + String dataCenter = datum.getDataCenter(); + String dataInfoId = datum.getDataInfoId(); + Datum cacheDatum = DATUM_MAP.get(dataCenter).get(dataInfoId); + if (datum.getVersion() != cacheDatum.getVersion()) { + DATUM_MAP.get(dataCenter).put(dataInfoId, datum); + Map pubMap = datum.getPubMap(); + Map cachePubMap = new HashMap<>(cacheDatum.getPubMap()); + for (Entry pubEntry : pubMap.entrySet()) { + String registerId = pubEntry.getKey(); + Publisher pub = pubEntry.getValue(); + String pubAddr = pub.getSourceAddress().getAddressString(); + if (!CLIENT_PUB_MAP.containsKey(pubAddr)) { + CLIENT_PUB_MAP.putIfAbsent(pubAddr, new ConcurrentHashMap<>()); + } + CLIENT_PUB_MAP.get(pubAddr).put(registerId, pub); + Publisher cachePub = cachePubMap.get(registerId); + if (cachePub != null + && pubAddr.equals(cachePub.getSourceAddress().getAddressString())) { + cachePubMap.remove(registerId); + } + } + if (!cachePubMap.isEmpty()) { + for (Publisher cachePub : cachePubMap.values()) { + CLIENT_PUB_MAP.get(cachePub.getSourceAddress().getAddressString()).remove( + cachePub.getRegisterId()); + } + } + } + return cacheDatum.getVersion(); + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/MergeResult.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/MergeResult.java new file mode 100644 index 000000000..eea48131c --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/MergeResult.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +/** + * + * @author shangyu.wh + * @version $Id: MergeResult.java, v 0.1 2019-02-20 17:24 shangyu.wh Exp $ + */ +public class MergeResult { + + private Long lastVersion; + + private boolean changeFlag; + + public MergeResult(Long lastVersion, boolean changeFlag) { + this.lastVersion = lastVersion; + this.changeFlag = changeFlag; + } + + /** + * Getter method for property lastVersion. + * + * @return property value of lastVersion + */ + public Long getLastVersion() { + return lastVersion; + } + + /** + * Setter method for property lastVersion. + * + * @param lastVersion value to be assigned to property lastVersion + */ + public void setLastVersion(Long lastVersion) { + this.lastVersion = lastVersion; + } + + /** + * Getter method for property changeFlag. + * + * @return property value of changeFlag + */ + public boolean isChangeFlag() { + return changeFlag; + } + + /** + * Setter method for property changeFlag. + * + * @param changeFlag value to be assigned to property changeFlag + */ + public void setChangeFlag(boolean changeFlag) { + this.changeFlag = changeFlag; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/UnPublisher.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/UnPublisher.java new file mode 100644 index 000000000..5db5d80b9 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/cache/UnPublisher.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.cache; + +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; + +/** + * + * @author qian.lqlq + * @version $Id: UnPublisher.java, v 0.1 2018-01-11 20:05 qian.lqlq Exp $ + */ +public class UnPublisher extends Publisher { + + /** + * + * @param dataInfoId + * @param registerId + * @param registerTimeStamp + */ + public UnPublisher(String dataInfoId, String registerId, long registerTimeStamp) { + setDataInfoId(dataInfoId); + setRegisterId(registerId); + setRegisterTimestamp(registerTimeStamp); + //avoid new datum dataId is null + DataInfo dataInfo = DataInfo.valueOf(dataInfoId); + setDataId(dataInfo.getDataId()); + setGroup(dataInfo.getDataType()); + setInstanceId(dataInfo.getInstanceId()); + } + + @Override + public DataType getDataType() { + return DataType.UNPUBLISHER; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/ChangeData.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/ChangeData.java new file mode 100644 index 000000000..166f8fa48 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/ChangeData.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * changed data + * + * @author qian.lqlq + * @version $Id: ChangeData.java, v 0.1 2017-12-08 16:23 qian.lqlq Exp $ + */ +public class ChangeData implements Delayed { + + /** data changed */ + private Datum datum; + + /** change time */ + private Long gmtCreate; + + /** timeout */ + private long timeout; + + private DataSourceTypeEnum sourceType; + + private DataChangeTypeEnum changeType; + + /** + * constructor + * @param datum + * @param timeout + * @param sourceType + * @param changeType + */ + public ChangeData(Datum datum, long timeout, DataSourceTypeEnum sourceType, + DataChangeTypeEnum changeType) { + this.datum = datum; + this.gmtCreate = System.currentTimeMillis(); + this.timeout = timeout; + this.sourceType = sourceType; + this.changeType = changeType; + } + + /** + * Getter method for property datum. + * + * @return property value of datum + */ + public Datum getDatum() { + return datum; + } + + /** + * Setter method for property datum. + * + * @param datum value to be assigned to property datum + */ + public void setDatum(Datum datum) { + this.datum = datum; + } + + /** + * Getter method for property sourceType. + * + * @return property value of sourceType + */ + public DataSourceTypeEnum getSourceType() { + return sourceType; + } + + /** + * Getter method for property changeType. + * + * @return property value of changeType + */ + public DataChangeTypeEnum getChangeType() { + return changeType; + } + + @Override + public long getDelay(TimeUnit unit) { + return unit + .convert(gmtCreate + timeout - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(Delayed o) { + if (o == this) { + return 0; + } + if (o instanceof ChangeData) { + ChangeData other = (ChangeData) o; + if (this.gmtCreate < other.gmtCreate) { + return -1; + } else if (this.gmtCreate > other.gmtCreate) { + return 1; + } else { + return 0; + } + } + return -1; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeHandler.java new file mode 100644 index 000000000..6bf66a946 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeHandler.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.cache.MergeResult; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventQueue; +import com.alipay.sofa.registry.server.data.change.notify.IDataChangeNotifier; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * notify sessionserver when data changed + * + * @author qian.lqlq + * @version $Id: DataChangeHandler.java, v 0.1 2017-12-07 18:44 qian.lqlq Exp $ + */ +public class DataChangeHandler implements InitializingBean { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataChangeHandler.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + @Resource + private List dataChangeNotifiers; + + @Override + public void afterPropertiesSet() { + //init DataChangeEventCenter + dataChangeEventCenter.init(dataServerBootstrapConfig); + start(); + } + + /** + * + */ + public void start() { + DataChangeEventQueue[] queues = dataChangeEventCenter.getQueues(); + int queueCount = queues.length; + Executor executor = ExecutorFactory.newFixedThreadPool(queueCount, + DataChangeHandler.class.getSimpleName()); + Executor notifyExecutor = ExecutorFactory.newFixedThreadPool( + dataServerBootstrapConfig.getQueueCount() * 5, this.getClass().getSimpleName()); + for (int idx = 0; idx < queueCount; idx++) { + final DataChangeEventQueue dataChangeEventQueue = queues[idx]; + final String name = dataChangeEventQueue.getName(); + LOGGER.info("[DataChangeHandler] begin to notify datum in queue:{}", name); + executor.execute(() -> { + while (true) { + try { + final ChangeData changeData = dataChangeEventQueue.take(); + notifyExecutor.execute(new ChangeNotifier(changeData, name)); + } catch (Throwable e) { + LOGGER.error("[DataChangeHandler][{}] notify scheduler error", name, e); + } + } + }); + LOGGER.info("[DataChangeHandler] notify datum in queue:{} success", name); + } + } + + /** + * + */ + private class ChangeNotifier implements Runnable { + + private ChangeData changeData; + + private String name; + + /** + * constructor + * @param changeData + * @param name + */ + public ChangeNotifier(ChangeData changeData, String name) { + this.changeData = changeData; + this.name = name; + } + + @Override + public void run() { + Datum datum = changeData.getDatum(); + String dataCenter = datum.getDataCenter(); + String dataInfoId = datum.getDataInfoId(); + long version = datum.getVersion(); + DataSourceTypeEnum sourceType = changeData.getSourceType(); + DataChangeTypeEnum changeType = changeData.getChangeType(); + try { + if (sourceType == DataSourceTypeEnum.CLEAN) { + if (DatumCache.cleanDatum(dataCenter, dataInfoId)) { + LOGGER + .info( + "[DataChangeHandler][{}] clean datum, dataCenter={}, dataInfoId={}, version={},sourceType={}, changeType={}", + name, dataCenter, dataInfoId, version, sourceType, changeType); + } + + } else { + Long lastVersion = null; + + if (sourceType == DataSourceTypeEnum.PUB_TEMP) { + notifyTempPub(datum, sourceType, changeType); + return; + } + + MergeResult mergeResult = DatumCache.putDatum(changeType, datum); + lastVersion = mergeResult.getLastVersion(); + + if (lastVersion != null + && lastVersion.longValue() == DatumCache.ERROR_DATUM_VERSION) { + LOGGER + .error( + "[DataChangeHandler][{}] first put unPub datum into cache error, dataCenter={}, dataInfoId={}, version={}, sourceType={},isContainsUnPub={}", + name, dataCenter, dataInfoId, version, sourceType, + datum.isContainsUnPub()); + return; + } + + boolean changeFlag = mergeResult.isChangeFlag(); + + LOGGER + .info( + "[DataChangeHandler][{}] datum handle,datum={},dataCenter={}, dataInfoId={}, version={}, lastVersion={}, sourceType={}, changeType={},changeFlag={},isContainsUnPub={}", + name, datum.hashCode(), dataCenter, dataInfoId, version, lastVersion, + sourceType, changeType, changeFlag, datum.isContainsUnPub()); + //lastVersion null means first add datum + if (lastVersion == null || version != lastVersion) { + if (changeFlag) { + for (IDataChangeNotifier notifier : dataChangeNotifiers) { + if (notifier.getSuitableSource().contains(sourceType)) { + notifier.notify(datum, lastVersion); + } + } + } + } + } + } catch (Exception e) { + LOGGER + .error( + "[DataChangeHandler][{}] put datum into cache error, dataCenter={}, dataInfoId={}, version={}, sourceType={},isContainsUnPub={}", + name, dataCenter, dataInfoId, version, sourceType, datum.isContainsUnPub(), + e); + } + + } + + private void notifyTempPub(Datum datum, DataSourceTypeEnum sourceType, + DataChangeTypeEnum changeType) { + + String dataCenter = datum.getDataCenter(); + String dataInfoId = datum.getDataInfoId(); + long version = datum.getVersion(); + LOGGER + .info( + "[DataChangeHandler][{}] datum handle temp pub,datum={},dataCenter={}, dataInfoId={}, version={}, sourceType={}, changeType={},isContainsUnPub={}", + name, datum.hashCode(), dataCenter, dataInfoId, version, sourceType, + changeType, datum.isContainsUnPub()); + + for (IDataChangeNotifier notifier : dataChangeNotifiers) { + if (notifier.getSuitableSource().contains(sourceType)) { + notifier.notify(datum, null); + } + } + } + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeTypeEnum.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeTypeEnum.java new file mode 100644 index 000000000..ef3ba0a66 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataChangeTypeEnum.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change; + +/** + * enum for data change type + * + * @author qian.lqlq + * @version $Id: DataChangeTypeEnum.java, v 0.1 2017-12-07 18:43 qian.lqlq Exp $ + */ +public enum DataChangeTypeEnum { + + /** */ + MERGE, + + /** */ + COVER +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataSourceTypeEnum.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataSourceTypeEnum.java new file mode 100644 index 000000000..c41a14f51 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/DataSourceTypeEnum.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change; + +/** + * + * @author qian.lqlq + * @version $Id: DataSourceTypeEnum.java, v 0.1 2018-03-12 18:01 qian.lqlq Exp $ + */ +public enum DataSourceTypeEnum { + + /** + * pub by client + */ + PUB, + + /** + * pub temporary data + */ + PUB_TEMP, + + /** + * sync from dataservers in other datacenter + */ + SYNC, + + /** + * from dataservers in the same datacenter + */ + BACKUP, + + /** + * local dataInfo check,not belong this node schedule remove + */ + CLEAN +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/ClientChangeEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/ClientChangeEvent.java new file mode 100644 index 000000000..c063f50d4 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/ClientChangeEvent.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.event; + +/** + * + * @author qian.lqlq + * @version $Id: ClientChangeEvent.java, v 0.1 2018-05-10 17:12 qian.lqlq Exp $ + */ +public class ClientChangeEvent implements IDataChangeEvent { + + private String host; + + private String dataCenter; + + private long occurredTimestamp; + + private long version; + + /** + * constructor + * @param host + * @param dataCenter + * @param occurredTimestamp + */ + public ClientChangeEvent(String host, String dataCenter, long occurredTimestamp) { + this.host = host; + this.dataCenter = dataCenter; + this.occurredTimestamp = occurredTimestamp; + this.version = System.currentTimeMillis(); + } + + @Override + public DataChangeScopeEnum getScope() { + return DataChangeScopeEnum.CLIENT; + } + + /** + * Getter method for property host. + * + * @return property value of host + */ + public String getHost() { + return host; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Getter method for property occurredTimestamp. + * + * @return property value of occurredTimestamp + */ + public long getOccurredTimestamp() { + return occurredTimestamp; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEvent.java new file mode 100644 index 000000000..f92a8e36c --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEvent.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.event; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.server.data.change.DataChangeTypeEnum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; + +/** + * event for data changed + * + * @author qian.lqlq + * @version $Id: DataChangeEvent.java, v 0.1 2017-12-07 18:44 qian.lqlq Exp $ + */ +public class DataChangeEvent implements IDataChangeEvent { + + /** + * type of changed data, MERGE or COVER + */ + private DataChangeTypeEnum changeType; + + /** + * + */ + private DataSourceTypeEnum sourceType; + + /** + * data changed + */ + private Datum datum; + + /** + * constructor + * @param changeType + * @param sourceType + * @param datum + */ + public DataChangeEvent(DataChangeTypeEnum changeType, DataSourceTypeEnum sourceType, Datum datum) { + this.changeType = changeType; + this.sourceType = sourceType; + this.datum = datum; + } + + /** + * Getter method for property changeType. + * + * @return property value of changeType + */ + public DataChangeTypeEnum getChangeType() { + return changeType; + } + + /** + * Getter method for property datum. + * + * @return property value of datum + */ + public Datum getDatum() { + return datum; + } + + /** + * Setter method for property datum. + * + * @param datum value to be assigned to property datum + */ + public void setDatum(Datum datum) { + this.datum = datum; + } + + /** + * Getter method for property sourceType. + * + * @return property value of sourceType + */ + public DataSourceTypeEnum getSourceType() { + return sourceType; + } + + @Override + public DataChangeScopeEnum getScope() { + return DataChangeScopeEnum.DATUM; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventCenter.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventCenter.java new file mode 100644 index 000000000..58c5496e2 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventCenter.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.event; + +import com.alipay.sofa.registry.common.model.PublishType; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.UnPublisher; +import com.alipay.sofa.registry.server.data.change.DataChangeTypeEnum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author qian.lqlq + * @version $Id: DataChangeEventCenter.java, v 0.1 2018-03-09 14:25 qian.lqlq Exp $ + */ +public class DataChangeEventCenter { + private AtomicBoolean isInited = new AtomicBoolean(false); + + /** + * count of DataChangeEventQueue + */ + private int queueCount; + + /** + * queues of DataChangeEvent + */ + private DataChangeEventQueue[] dataChangeEventQueues; + + /** + * + * @param config + */ + public void init(DataServerConfig config) { + if (isInited.compareAndSet(false, true)) { + queueCount = config.getQueueCount(); + dataChangeEventQueues = new DataChangeEventQueue[queueCount]; + for (int idx = 0; idx < queueCount; idx++) { + dataChangeEventQueues[idx] = new DataChangeEventQueue(idx, config); + dataChangeEventQueues[idx].start(); + } + } + } + + /** + * receive changed publisher, then wrap it into the DataChangeEvent and put it into dataChangeEventQueue + * + * @param publisher + * @param dataCenter + */ + public void onChange(Publisher publisher, String dataCenter) { + int idx = hash(publisher.getDataInfoId()); + Datum datum = new Datum(publisher, dataCenter); + if (publisher instanceof UnPublisher) { + datum.setContainsUnPub(true); + } + if (publisher.getPublishType() != PublishType.TEMPORARY) { + dataChangeEventQueues[idx].onChange(new DataChangeEvent(DataChangeTypeEnum.MERGE, + DataSourceTypeEnum.PUB, datum)); + } else { + dataChangeEventQueues[idx].onChange(new DataChangeEvent(DataChangeTypeEnum.MERGE, + DataSourceTypeEnum.PUB_TEMP, datum)); + } + } + + /** + * for local dataInfo datum schedule remove,config source type to avoid clean fire notify + * @param datum + * @param dataSourceTypeEnum + */ + public void clean(Datum datum, DataSourceTypeEnum dataSourceTypeEnum) { + int idx = hash(datum.getDataInfoId()); + dataChangeEventQueues[idx].onChange(new DataChangeEvent(DataChangeTypeEnum.COVER, + dataSourceTypeEnum, datum)); + } + + /** + * + * @param event + */ + public void onChange(ClientChangeEvent event) { + for (DataChangeEventQueue dataChangeEventQueue : dataChangeEventQueues) { + dataChangeEventQueue.onChange(event); + } + } + + /** + * + * @param changeType + * @param datum + */ + public void sync(DataChangeTypeEnum changeType, DataSourceTypeEnum sourceType, Datum datum) { + int idx = hash(datum.getDataInfoId()); + DataChangeEvent event = new DataChangeEvent(changeType, sourceType, datum); + dataChangeEventQueues[idx].onChange(event); + } + + /** + * compute target DataChangeEventQueue + * + * @param key + * @return + */ + private int hash(String key) { + if (queueCount > 1) { + return Math.abs(key.hashCode() % queueCount); + } else { + return 0; + } + } + + /** + * + * @return + */ + public DataChangeEventQueue[] getQueues() { + return dataChangeEventQueues; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventQueue.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventQueue.java new file mode 100644 index 000000000..45e5cffab --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeEventQueue.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.event; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.cache.UnPublisher; +import com.alipay.sofa.registry.server.data.change.ChangeData; +import com.alipay.sofa.registry.server.data.change.DataChangeTypeEnum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.node.DataServerNode; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerNodeFactory; +import com.google.common.collect.Interners; + +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.locks.ReentrantLock; + +/** + * a queue of DataChangeEvent + * + * @author qian.lqlq + * @version $Id: DataChangeEventQueue.java, v 0.1 2017-12-11 17:10 qian.lqlq Exp $ + */ +public class DataChangeEventQueue { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataChangeEventQueue.class); + + /** + * + */ + private final String name; + + /** + * a block queue that stores all data change events + */ + private final BlockingQueue eventQueue; + + /** + * + */ + private final Map> CHANGE_DATA_MAP = new ConcurrentHashMap<>(); + + /** + * + */ + private final DelayQueue CHANGE_QUEUE = new DelayQueue(); + + private final int notifyIntervalMs; + + private final ReentrantLock lock = new ReentrantLock(); + + private DataServerConfig dataServerConfig; + + /** + * constructor + * @param idx + * @param dataServerConfig + */ + public DataChangeEventQueue(int idx, DataServerConfig dataServerConfig) { + + this.name = String.format("%s_%s", DataChangeEventQueue.class.getSimpleName(), idx); + this.dataServerConfig = dataServerConfig; + int queueSize = dataServerConfig.getQueueSize(); + if (queueSize <= 0) { + eventQueue = new LinkedBlockingDeque<>(); + } else { + eventQueue = new LinkedBlockingDeque<>(queueSize); + } + this.notifyIntervalMs = dataServerConfig.getNotifyIntervalMs(); + } + + /** + * receive event when data changed + * + * @param event + */ + public void onChange(IDataChangeEvent event) { + eventQueue.add(event); + } + + /** + * + * @return + */ + public String getName() { + return name; + } + + /** + * + * @return + * @throws InterruptedException + */ + public ChangeData take() throws InterruptedException { + ChangeData changeData = CHANGE_QUEUE.take(); + lock.lock(); + try { + Datum datum = changeData.getDatum(); + CHANGE_DATA_MAP.get(datum.getDataCenter()).remove(datum.getDataInfoId()); + return changeData; + } finally { + lock.unlock(); + } + } + + /** + * + * @param dataCenter + * @param dataInfoId + * @param sourceType + * @param changeType + * @return + */ + private ChangeData getChangeData(String dataCenter, String dataInfoId, + DataSourceTypeEnum sourceType, DataChangeTypeEnum changeType) { + Map map = CHANGE_DATA_MAP.get(dataCenter); + if (map == null) { + Map newMap = new ConcurrentHashMap<>(); + map = CHANGE_DATA_MAP.putIfAbsent(dataCenter, newMap); + if (map == null) { + map = newMap; + } + } + + ChangeData changeData = map.get(dataInfoId); + if (changeData == null) { + ChangeData newChangeData = new ChangeData(null, this.notifyIntervalMs, sourceType, + changeType); + changeData = map.putIfAbsent(dataInfoId, newChangeData); + if (changeData == null) { + changeData = newChangeData; + } + CHANGE_QUEUE.put(changeData); + } + return changeData; + } + + /** + * + */ + public void start() { + LOGGER.info("[{}] begin start DataChangeEventQueue", getName()); + Executor executor = ExecutorFactory.newSingleThreadExecutor( + String.format("%s_%s", DataChangeEventQueue.class.getSimpleName(), getName())); + executor.execute(() -> { + while (true) { + try { + IDataChangeEvent event = eventQueue.take(); + DataChangeScopeEnum scope = event.getScope(); + if (scope == DataChangeScopeEnum.DATUM) { + DataChangeEvent dataChangeEvent = (DataChangeEvent) event; + handleDatum(dataChangeEvent.getChangeType(), + dataChangeEvent.getSourceType(), dataChangeEvent.getDatum()); + } else if (scope == DataChangeScopeEnum.CLIENT) { + handleHost((ClientChangeEvent) event); + } + } catch (Throwable e) { + LOGGER.error("[{}] handle change event failed", getName(), e); + } + } + }); + LOGGER.info("[{}] start DataChangeEventQueue success", getName()); + } + + private void handleHost(ClientChangeEvent event) { + String clientHost = event.getHost(); + synchronized (Interners.newWeakInterner().intern(clientHost)) { + Map pubMap = DatumCache.getByHost(clientHost); + if (pubMap != null && !pubMap.isEmpty()) { + int count = 0; + for (Publisher publisher : pubMap.values()) { + DataServerNode dataServerNode = DataServerNodeFactory.computeDataServerNode( + dataServerConfig.getLocalDataCenter(), publisher.getDataInfoId()); + //current dataCenter backup data need not unPub,it will be unPub by backup sync event + if (DataServerConfig.IP.equals(dataServerNode.getIp())) { + Datum datum = new Datum(new UnPublisher(publisher.getDataInfoId(), + publisher.getRegisterId(), event.getOccurredTimestamp()), + event.getDataCenter(), event.getVersion()); + datum.setContainsUnPub(true); + handleDatum(DataChangeTypeEnum.MERGE, DataSourceTypeEnum.PUB, datum); + count++; + } + } + LOGGER + .info( + "[{}] client off handle, host={}, occurTimestamp={},version={},handle pub size={}", + getName(), clientHost, event.getOccurredTimestamp(), event.getVersion(), + count); + } else { + LOGGER.info("[{}] no datum to handle, host={}", getName(), clientHost); + } + } + } + + private void handleDatum(DataChangeTypeEnum changeType, DataSourceTypeEnum sourceType, + Datum targetDatum) { + lock.lock(); + try { + //get changed datum + ChangeData changeData = getChangeData(targetDatum.getDataCenter(), + targetDatum.getDataInfoId(), sourceType, changeType); + Datum cacheDatum = changeData.getDatum(); + if (changeType == DataChangeTypeEnum.COVER || cacheDatum == null) { + changeData.setDatum(targetDatum); + } else { + Map targetPubMap = targetDatum.getPubMap(); + Map cachePubMap = cacheDatum.getPubMap(); + for (Publisher pub : targetPubMap.values()) { + String registerId = pub.getRegisterId(); + Publisher cachePub = cachePubMap.get(registerId); + if (cachePub != null) { + // if the registerTimestamp of cachePub is greater than the registerTimestamp of pub, it means + // that pub is not the newest data, should be ignored + if (pub.getRegisterTimestamp() < cachePub.getRegisterTimestamp()) { + continue; + } + // if pub and cachePub both are publisher, and sourceAddress of both are equal, + // and version of cachePub is greater than version of pub, should be ignored + if (!(pub instanceof UnPublisher) && !(cachePub instanceof UnPublisher) + && pub.getSourceAddress().equals(cachePub.getSourceAddress()) + && cachePub.getVersion() >= pub.getVersion()) { + continue; + } + } + cachePubMap.put(registerId, pub); + cacheDatum.setVersion(targetDatum.getVersion()); + } + } + } finally { + lock.unlock(); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeScopeEnum.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeScopeEnum.java new file mode 100644 index 000000000..bfba719e5 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/DataChangeScopeEnum.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.event; + +/** + * + * @author qian.lqlq + * @version $Id: DataChangeScopeEnum.java, v 0.1 2018-05-10 16:51 qian.lqlq Exp $ + */ +public enum DataChangeScopeEnum { + CLIENT, DATUM +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/IDataChangeEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/IDataChangeEvent.java new file mode 100644 index 000000000..1006ce6ee --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/event/IDataChangeEvent.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.event; + +/** + * + * @author qian.lqlq + * @version $Id: IDataChangeEvent.java, v 0.1 2018-05-10 17:11 qian.lqlq Exp $ + */ +public interface IDataChangeEvent { + + /** + * + * @return + */ + DataChangeScopeEnum getScope(); +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/BackUpNotifier.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/BackUpNotifier.java new file mode 100644 index 000000000..293376031 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/BackUpNotifier.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.notify; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.datasync.Operator; +import com.alipay.sofa.registry.server.data.datasync.SyncDataService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: BackUpNotifier.java, v 0.1 2018-03-12 18:40 qian.lqlq Exp $ + */ +public class BackUpNotifier implements IDataChangeNotifier { + + @Autowired + private SyncDataService syncDataService; + + @Override + public Set getSuitableSource() { + Set set = new HashSet<>(); + set.add(DataSourceTypeEnum.PUB); + set.add(DataSourceTypeEnum.SYNC); + return set; + } + + @Override + public void notify(Datum datum, Long lastVersion) { + syncDataService.appendOperator(new Operator(datum.getVersion(), lastVersion, datum, + DataSourceTypeEnum.BACKUP)); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/IDataChangeNotifier.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/IDataChangeNotifier.java new file mode 100644 index 000000000..8b5669eb2 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/IDataChangeNotifier.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.notify; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; + +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: IDataChangeNotifier.java, v 0.1 2018-03-09 15:30 qian.lqlq Exp $ + */ +public interface IDataChangeNotifier { + + /** + * + * @return + */ + Set getSuitableSource(); + + /** + * + * @param datum + * @param lastVersion + */ + void notify(Datum datum, Long lastVersion); + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/SessionServerNotifier.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/SessionServerNotifier.java new file mode 100644 index 000000000..727156d35 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/SessionServerNotifier.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.notify; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.sessionserver.DataChangeRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer.TaskFailedCallback; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * Notify session DataChangeRequest,if fail get result callback retry + * + * @author qian.lqlq + * @version $Id: SessionServerNotifier.java, v 0.1 2018-03-09 15:32 qian.lqlq Exp $ + */ +public class SessionServerNotifier implements IDataChangeNotifier { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionServerNotifier.class); + + private AsyncHashedWheelTimer asyncHashedWheelTimer; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionServerConnectionFactory sessionServerConnectionFactory; + + public SessionServerNotifier() { + ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder(); + threadFactoryBuilder.setDaemon(true); + asyncHashedWheelTimer = new AsyncHashedWheelTimer(threadFactoryBuilder.setNameFormat( + "Registry-SessionServerNotifier-WheelTimer").build(), 100, TimeUnit.MILLISECONDS, 1024, + threadFactoryBuilder.setNameFormat("Registry-SessionServerNotifier-WheelExecutor-%d") + .build(), new TaskFailedCallback() { + @Override + public void executionRejected(Throwable e) { + LOGGER.error("executionRejected: " + e.getMessage(), e); + } + + @Override + public void executionFailed(Throwable e) { + LOGGER.error("executionFailed: " + e.getMessage(), e); + } + }); + } + + @Override + public Set getSuitableSource() { + Set set = new HashSet<>(); + set.add(DataSourceTypeEnum.PUB); + set.add(DataSourceTypeEnum.SYNC); + return set; + } + + @Override + public void notify(Datum datum, Long lastVersion) { + DataChangeRequest request = new DataChangeRequest(datum.getDataInfoId(), + datum.getDataCenter(), datum.getVersion()); + List connections = sessionServerConnectionFactory.getConnections(); + for (Connection connection : connections) { + doNotify(new NotifyCallback(connection, request)); + } + } + + private void doNotify(NotifyCallback notifyCallback) { + Connection connection = notifyCallback.connection; + DataChangeRequest request = notifyCallback.request; + try { + //check connection active + if (!connection.isFine()) { + if (LOGGER.isInfoEnabled()) { + LOGGER + .info(String + .format( + "connection from sessionserver(%s) is not fine, so ignore notify, retryTimes=%s,request=%s", + connection.getRemoteAddress(), notifyCallback.retryTimes, request)); + } + return; + } + Server sessionServer = boltExchange.getServer(dataServerBootstrapConfig.getPort()); + sessionServer.sendCallback(sessionServer.getChannel(connection.getRemoteAddress()), + request, notifyCallback, dataServerBootstrapConfig.getRpcTimeout()); + } catch (Exception e) { + LOGGER.error(String.format( + "invokeWithCallback failed: sessionserver(%s),retryTimes=%s, request=%s", + connection.getRemoteAddress(), notifyCallback.retryTimes, request), e); + onFailed(notifyCallback); + } + } + + /** + * on failed, retry if necessary + */ + private void onFailed(NotifyCallback notifyCallback) { + DataChangeRequest request = notifyCallback.request; + Connection connection = notifyCallback.connection; + notifyCallback.retryTimes++; + + if (notifyCallback.retryTimes <= dataServerBootstrapConfig.getNotifySessionRetryTimes()) { + this.asyncHashedWheelTimer.newTimeout(timeout -> { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(String.format("retrying notify sessionserver(%s), retryTimes=%s, request=%s", + connection.getRemoteAddress(), notifyCallback.retryTimes, request)); + } + //check version, if it's fall behind, stop retry + long currentVersion = DatumCache.get(request.getDataCenter(), request.getDataInfoId()).getVersion(); + if (request.getVersion() == currentVersion) { + doNotify(notifyCallback); + } else { + if (LOGGER.isInfoEnabled()) { + LOGGER.info(String.format( + "current version change %s, retry version is %s, stop retry! retryTimes=%s, request=%s", + currentVersion, request.getVersion(), notifyCallback.retryTimes, request)); + } + } + }, getDelayTimeForRetry(notifyCallback.retryTimes), TimeUnit.MILLISECONDS); + } else { + LOGGER.error( + String.format("retryTimes have exceeded! stop retry! retryTimes=%s, sessionServer(%s), request=%s", + notifyCallback.retryTimes, connection.getRemoteAddress(), request)); + } + } + + private long getDelayTimeForRetry(int retryTimes) { + long initialSleepTime = TimeUnit.MILLISECONDS.toMillis(dataServerBootstrapConfig + .getNotifySessionRetryFirstDelay()); + long increment = TimeUnit.MILLISECONDS.toMillis(dataServerBootstrapConfig + .getNotifySessionRetryIncrementDelay()); + long result = initialSleepTime + (increment * (retryTimes - 1)); + return result >= 0L ? result : 0L; + } + + private class NotifyCallback implements CallbackHandler { + + private int retryTimes = 0; + private Connection connection; + private DataChangeRequest request; + + public NotifyCallback(Connection connection, DataChangeRequest request) { + this.connection = connection; + this.request = request; + } + + @Override + public void onCallback(Channel channel, Object message) { + CommonResponse result = (CommonResponse) message; + if (result != null && !result.isSuccess()) { + LOGGER + .error(String + .format( + "response not success when notify sessionserver(%s), retryTimes=%s, request=%s, response=%s", + connection.getRemoteAddress(), retryTimes, request, result)); + onFailed(this); + } + } + + @Override + public void onException(Channel channel, Throwable e) { + LOGGER.error(String.format( + "exception when notify sessionserver(%s), retryTimes=%s, request=%s", + connection.getRemoteAddress(), retryTimes, request), e); + onFailed(this); + } + + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/TempPublisherNotifier.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/TempPublisherNotifier.java new file mode 100644 index 000000000..b37fa7541 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/change/notify/TempPublisherNotifier.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.change.notify; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.InvokeCallback; +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.sessionserver.DataPushRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Executor; + +/** + * + * @author shangyu.wh + * @version $Id: TempPublisherNotifier.java, v 0.1 2018-08-29 18:05 shangyu.wh Exp $ + */ +public class TempPublisherNotifier implements IDataChangeNotifier { + + private static final Logger LOGGER = LoggerFactory + .getLogger(TempPublisherNotifier.class); + + private static final Executor EXECUTOR = ExecutorFactory + .newFixedThreadPool(10, + TempPublisherNotifier.class + .getSimpleName()); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionServerConnectionFactory sessionServerConnectionFactory; + + @Override + public Set getSuitableSource() { + Set set = new HashSet<>(); + set.add(DataSourceTypeEnum.PUB_TEMP); + return set; + } + + @Override + public void notify(Datum datum, Long lastVersion) { + DataPushRequest request = new DataPushRequest(datum); + List connections = sessionServerConnectionFactory.getConnections(); + for (Connection connection : connections) { + doNotify(new NotifyPushDataCallback(connection, request)); + } + } + + private void doNotify(NotifyPushDataCallback notifyPushdataCallback) { + + Connection connection = notifyPushdataCallback.getConnection(); + DataPushRequest request = notifyPushdataCallback.getRequest(); + try { + Server sessionServer = boltExchange.getServer(dataServerBootstrapConfig.getPort()); + sessionServer.sendCallback(sessionServer.getChannel(connection.getRemoteAddress()), + request, new CallbackHandler() { + + @Override + public void onCallback(Channel channel, Object message) { + notifyPushdataCallback.onResponse(message); + } + + @Override + public void onException(Channel channel, Throwable exception) { + notifyPushdataCallback.onException(exception); + } + }, dataServerBootstrapConfig.getRpcTimeout()); + } catch (Exception e) { + LOGGER.error("[TempPublisherNotifier] notify sessionserver {} failed, {}", + connection.getRemoteIP(), request, e); + } + } + + private static class NotifyPushDataCallback implements InvokeCallback { + + private Connection connection; + + private DataPushRequest request; + + public NotifyPushDataCallback(Connection connection, DataPushRequest request) { + this.connection = connection; + this.request = request; + } + + @Override + public void onResponse(Object obj) { + CommonResponse result = (CommonResponse) obj; + if (result != null && !result.isSuccess()) { + //doNotify(this); + LOGGER + .error( + "[TempPublisherNotifier] notify sessionserver {} not success, request={}, result={}", + connection.getRemoteIP(), request, result.getMessage()); + } + } + + @Override + public void onException(Throwable e) { + onResponse(CommonResponse.buildFailedResponse(e.getMessage())); + } + + @Override + public Executor getExecutor() { + return EXECUTOR; + } + + /** + * Getter method for property connection. + * + * @return property value of connection + */ + public Connection getConnection() { + return connection; + } + + /** + * Getter method for property request. + * + * @return property value of request + */ + public DataPushRequest getRequest() { + return request; + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/correction/LocalDataServerCleanHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/correction/LocalDataServerCleanHandler.java new file mode 100644 index 000000000..bfc1fc3c8 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/correction/LocalDataServerCleanHandler.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.correction; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.consistency.hash.ConsistentHash; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.BackupTriad; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.util.DelayItem; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author shangyu.wh + * @version $Id: LocalDataServerCleanHandler.java, v 0.1 2018-07-16 17:50 shangyu.wh Exp $ + */ +public class LocalDataServerCleanHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(LocalDataServerCleanHandler.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private DataServerCache dataServerCache; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + private LocalCleanTask task; + + /** + * a DelayQueue that contains clean task + */ + private final DelayQueue> EVENT_QUEUE = new DelayQueue<>(); + + /** + * constructor + */ + public LocalDataServerCleanHandler() { + LOGGER.info("[LocalDataServerCleanHandler] begin start LocalDataServerCleanHandler"); + Executor executor = ExecutorFactory + .newSingleThreadExecutor(LocalDataServerCleanHandler.class.getSimpleName()); + executor.execute(() -> { + while (true) { + try { + DelayItem delayItem = EVENT_QUEUE.take(); + task = delayItem.getItem(); + task.run(); + } catch (Throwable e) { + LOGGER.error("[LocalDataServerCleanHandler] handle clean task failed", e); + } + } + }); + LOGGER.info("[LocalDataServerCleanHandler] start LocalDataServerCleanHandler success"); + } + + /** + * + */ + public void reset() { + synchronized (LocalDataServerCleanHandler.class) { + if (EVENT_QUEUE.isEmpty() && task != null) { + task.stop(); + EVENT_QUEUE.clear(); + } + } + EVENT_QUEUE.add(new DelayItem<>(new LocalCleanTask(), dataServerBootstrapConfig + .getLocalDataServerCleanDelay())); + } + + private class LocalCleanTask { + + private AtomicBoolean running = new AtomicBoolean(false); + + /** + * + */ + public void run() { + if (running.compareAndSet(false, true)) { + try { + + Map dataNodeMap = dataServerCache + .getDataServers(dataServerBootstrapConfig.getLocalDataCenter()); + if (dataNodeMap == null || dataNodeMap.isEmpty()) { + LOGGER.warn("Calculate Old BackupTriad,old dataServer list is empty!"); + return; + } + + ConsistentHash consistentHash = new ConsistentHash<>( + dataServerBootstrapConfig.getNumberOfReplicas(), dataNodeMap.values()); + + Map> dataMapAll = DatumCache.getAll(); + + for (Entry> entryAll : dataMapAll.entrySet()) { + String dataCenter = entryAll.getKey(); + Map dataMap = entryAll.getValue(); + for (Entry entry : dataMap.entrySet()) { + + String dataInfoId = entry.getKey(); + Datum datum = entry.getValue(); + if (!running.get()) { + LOGGER.info( + "[LocalDataServerCleanHandler] task cancel, dataInfoId={}", + dataInfoId); + return; + } + + BackupTriad backupTriad = new BackupTriad(dataInfoId, + consistentHash.getNUniqueNodesFor(dataInfoId, + dataServerBootstrapConfig.getStoreNodes())); + if (!backupTriad.containsSelf()) { + if (datum != null) { + int size = datum.getPubMap() != null ? datum.getPubMap().size() + : 0; + dataChangeEventCenter.clean(datum, DataSourceTypeEnum.CLEAN); + LOGGER + .info( + "[LocalDataServerCleanHandler] clean handle, dataCenter={},dataInfoId={},pub size={}", + dataCenter, dataInfoId, size); + } + } + } + } + } catch (Throwable e) { + LOGGER.error("[LocalDataServerCleanHandler] clean local datum task error!", e); + } finally { + EVENT_QUEUE.add(new DelayItem<>(new LocalCleanTask(), dataServerBootstrapConfig + .getLocalDataServerCleanDelay())); + } + } + } + + /** + * + */ + public void stop() { + running.set(false); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/AcceptorStore.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/AcceptorStore.java new file mode 100644 index 000000000..c17bbd257 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/AcceptorStore.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync; + +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; + +/** + * + * @author shangyu.wh + * @version $Id: AcceptorStore.java, v 0.1 2018-03-22 12:21 shangyu.wh Exp $ + */ +public interface AcceptorStore { + + /** + * appender operator logs to Acceptor + * @param operator + */ + void addOperator(Operator operator); + + /** + * notify change fire sync data get request,get sync data return + * @param syncDataRequest + * @return + */ + SyncData getSyncData(SyncDataRequest syncDataRequest); + + /** + * scheduler get change Acceptor to notify other dataCenter or data node get sync data + */ + void changeDataCheck(); + + /** + * scheduler check Acceptor has Expired,remove all queue logs + */ + void checkAcceptorsChangAndExpired(); + + /** + * get sync type,dataCenter or dataNode + * @return + */ + String getType(); + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/Operator.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/Operator.java new file mode 100644 index 000000000..60f186a39 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/Operator.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; + +/** + * + * @author shangyu.wh + * @version $Id: Operator.java, v 0.1 2018-03-05 17:01 shangyu.wh Exp $ + */ +public class Operator { + + private Long version; + + private Long sourceVersion; + + private Datum datum; + + private DataSourceTypeEnum sourceType; + + /** + * constructor + */ + public Operator() { + } + + /** + * constructor + * @param version + * @param sourceVersion + * @param datum + * @param sourceType + */ + public Operator(Long version, Long sourceVersion, Datum datum, DataSourceTypeEnum sourceType) { + this.version = version; + this.sourceVersion = sourceVersion; + this.datum = datum; + this.sourceType = sourceType; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } + + /** + * Getter method for property sourceVersion. + * + * @return property value of sourceVersion + */ + public Long getSourceVersion() { + return sourceVersion; + } + + /** + * Setter method for property sourceVersion. + * + * @param sourceVersion value to be assigned to property sourceVersion + */ + public void setSourceVersion(Long sourceVersion) { + this.sourceVersion = sourceVersion; + } + + /** + * Getter method for property datum. + * + * @return property value of datum + */ + public Datum getDatum() { + return datum; + } + + /** + * Setter method for property datum. + * + * @param datum value to be assigned to property datum + */ + public void setDatum(Datum datum) { + this.datum = datum; + } + + /** + * Getter method for property sourceType. + * + * @return property value of sourceType + */ + public DataSourceTypeEnum getSourceType() { + return sourceType; + } + + /** + * Setter method for property sourceType. + * + * @param sourceType value to be assigned to property sourceType + */ + public void setSourceType(DataSourceTypeEnum sourceType) { + this.sourceType = sourceType; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/SyncDataService.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/SyncDataService.java new file mode 100644 index 000000000..6812526c5 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/SyncDataService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync; + +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; + +/** + * + * @author shangyu.wh + * @version $Id: SyncDataService.java, v 0.1 2018-03-09 17:10 shangyu.wh Exp $ + */ +public interface SyncDataService { + + /** + * + * @param operator + */ + void appendOperator(Operator operator); + + /** + * + * @param syncDataRequest + * @return + */ + SyncData getSyncDataChange(SyncDataRequest syncDataRequest); + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/AbstractAcceptorStore.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/AbstractAcceptorStore.java new file mode 100644 index 000000000..c85ff165c --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/AbstractAcceptorStore.java @@ -0,0 +1,273 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync.sync; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.NotifyDataSyncRequest; +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.datasync.AcceptorStore; +import com.alipay.sofa.registry.server.data.datasync.Operator; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import com.alipay.sofa.registry.server.data.util.DelayItem; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractAcceptorStore.java, v 0.1 2018-03-22 12:28 shangyu.wh Exp $ + */ +public abstract class AbstractAcceptorStore implements AcceptorStore { + private static final Logger LOGGER = LoggerFactory + .getLogger( + AbstractAcceptorStore.class, + "[SyncDataService]"); + + private static final int DEFAULT_MAX_BUFFER_SIZE = 30; + private static final int DEFAULT_DELAY_TIMEOUT = 3000; + private static final int NOTIFY_RETRY = 3; + + @Autowired + protected IMetaServerService metaServerService; + + @Autowired + private Exchange boltExchange; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private DataServerConnectionFactory dataServerConnectionFactory; + + private Map> acceptors = new ConcurrentHashMap<>(); + + private Map> notifyAcceptorsCache = new ConcurrentHashMap<>(); + + private DelayQueue> delayQueue = new DelayQueue<>(); + + @Override + public void checkAcceptorsChangAndExpired() { + acceptors.forEach((dataCenter, acceptorMap) -> { + if (acceptorMap != null && !acceptorMap.isEmpty()) { + acceptorMap.forEach((dataInfoId, acceptor) -> acceptor.checkExpired(0)); + } + }); + } + + private String getLogByClass(String msg) { + StringBuilder sb = new StringBuilder(); + sb.append(" [").append(this.getClass().getSimpleName()).append("] ").append(msg); + return sb.toString(); + } + + @Override + public void addOperator(Operator operator) { + + Datum datum = operator.getDatum(); + String dataCenter = datum.getDataCenter(); + String dataInfoId = datum.getDataInfoId(); + try { + Map acceptorMap = acceptors.get(dataCenter); + if (acceptorMap == null) { + Map newMap = new ConcurrentHashMap<>(); + acceptorMap = acceptors.putIfAbsent(dataCenter, newMap); + if (acceptorMap == null) { + acceptorMap = newMap; + } + } + + Acceptor existAcceptor = acceptorMap.get(dataInfoId); + if (existAcceptor == null) { + Acceptor newAcceptor = new Acceptor(DEFAULT_MAX_BUFFER_SIZE, dataInfoId, dataCenter); + existAcceptor = acceptorMap.putIfAbsent(dataInfoId, newAcceptor); + if (existAcceptor == null) { + existAcceptor = newAcceptor; + } + } + existAcceptor.appendOperator(operator); + //put cache + putCache(existAcceptor); + } catch (Exception e) { + LOGGER.error(getLogByClass("Append Operator error!"), e); + throw new RuntimeException("Append Operator error!", e); + } + } + + private void putCache(Acceptor acceptor) { + + String dataCenter = acceptor.getDataCenter(); + String dataInfoId = acceptor.getDataInfoId(); + + try { + Map acceptorMap = notifyAcceptorsCache.get(dataCenter); + if (acceptorMap == null) { + Map newMap = new ConcurrentHashMap<>(); + acceptorMap = notifyAcceptorsCache.putIfAbsent(dataCenter, newMap); + if (acceptorMap == null) { + acceptorMap = newMap; + } + } + Acceptor existAcceptor = acceptorMap.putIfAbsent(dataInfoId, acceptor); + if (existAcceptor == null) { + addQueue(acceptor); + } + } catch (Exception e) { + LOGGER.error(getLogByClass("Operator push to delay cache error!"), e); + throw new RuntimeException("Operator push to delay cache error!", e); + } + } + + private void removeCache(Acceptor acceptor) { + String dataCenter = acceptor.getDataCenter(); + String dataInfoId = acceptor.getDataInfoId(); + + try { + Map acceptorMap = notifyAcceptorsCache.get(dataCenter); + if (acceptorMap != null) { + boolean result = acceptorMap.remove(dataInfoId, acceptor); + if (result) { + //data change notify + notifyChange(acceptor); + } + } + } catch (Exception e) { + LOGGER.error(getLogByClass("Operator remove from delay cache error!"), e); + throw new RuntimeException("Operator remove from delay cache error!", e); + } + } + + private void addQueue(Acceptor acceptor) { + delayQueue.put(new DelayItem(acceptor, DEFAULT_DELAY_TIMEOUT)); + } + + private void notifyChange(Acceptor acceptor) { + + Long lastVersion = acceptor.getLastVersion(); + + //may be delete by expired + if (lastVersion == null) { + LOGGER + .warn(getLogByClass("There is not data in acceptor queue!maybe has been expired!")); + lastVersion = 0L; + } + + if (LOGGER.isDebugEnabled()) { + acceptor.printInfo(); + } + + NotifyDataSyncRequest request = new NotifyDataSyncRequest(acceptor.getDataInfoId(), + acceptor.getDataCenter(), lastVersion, getType()); + + List targetDataIps = getTargetDataIp(acceptor.getDataInfoId()); + for (String targetDataIp : targetDataIps) { + + if (DataServerConfig.IP.equals(targetDataIp)) { + continue; + } + + Connection connection = dataServerConnectionFactory.getConnection(targetDataIp); + if (connection == null) { + LOGGER.error(getLogByClass(String.format( + "Can not get notify data server connection!ip: %s", targetDataIp))); + continue; + } + LOGGER.info(getLogByClass("Notify data server {} change data {} to sync"), + connection.getRemoteIP(), request); + for (int tryCount = 0; tryCount < NOTIFY_RETRY; tryCount++) { + try { + Server syncServer = boltExchange.getServer(dataServerBootstrapConfig + .getSyncDataPort()); + syncServer.sendSync(syncServer.getChannel(connection.getRemoteAddress()), + request, 1000); + break; + } catch (Exception e) { + LOGGER.error(getLogByClass(String.format( + "Notify data server %s failed, NotifyDataSyncRequest:%s", targetDataIp, + request)), e); + } + } + } + } + + abstract public List getTargetDataIp(String dataInfoId); + + @Override + public void changeDataCheck() { + + while (true) { + try { + DelayItem delayItem = delayQueue.take(); + Acceptor acceptor = delayItem.getItem(); + removeCache(acceptor); // compare and remove + } catch (InterruptedException e) { + break; + } + } + + } + + @Override + public SyncData getSyncData(SyncDataRequest syncDataRequest) { + + String dataCenter = syncDataRequest.getDataCenter(); + String dataInfoId = syncDataRequest.getDataInfoId(); + + Long currentVersion = syncDataRequest.getVersion(); + try { + Map acceptorMap = acceptors.get(dataCenter); + if (acceptorMap == null) { + LOGGER.error( + getLogByClass("Can not find Sync Data acceptor instance,dataCenter:{}"), + dataCenter); + throw new RuntimeException("Can not find Sync Data acceptor instance!"); + } + + Acceptor existAcceptor = acceptorMap.get(dataInfoId); + if (existAcceptor == null) { + LOGGER.error( + getLogByClass("Can not find Sync Data acceptor instance,dataInfoId:{}"), + dataInfoId); + throw new RuntimeException("Can not find Sync Data acceptor instance!"); + } + return existAcceptor.process(currentVersion); + } catch (Exception e) { + LOGGER.error(getLogByClass("Get change SyncData error!"), e); + throw new RuntimeException("Get change SyncData error!", e); + } + } + + /** + * Getter method for property dataServerBootstrapConfig. + * + * @return property value of dataServerBootstrapConfig + */ + public DataServerConfig getDataServerConfig() { + return dataServerBootstrapConfig; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Acceptor.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Acceptor.java new file mode 100644 index 000000000..5650ea263 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Acceptor.java @@ -0,0 +1,319 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync.sync; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.datasync.Operator; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: Acceptor.java, v 0.1 2018-03-05 16:57 shangyu.wh Exp $ + */ +public class Acceptor { + + static final int DEFAULT_DURATION_SECS = 30; + private static final Logger LOGGER = LoggerFactory.getLogger( + Acceptor.class, + "[SyncDataService]"); + private final Deque logOperatorsOrder = new ConcurrentLinkedDeque<>(); + private final String dataInfoId; + private final String dataCenter; + private int maxBufferSize; + private Map logOperators = new ConcurrentHashMap<>(); + + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock.readLock(); + private final Lock write = readWriteLock.writeLock(); + + /** + * constructor + * @param maxBufferSize + * @param dataInfoId + * @param dataCenter + */ + public Acceptor(int maxBufferSize, String dataInfoId, String dataCenter) { + this.maxBufferSize = maxBufferSize; + this.dataInfoId = dataInfoId; + this.dataCenter = dataCenter; + } + + /** + * append operator to queue,if queue is full poll the first element and append. + * Process will check version sequence,it must append with a consequent increase in version, + * otherwise queue will be clean + * + * @param operator + */ + public void appendOperator(Operator operator) { + write.lock(); + try { + if (isFull()) { + logOperators.remove(logOperatorsOrder.poll()); + } + if (operator.getSourceVersion() == null) { + operator.setSourceVersion(0L); + } + Long tailVersion = logOperatorsOrder.peekLast(); + + if (tailVersion != null) { + //operation add not by solid sequence + if (tailVersion.longValue() != operator.getSourceVersion().longValue()) { + LOGGER + .warn( + "Datum {} append operation not follow version sequence!Current version {},but input source version {}.In order to avoid get " + + "data error clear operations!", operator.getDatum() + .getDataInfoId(), tailVersion, operator.getSourceVersion()); + clearBefore(); + } + } + + Operator previousOperator = logOperators.put(operator.getVersion(), operator); + if (previousOperator == null) { + logOperatorsOrder.add(operator.getVersion()); + } else { + LOGGER.warn("Append operation has been exist!"); + } + } finally { + write.unlock(); + } + } + + /** + * + * @return + */ + public Collection getAllOperators() { + LinkedList linkRet = new LinkedList<>(); + if (logOperatorsOrder.peek() != null) { + Iterator iterator = logOperatorsOrder.iterator(); + while (iterator.hasNext()) { + Long i = (Long) iterator.next(); + linkRet.add(logOperators.get(i)); + } + } + return linkRet; + } + + /** + * process send data current version,check current version exist in current queue + * if(existed) return operators which version bigger than current version + * else get all datum data operators + * + * @param currentVersion + * @return + */ + public SyncData process(Long currentVersion) { + read.lock(); + try { + Collection operators = acceptOperator(currentVersion); + + List retList = new LinkedList<>(); + SyncData syncData; + boolean wholeDataTag = false; + if (operators != null) { + //first get all data + if (operators.isEmpty()) { + wholeDataTag = true; + retList.add(DatumCache.get(dataCenter, dataInfoId)); + LOGGER.info("Get all data!dataInfoID:{} dataCenter:{}.All data size{}:", + dataInfoId, dataCenter, retList.size()); + } else { + for (Operator operator : operators) { + retList.add(operator.getDatum()); + } + } + syncData = new SyncData(dataInfoId, dataCenter, wholeDataTag, retList); + } else { + //no match get all data + LOGGER + .info( + "Append log queue is empty,Maybe all logs record expired or no operator append!So must get all data!dataInfoID:{} dataCenter:{}.queue size{}:", + dataInfoId, dataCenter, logOperatorsOrder.size()); + wholeDataTag = true; + retList.add(DatumCache.get(dataCenter, dataInfoId)); + syncData = new SyncData(dataInfoId, dataCenter, wholeDataTag, retList); + } + + return syncData; + } finally { + read.unlock(); + } + } + + /** + * + * @param currentVersion + * @return + */ + public Collection acceptOperator(Long currentVersion) { + //first get all data + if (currentVersion == null) { + LOGGER + .info( + "Current version input is null,maybe first get all data!dataInfoID:{} dataCenter:{}", + dataInfoId, dataCenter); + return new ArrayList<>(); + } + + if (logOperatorsOrder.size() > 0) { + LinkedList linkRet = new LinkedList<>(); + //target version found + if (logOperatorsOrder.contains(currentVersion)) { + Iterator iterator = logOperatorsOrder.descendingIterator(); + while (iterator.hasNext()) { + Long i = (Long) iterator.next(); + if (currentVersion.equals(i)) { + break; + } + linkRet.addFirst(logOperators.get(i)); + } + } else { + //target version not found,but source version equals + Operator headOperator = logOperators.get(logOperatorsOrder.peek()); + if (currentVersion.equals(headOperator.getSourceVersion())) { + LOGGER + .info("current version not found on queue,but header source version equals current version!"); + linkRet.addAll(logOperators.values()); + } + } + if (linkRet.isEmpty()) { + LOGGER.info("Current version {} not match on queue,queue size {} !", + currentVersion, logOperatorsOrder.size()); + } + return linkRet; + } + //cannot match version,must poll all data + return null; + } + + /** + * + * @param durationSEC + */ + public void checkExpired(int durationSEC) { + write.lock(); + try { + //check all expired + Long peekVersion = logOperatorsOrder.peek(); + if (peekVersion != null && isExpired(durationSEC, peekVersion)) { + logOperators.remove(logOperatorsOrder.poll()); + checkExpired(durationSEC); + } + } finally { + write.unlock(); + } + } + + /** + * + * @return + */ + public Long getLastVersion() { + return logOperatorsOrder.peekLast(); + } + + private boolean isFull() { + return logOperators.size() >= maxBufferSize; + } + + private boolean isExpired(int durationSECS, long peekVersion) { + durationSECS = (durationSECS > 0) ? durationSECS * 1000 : DEFAULT_DURATION_SECS * 1000; + boolean ret = System.currentTimeMillis() > peekVersion + durationSECS; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("now:" + System.currentTimeMillis() + " peek:" + peekVersion + " du:" + + durationSECS + " result:" + ret); + } + return ret; + } + + private void clearBefore() { + write.lock(); + try { + + logOperators.clear(); + logOperatorsOrder.clear(); + } finally { + write.unlock(); + } + } + + /** + * + */ + public void printInfo() { + LOGGER + .debug("----------------------------------------------------------------------------"); + LOGGER.debug("Acceptor info has " + logOperators.size() + " operations,dataInfoID:" + + this.getDataInfoId() + " dataCenter:" + this.getDataCenter()); + if (logOperatorsOrder.size() > 0) { + for (Long version : logOperatorsOrder) { + Operator operator = logOperators.get(version); + LOGGER.debug("| " + pidLine(String.valueOf(operator.getVersion()), 24, " ") + + pidLine(String.valueOf(operator.getSourceVersion()), 24, " ") + + operator.getDatum()); + + } + } + } + + private String pidLine(String line, int length, String space) { + StringBuilder sb = new StringBuilder(); + sb.append(line); + int spaces = length - line.getBytes(Charset.defaultCharset()).length - 1; + for (int i = 0; i < spaces; i++) { + sb.append(space); + } + return sb.toString(); + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/LocalAcceptorStore.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/LocalAcceptorStore.java new file mode 100644 index 000000000..85d2e3292 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/LocalAcceptorStore.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync.sync; + +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.node.DataServerNode; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: LocalAcceptorStore.java, v 0.1 2018-03-22 12:31 shangyu.wh Exp $ + */ +public class LocalAcceptorStore extends AbstractAcceptorStore { + @Override + public String getType() { + return DataSourceTypeEnum.BACKUP.toString(); + } + + @Override + public List getTargetDataIp(String dataInfoId) { + + List ips = new ArrayList<>(); + List dataServerNodes = metaServerService + .getDataServers(getDataServerConfig().getLocalDataCenter(), dataInfoId); + if (dataServerNodes != null && !dataServerNodes.isEmpty()) { + ips = dataServerNodes.stream().map(DataServerNode::getIp).collect(Collectors.toList()); + } + + return ips; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Scheduler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Scheduler.java new file mode 100644 index 000000000..28b3d0b2b --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/Scheduler.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync.sync; + +import com.alipay.sofa.registry.server.data.datasync.AcceptorStore; +import com.alipay.sofa.registry.task.scheduler.TimedSupervisorTask; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: Scheduler.java, v 0.1 2018-03-07 16:07 shangyu.wh Exp $ + */ +public class Scheduler { + + public final ExecutorService versionCheckExecutor; + private final ScheduledExecutorService scheduler; + private final ThreadPoolExecutor expireCheckExecutor; + + @Autowired + private AcceptorStore localAcceptorStore; + + /** + * constructor + */ + public Scheduler() { + scheduler = new ScheduledThreadPoolExecutor(4, new NamedThreadFactory("SyncDataScheduler")); + + expireCheckExecutor = new ThreadPoolExecutor(1, 3, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SyncDataScheduler-expireChangeCheck")); + + versionCheckExecutor = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new NamedThreadFactory( + "SyncDataScheduler-versionChangeCheck")); + + } + + /** + * start scheduler + */ + public void startScheduler() { + + scheduler.schedule( + new TimedSupervisorTask("FetchDataLocal", scheduler, expireCheckExecutor, 3, + TimeUnit.SECONDS, 10, () -> localAcceptorStore.checkAcceptorsChangAndExpired()), + 30, TimeUnit.SECONDS); + + + versionCheckExecutor.execute(() -> localAcceptorStore.changeDataCheck()); + + } + + /** + * stop scheduler + */ + public void stopScheduler() { + if (scheduler != null && !scheduler.isShutdown()) { + scheduler.shutdown(); + } + if (versionCheckExecutor != null && !versionCheckExecutor.isShutdown()) { + versionCheckExecutor.shutdown(); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/StoreServiceFactory.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/StoreServiceFactory.java new file mode 100644 index 000000000..3dcbb0f0c --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/StoreServiceFactory.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync.sync; + +import com.alipay.sofa.registry.server.data.datasync.AcceptorStore; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: StoreServiceFactory.java, v 0.1 2018-03-22 15:49 shangyu.wh Exp $ + */ +public class StoreServiceFactory implements ApplicationContextAware { + + private static Map storeServiceMap = new HashMap<>(); + + /** + * get AcceptorStore by storeType + * @param storeType + * @return + */ + public static AcceptorStore getStoreService(String storeType) { + return storeServiceMap.get(storeType); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + Map map = applicationContext.getBeansOfType(AcceptorStore.class); + + map.forEach((key, value) -> storeServiceMap.put(value.getType(), value)); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/SyncDataServiceImpl.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/SyncDataServiceImpl.java new file mode 100644 index 000000000..dd0f01389 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/datasync/sync/SyncDataServiceImpl.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.datasync.sync; + +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.datasync.AcceptorStore; +import com.alipay.sofa.registry.server.data.datasync.Operator; +import com.alipay.sofa.registry.server.data.datasync.SyncDataService; + +/** + * + * @author shangyu.wh + * @version $Id: SyncDataService.java, v 0.1 2018-03-07 16:13 shangyu.wh Exp $ + */ +public class SyncDataServiceImpl implements SyncDataService { + + private static final Logger LOGGER = LoggerFactory.getLogger(SyncDataServiceImpl.class, + "[SyncDataService]"); + + @Override + public void appendOperator(Operator operator) { + AcceptorStore acceptorStore = StoreServiceFactory.getStoreService(operator.getSourceType() + .toString()); + if (acceptorStore != null) { + acceptorStore.addOperator(operator); + } else { + LOGGER.error("Can't find acceptor store type {} to Append operator!", + operator.getSourceType()); + throw new RuntimeException("Can't find acceptor store to Append operator!"); + } + } + + @Override + public SyncData getSyncDataChange(SyncDataRequest syncDataRequest) { + AcceptorStore acceptorStore = StoreServiceFactory.getStoreService(syncDataRequest + .getDataSourceType()); + if (acceptorStore != null) { + return acceptorStore.getSyncData(syncDataRequest); + } else { + LOGGER.error("Can't find acceptor store type {} to get sync Data!", + syncDataRequest.getDataSourceType()); + throw new RuntimeException("Can't find acceptor store to get sync Data!"); + } + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/DataServerChangeEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/DataServerChangeEvent.java new file mode 100644 index 000000000..a41dfd113 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/DataServerChangeEvent.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.server.data.cache.DataServerChangeItem; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author qian.lqlq + * @version $Id: DataServerChangeEvent.java, v 0.1 2018-03-13 14:37 qian.lqlq Exp $ + */ +public class DataServerChangeEvent { + + private DataServerChangeItem dataServerChangeItem; + + /** + * constructor + * @param dataServerChangeItem + */ + public DataServerChangeEvent(DataServerChangeItem dataServerChangeItem) { + this.dataServerChangeItem = dataServerChangeItem; + } + + /** + * constructor + * @param serverMap + * @param versionMap + */ + public DataServerChangeEvent(Map> serverMap, + Map versionMap) { + if (serverMap == null) { + serverMap = new HashMap<>(); + } + if (versionMap == null) { + versionMap = new HashMap<>(); + } + this.dataServerChangeItem = new DataServerChangeItem(serverMap, versionMap); + } + + /** + * Getter method for property dataServerChangeItem. + * + * @return property value of dataServerChangeItem + */ + public DataServerChangeItem getDataServerChangeItem() { + return dataServerChangeItem; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/EventCenter.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/EventCenter.java new file mode 100644 index 000000000..3e5dd8daf --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/EventCenter.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event; + +import com.alipay.sofa.registry.server.data.event.handler.AbstractEventHandler; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author qian.lqlq + * @version $Id: EventCenter.java, v 0.1 2018-03-13 14:41 qian.lqlq Exp $ + */ +public class EventCenter { + + private final Map MAP = new ConcurrentHashMap<>(); + + /** + * eventHandler register + * @param handler + */ + public void register(AbstractEventHandler handler) { + MAP.put(handler.interest(), handler); + } + + /** + * event handler handle process + * @param event + */ + public void post(Object event) { + Class clazz = event.getClass(); + if (MAP.containsKey(clazz)) { + MAP.get(clazz).handle(event); + } else { + throw new RuntimeException("no suitable handler was found:" + clazz); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/LocalDataServerChangeEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/LocalDataServerChangeEvent.java new file mode 100644 index 000000000..100af3482 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/LocalDataServerChangeEvent.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; + +import java.util.Map; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: LocalDataServerChangeEvent.java, v 0.1 2018-05-07 20:13 qian.lqlq Exp $ + */ +public class LocalDataServerChangeEvent { + + private Map localDataServerMap; + + private long localDataCenterversion; + + private Set newJoined; + + private long version; + + /** + * constructor + * @param localDataServerMap + * @param newJoined + * @param version + * @param localDataCenterversion + */ + public LocalDataServerChangeEvent(Map localDataServerMap, + Set newJoined, long version, + long localDataCenterversion) { + this.localDataServerMap = localDataServerMap; + this.newJoined = newJoined; + this.version = version; + this.localDataCenterversion = localDataCenterversion; + } + + /** + * Getter method for property localDataServerMap. + * + * @return property value of localDataServerMap + */ + public Map getLocalDataServerMap() { + return localDataServerMap; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public long getVersion() { + return version; + } + + /** + * Getter method for property newJoined. + * + * @return property value of newJoined + */ + public Set getNewJoined() { + return newJoined; + } + + /** + * Getter method for property localDataCenterversion. + * + * @return property value of localDataCenterversion + */ + public long getLocalDataCenterversion() { + return localDataCenterversion; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/MetaServerChangeEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/MetaServerChangeEvent.java new file mode 100644 index 000000000..d726eb664 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/MetaServerChangeEvent.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event; + +import java.util.Map; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: MetaServerChangeEvent.java, v 0.1 2018-03-13 15:31 qian.lqlq Exp $ + */ +public class MetaServerChangeEvent { + + private Map> ipMap; + + /** + * constructor + * @param ipMap + */ + public MetaServerChangeEvent(Map> ipMap) { + this.ipMap = ipMap; + } + + /** + * Getter method for property ipMap. + * + * @return property value of ipMap + */ + public Map> getIpMap() { + return ipMap; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/StartTaskEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/StartTaskEvent.java new file mode 100644 index 000000000..f49f3c01a --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/StartTaskEvent.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event; + +/** + * + * @author qian.lqlq + * @version $Id: StartTaskEvent.java, v 0.1 2018-03-13 15:13 qian.lqlq Exp $ + */ +public class StartTaskEvent { + + private static final StartTaskEvent INSTANCE = new StartTaskEvent(); + + private StartTaskEvent() { + } + + /** + * get instance of StartTaskEvent + * @return + */ + public static StartTaskEvent getInstance() { + return INSTANCE; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/AbstractEventHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/AbstractEventHandler.java new file mode 100644 index 000000000..e33401b61 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/AbstractEventHandler.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event.handler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author qian.lqlq + * @version $Id: AbstractEventHandler.java, v 0.1 2018-03-13 15:34 qian.lqlq Exp $ + */ +public abstract class AbstractEventHandler implements InitializingBean { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractEventHandler.class); + + @Autowired + private EventCenter eventCenter; + + @Override + public void afterPropertiesSet() throws Exception { + eventCenter.register(this); + } + + /** + * event handle func + * @param event + */ + public void handle(T event) { + try { + doHandle(event); + } catch (Exception e) { + LOGGER.error("[{}] handle event error", this.getClass().getSimpleName(), e); + } + } + + public abstract Class interest(); + + public abstract void doHandle(T event); +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/DataServerChangeEventHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/DataServerChangeEventHandler.java new file mode 100644 index 000000000..931877b03 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/DataServerChangeEventHandler.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event.handler; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.cache.DataServerChangeItem; +import com.alipay.sofa.registry.server.data.event.DataServerChangeEvent; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.event.LocalDataServerChangeEvent; +import com.alipay.sofa.registry.server.data.node.DataServerNode; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerNodeFactory; +import com.alipay.sofa.registry.server.data.util.TimeUtil; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author qian.lqlq + * @version $Id: DataServerChangeEventHandler.java, v 0.1 2018-03-13 14:38 qian.lqlq Exp $ + */ +public class DataServerChangeEventHandler extends AbstractEventHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataServerChangeEventHandler.class); + + private static final int TRY_COUNT = 5; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private DataServerCache dataServerCache; + + @Autowired + private DataNodeExchanger dataNodeExchanger; + + @Autowired + private EventCenter eventCenter; + + @Override + public Class interest() { + return DataServerChangeEvent.class; + } + + @Override + public void doHandle(DataServerChangeEvent event) { + synchronized (this) { + //register self first,execute once + DataServerNodeFactory.initConsistent(dataServerBootstrapConfig); + + DataServerChangeItem dataServerChangeItem = event.getDataServerChangeItem(); + Set localDataServers = dataServerCache.getDataServers( + dataServerBootstrapConfig.getLocalDataCenter()).keySet(); + //get changed dataservers + Map> changedMap = dataServerCache + .compareAndSet(dataServerChangeItem); + if(!changedMap.isEmpty()) { + for (Entry> changeEntry : changedMap.entrySet()) { + String dataCenter = changeEntry.getKey(); + Set ips = changeEntry.getValue(); + if (!CollectionUtils.isEmpty(ips)) { + for (String ip : ips) { + if (!StringUtils.equals(ip, DataServerConfig.IP)) { + DataServerNode dataServerNode = DataServerNodeFactory + .getDataServerNode(dataCenter, ip); + if (dataServerNode == null || dataServerNode.getConnection() == null + || !dataServerNode.getConnection().isFine()) { + connectDataServer(dataCenter, ip); + } + } + } + //remove all old DataServerNode not in change map + Set ipSet = DataServerNodeFactory.getIps(dataCenter); + for (String ip : ipSet) { + if (!ips.contains(ip)) { + DataServerNodeFactory.remove(dataCenter, ip, dataServerBootstrapConfig); + LOGGER.info( + "[DataServerChangeEventHandler] remove connection, datacenter:{}, ip:{}", + dataCenter, ip); + } + } + + Long newVersion = dataServerCache.getDataCenterNewVersion(dataCenter); + Map newDataNodes = dataServerCache.getNewDataServerMap(dataCenter); + //if the datacenter is self, post LocalDataServerChangeEvent + if (dataServerBootstrapConfig.getLocalDataCenter().equals(dataCenter)) { + Set newjoined = new HashSet<>(ips); + newjoined.removeAll(localDataServers); + //avoid input map reference operation DataServerNodeFactory MAP + Map map = new ConcurrentHashMap<>(newDataNodes); + + LOGGER.info("Node list change fire LocalDataServerChangeEvent,current node list={},version={}", + map.keySet(), newVersion); + eventCenter.post(new LocalDataServerChangeEvent(map, newjoined, + dataServerChangeItem.getVersionMap() + .get(dataServerBootstrapConfig.getLocalDataCenter()), + newVersion)); + } else { + dataServerCache.updateItem(newDataNodes, newVersion, dataCenter); + } + } else { + //if the datacenter which has no dataservers is not self, remove it + if (!dataServerBootstrapConfig.getLocalDataCenter().equals(dataCenter)) { + removeDataCenter(dataCenter); + } + Long newVersion = dataServerCache.getDataCenterNewVersion(dataCenter); + Map newDataNodes = dataServerCache.getNewDataServerMap(dataCenter); + dataServerCache.updateItem(newDataNodes, newVersion, dataCenter); + } + } + } else { + //refresh for keep connect + Set allDataCenter = new HashSet<>(DataServerNodeFactory.getAllDataCenters()); + for (String dataCenter:allDataCenter) { + Map dataNodes = DataServerNodeFactory.getDataServerNodes(dataCenter); + if(dataNodes != null && !dataNodes.isEmpty()){ + + dataNodes.forEach((ip,dataServerNode)->{ + if (!StringUtils.equals(ip, DataServerConfig.IP)) { + Connection connection = dataServerNode.getConnection(); + if (connection != null && !connection.isFine()) { + LOGGER.warn("[DataServerChangeEventHandler] dataServer connections is not fine,try to reconnect it,old connection={},dataCenter={}", + connection.getRemoteAddress(), dataCenter); + connectDataServer(dataCenter, ip); + } + } + }); + } + } + } + } + } + + /** + * connect specific dataserver + * + * @param dataCenter + * @param ip + */ + private void connectDataServer(String dataCenter, String ip) { + Connection conn = null; + for (int tryCount = 0; tryCount < TRY_COUNT; tryCount++) { + try { + conn = ((BoltChannel) dataNodeExchanger.connect(new URL(ip, + dataServerBootstrapConfig.getSyncDataPort()))).getConnection(); + break; + } catch (Exception e) { + LOGGER.error("[DataServerChangeEventHandler] connect dataServer {} in {} error", + ip, dataCenter, e); + TimeUtil.randomDelay(3000); + } + } + if (conn == null || !conn.isFine()) { + LOGGER.error( + "[DataServerChangeEventHandler] connect dataserver {} in {} failed five times", ip, + dataCenter); + throw new RuntimeException( + String + .format( + "[DataServerChangeEventHandler] connect dataserver %s in %s failed five times,dataServer will not work,please check connect!", + ip, dataCenter)); + } + //maybe get dataNode from metaServer,current has not start! register dataNode info to factory,wait for connect task next execute + DataServerNodeFactory.register(new DataServerNode(ip, dataCenter, conn), + dataServerBootstrapConfig); + } + + /** + * remove datacenter, and close connections of dataservers in this datacenter + * + * @param dataCenter + */ + private void removeDataCenter(String dataCenter) { + DataServerNodeFactory.getDataServerNodes(dataCenter).values().stream().map(DataServerNode::getConnection) + .filter(connection -> connection != null && connection.isFine()).forEach(Connection::close); + DataServerNodeFactory.remove(dataCenter); + LOGGER.info( + "[DataServerChangeEventHandler] remove connections of datacenter : {}", dataCenter); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/LocalDataServerChangeEventHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/LocalDataServerChangeEventHandler.java new file mode 100644 index 000000000..774b7572f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/LocalDataServerChangeEventHandler.java @@ -0,0 +1,385 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.NotifyFetchDatumRequest; +import com.alipay.sofa.registry.common.model.dataserver.NotifyOnlineRequest; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.consistency.hash.ConsistentHash; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.BackupTriad; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.correction.LocalDataServerCleanHandler; +import com.alipay.sofa.registry.server.data.event.LocalDataServerChangeEvent; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.node.DataNodeStatus; +import com.alipay.sofa.registry.server.data.node.DataServerNode; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerNodeFactory; +import com.alipay.sofa.registry.server.data.util.LocalServerStatusEnum; +import com.alipay.sofa.registry.server.data.util.TimeUtil; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * + * @author qian.lqlq + * @version $Id: LocalDataServerChangeEventHandler.java, v 0.1 2018-04-28 23:55 qian.lqlq Exp $ + */ +public class LocalDataServerChangeEventHandler extends + AbstractEventHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(LocalDataServerChangeEventHandler.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private LocalDataServerCleanHandler localDataServerCleanHandler; + + @Autowired + private DataServerCache dataServerCache; + + @Autowired + private DataNodeExchanger dataNodeExchanger; + + @Autowired + private DataNodeStatus dataNodeStatus; + + private BlockingQueue events = new LinkedBlockingDeque<>(); + + private AtomicBoolean isChanged = new AtomicBoolean(false); + + @Override + public Class interest() { + return LocalDataServerChangeEvent.class; + } + + @Override + public void doHandle(LocalDataServerChangeEvent localDataServerChangeEvent) { + isChanged.set(true); + localDataServerCleanHandler.reset(); + events.offer(localDataServerChangeEvent); + } + + @Override + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + start(); + } + + /** + * + */ + public void start() { + Executor executor = ExecutorFactory + .newSingleThreadExecutor(LocalDataServerChangeEventHandler.class.getSimpleName()); + executor.execute(new LocalClusterDataSyncer()); + } + + private class LocalClusterDataSyncer implements Runnable { + + @Override + public void run() { + while (true) { + try { + LocalDataServerChangeEvent event = events.take(); + //if the new joined servers contains self, set status as INITIAL + Set newJoined = event.getNewJoined(); + if (newJoined.contains(DataServerConfig.IP) + && dataNodeStatus.getStatus() != LocalServerStatusEnum.INITIAL) { + dataNodeStatus.setStatus(LocalServerStatusEnum.INITIAL); + } + //if size of events is greater than 0, not handle and continue, only handle the last one in the queue + if (events.size() > 0) { + continue; + } + long changeVersion = event.getVersion(); + + LOGGER.info("begin handle dataserver change, version={},localDataServer={}", + changeVersion, event.getLocalDataServerMap().keySet()); + isChanged.set(false); + if (LocalServerStatusEnum.WORKING == dataNodeStatus.getStatus()) { + //if local server is working, compare sync data + notifyToFetch(event, changeVersion); + } else { + dataServerCache.checkAndUpdateStatus(changeVersion); + //if local server is not working, notify others that i am newer + notifyOnline(changeVersion); + + dataServerCache.updateItem(event.getLocalDataServerMap(), + event.getLocalDataCenterversion(), + dataServerBootstrapConfig.getLocalDataCenter()); + } + } catch (Throwable t) { + LOGGER.error("sync local data error", t); + } + } + } + + /** + * notify onlined newly dataservers to fetch datum + * + * @param event + * @param changeVersion + */ + private void notifyToFetch(LocalDataServerChangeEvent event, long changeVersion) { + + Map dataServerMapIn = event.getLocalDataServerMap(); + List dataServerNodeList = Lists.newArrayList(dataServerMapIn.values()); + ConsistentHash consistentHash = new ConsistentHash<>( + dataServerBootstrapConfig.getNumberOfReplicas(), dataServerNodeList); + Map dataServerMap = new ConcurrentHashMap<>(dataServerMapIn); + + Map>> toBeSyncMap = getToBeSyncMap(consistentHash); + if (!isChanged.get()) { + if (!toBeSyncMap.isEmpty()) { + for (Entry>> toBeSyncEntry : toBeSyncMap + .entrySet()) { + String ip = toBeSyncEntry.getKey(); + Map> allVersionMap = new HashMap<>(); + Map> dataInfoMap = toBeSyncEntry + .getValue(); + for (Entry> dataCenterEntry : dataInfoMap + .entrySet()) { + String dataCenter = dataCenterEntry.getKey(); + Map versionMap = new HashMap<>(); + Map dataTriadMap = dataCenterEntry.getValue(); + for (Entry dataTriadEntry : dataTriadMap + .entrySet()) { + String dataInfoId = dataTriadEntry.getKey(); + Datum datum = DatumCache.get(dataCenter, dataInfoId); + if (datum != null) { + versionMap.put(dataInfoId, datum.getVersion()); + } + } + if (!versionMap.isEmpty()) { + allVersionMap.put(dataCenter, versionMap); + } + } + if (!allVersionMap.isEmpty()) { + dataServerMap.remove(ip); + if (doNotify(ip, allVersionMap, changeVersion)) { + //remove new status node,avoid duplicate notify sync data + dataServerCache.removeNotifyNewStatusNode(ip); + } + } + } + } + //if no datum to notify, notify empty map + if (!dataServerMap.isEmpty()) { + for (String targetIp : dataServerMap.keySet()) { + if (doNotify(targetIp, new HashMap<>(), changeVersion)) { + //remove new status node,avoid duplicate notify sync data + dataServerCache.removeNotifyNewStatusNode(targetIp); + } + } + } + if (!isChanged.get()) { + //update server list + dataServerCache.updateItem(dataServerMapIn, event.getLocalDataCenterversion(), + dataServerBootstrapConfig.getLocalDataCenter()); + } + } + } + + /** + * get map of datum to be synced + * + * @param consistentHash + * @return + */ + private Map>> getToBeSyncMap(ConsistentHash consistentHash) { + + Map>> toBeSyncMap = new HashMap<>(); + Map> triadCache = new HashMap<>(); + + //compute new triad for every datum in cache + Map> allMap = DatumCache.getAll(); + for (Entry> dataCenterEntry : allMap.entrySet()) { + String dataCenter = dataCenterEntry.getKey(); + Map datumMap = dataCenterEntry.getValue(); + for (String dataInfoId : datumMap.keySet()) { + //if dataservers are changed, no longer to handle + if (isChanged.get()) { + return new HashMap<>(); + } + //compute new triad by new dataservers + List backupNodes; + if (triadCache.containsKey(dataInfoId)) { + backupNodes = triadCache.get(dataInfoId); + } else { + backupNodes = consistentHash.getNUniqueNodesFor(dataInfoId, + dataServerBootstrapConfig.getStoreNodes()); + triadCache.put(dataInfoId, backupNodes); + } + BackupTriad backupTriad = dataServerCache.calculateOldBackupTriad(dataInfoId, + dataServerBootstrapConfig.getLocalDataCenter(), dataServerBootstrapConfig); + if (backupTriad != null) { + List newJoinedNodes = backupTriad.getNewJoined(backupNodes, + dataServerCache.getNotWorking()); + //all data node send notify to new join,the same data maybe send twice,receiver check same data duplicate! + LOGGER + .info( + "DataInfoId {} has got newJoinedNodes={} for backupNodes={},now backupTriad is {}", + dataInfoId, newJoinedNodes, backupNodes, backupTriad); + if (!newJoinedNodes.isEmpty()) { + for (DataNode node : newJoinedNodes) { + String ip = node.getIp(); + if (!toBeSyncMap.containsKey(ip)) { + toBeSyncMap.put(ip, new HashMap<>()); + } + Map> dataInfoMap = toBeSyncMap + .get(ip); + if (!dataInfoMap.containsKey(dataCenter)) { + dataInfoMap.put(dataCenter, new HashMap<>()); + } + dataInfoMap.get(dataCenter).put(dataInfoId, backupTriad); + } + } + } + } + } + LOGGER.info("Get to Be SyncMap {}", toBeSyncMap); + return toBeSyncMap; + } + + /** + * do notify + * + * @param targetIp + * @param notifyVersionMap + */ + private boolean doNotify(String targetIp, Map> notifyVersionMap, + long version) { + while (!isChanged.get()) { + DataServerNode targetNode = DataServerNodeFactory.getDataServerNode( + dataServerBootstrapConfig.getLocalDataCenter(), targetIp); + if (targetNode == null || targetNode.getConnection() == null) { + LOGGER.info( + "notify version change to sync has not connect,targetNode={}, map={}", + targetIp, notifyVersionMap); + return false; + } + try { + CommonResponse response = (CommonResponse) dataNodeExchanger.request( + new Request() { + @Override + public Object getRequestBody() { + return new NotifyFetchDatumRequest(notifyVersionMap, + DataServerConfig.IP, version); + } + + @Override + public URL getRequestUrl() { + return new URL(targetNode.getConnection().getRemoteIP(), targetNode + .getConnection().getRemotePort()); + } + }).getResult(); + + if (response.isSuccess()) { + LOGGER + .info( + "notify {} version change to sync,current node list version={}, map={}", + targetNode.getIp(), version, notifyVersionMap); + return true; + } else { + throw new RuntimeException(response.getMessage()); + } + } catch (Throwable e) { + LOGGER.error("notify {} to fetch datum error", targetIp, e); + TimeUtil.randomDelay(500); + } + } + return false; + } + + /** + * notify other dataservers that this server is online newly + * + * @param changeVersion + */ + private void notifyOnline(long changeVersion) { + Map dataServerNodeMap = DataServerNodeFactory + .getDataServerNodes(dataServerBootstrapConfig.getLocalDataCenter()); + for (Entry serverEntry : dataServerNodeMap.entrySet()) { + while (true) { + String ip = serverEntry.getKey(); + DataServerNode dataServerNode = serverEntry.getValue(); + if (dataServerNode == null) { + break; + } + try { + if (dataServerNode.getConnection() == null + || !dataServerNode.getConnection().isFine()) { + //maybe get dataNode from metaServer,current has not connected!wait for connect task execute + TimeUtil.randomDelay(1000); + continue; + } + CommonResponse response = (CommonResponse) dataNodeExchanger.request( + new Request() { + + @Override + public Object getRequestBody() { + return new NotifyOnlineRequest(DataServerConfig.IP, + changeVersion); + } + + @Override + public URL getRequestUrl() { + return new URL(dataServerNode.getConnection().getRemoteIP(), + dataServerNode.getConnection().getRemotePort()); + } + }).getResult(); + if (response.isSuccess()) { + LOGGER.info("notify {} that i am newer success,version={}", ip, + changeVersion); + break; + } else { + throw new RuntimeException(response.getMessage()); + } + } catch (Exception e) { + LOGGER.info("notify {} that i am newer failed", ip); + LOGGER.error("notify {} that i am newer error", ip, e); + TimeUtil.randomDelay(500); + } + } + } + } + + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/MetaServerChangeEventHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/MetaServerChangeEventHandler.java new file mode 100644 index 000000000..3518503cb --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/MetaServerChangeEventHandler.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event.handler; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.event.DataServerChangeEvent; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.event.MetaServerChangeEvent; +import com.alipay.sofa.registry.server.data.remoting.MetaNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import com.alipay.sofa.registry.server.data.remoting.metaserver.MetaServerConnectionFactory; +import com.alipay.sofa.registry.server.data.util.TimeUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: MetaServerChangeEventHandler.java, v 0.1 2018-03-13 15:31 qian.lqlq Exp $ + */ +public class MetaServerChangeEventHandler extends AbstractEventHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaServerChangeEventHandler.class); + private static final int TRY_COUNT = 3; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private IMetaServerService metaServerService; + + @Autowired + private MetaNodeExchanger metaNodeExchanger; + + @Autowired + private EventCenter eventCenter; + + @Autowired + private MetaServerConnectionFactory metaServerConnectionFactory; + + @Override + public Class interest() { + return MetaServerChangeEvent.class; + } + + @Override + public void doHandle(MetaServerChangeEvent event) { + Map> ipMap = event.getIpMap(); + for (Entry> ipEntry : ipMap.entrySet()) { + String dataCenter = ipEntry.getKey(); + Set ips = ipEntry.getValue(); + if (!CollectionUtils.isEmpty(ips)) { + for (String ip : ips) { + Connection connection = metaServerConnectionFactory.getConnection(dataCenter, + ip); + if (connection == null || !connection.isFine()) { + registerMetaServer(dataCenter, ip); + } + } + Set ipSet = metaServerConnectionFactory.getIps(dataCenter); + for (String ip : ipSet) { + if (!ips.contains(ip)) { + metaServerConnectionFactory.remove(dataCenter, ip); + LOGGER + .info( + "[MetaServerChangeEventHandler] remove connection, datacenter:{}, ip:{}", + dataCenter, ip); + } + } + } else { + //remove connections of dataCenter if the connectionMap of the dataCenter in ipMap is empty + removeDataCenter(dataCenter); + } + } + //remove connections of dataCenter if the dataCenter not exist in ipMap + Set dataCenters = metaServerConnectionFactory.getAllDataCenters(); + for (String dataCenter : dataCenters) { + if (!ipMap.containsKey(dataCenter)) { + removeDataCenter(dataCenter); + } + } + } + + private void registerMetaServer(String dataCenter, String ip) { + + PeerId leader = metaServerService.getLeader(); + + for (int tryCount = 0; tryCount < TRY_COUNT; tryCount++) { + try { + Channel channel = metaNodeExchanger.connect(new URL(ip, dataServerBootstrapConfig + .getMetaServerPort())); + //connect all meta server + if (channel != null && channel.isConnected()) { + metaServerConnectionFactory.register(dataCenter, ip, + ((BoltChannel) channel).getConnection()); + } + //register leader meta node + if (ip.equals(leader.getIp())) { + Object obj = null; + try { + obj = metaNodeExchanger.request(new Request() { + @Override + public Object getRequestBody() { + return new DataNode(new URL(DataServerConfig.IP), + dataServerBootstrapConfig.getLocalDataCenter()); + } + + @Override + public URL getRequestUrl() { + return new URL(ip, dataServerBootstrapConfig.getMetaServerPort()); + } + }).getResult(); + } catch (Exception e) { + PeerId newLeader = metaServerService.refreshLeader(); + LOGGER + .error( + + "[MetaServerChangeEventHandler] register data node send error!retry once leader :{} error", + newLeader.getIp(), e); + } + if (obj instanceof NodeChangeResult) { + NodeChangeResult result = (NodeChangeResult) obj; + Map versionMap = result.getDataCenterListVersions(); + eventCenter.post(new DataServerChangeEvent(result.getNodes(), versionMap)); + break; + } + } + + } catch (Exception e) { + LOGGER.error("[MetaServerChangeEventHandler] connect metaServer:{} error", ip, e); + TimeUtil.randomDelay(1000); + } + } + } + + private void removeDataCenter(String dataCenter) { + metaServerConnectionFactory.remove(dataCenter); + LOGGER.info("[MetaServerChangeEventHandler] remove connections of datacenter : {}", + dataCenter); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/StartTaskEventHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/StartTaskEventHandler.java new file mode 100644 index 000000000..c6adfffe1 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/event/handler/StartTaskEventHandler.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.event.handler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.cache.CacheDigestTask; +import com.alipay.sofa.registry.server.data.event.StartTaskEvent; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.remoting.dataserver.task.AbstractTask; + +import javax.annotation.Resource; +import java.util.List; +import java.util.concurrent.ScheduledExecutorService; + +/** + * + * @author qian.lqlq + * @version $Id: StartTaskEventHandler.java, v 0.1 2018-03-07 21:21 qian.lqlq Exp $ + */ +public class StartTaskEventHandler extends AbstractEventHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(StartTaskEventHandler.class); + + @Resource(name = "tasks") + private List tasks; + + private ScheduledExecutorService executor = null; + + @Override + public Class interest() { + return StartTaskEvent.class; + } + + @Override + public void doHandle(StartTaskEvent event) { + if (executor == null || executor.isShutdown()) { + executor = ExecutorFactory.newScheduledThreadPool(tasks.size(), this.getClass() + .getSimpleName()); + for (AbstractTask task : tasks) { + LOGGER.info("[StartTaskEventHandler] start task:{}", task.getName()); + executor.scheduleWithFixedDelay(task, task.getInitialDelay(), task.getDelay(), + task.getTimeUnit()); + LOGGER.info("[StartTaskEventHandler] start task:{} success", task.getName()); + } + new CacheDigestTask().start(); + } + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/executor/ExecutorFactory.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/executor/ExecutorFactory.java new file mode 100644 index 000000000..233e6013c --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/executor/ExecutorFactory.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.executor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.util.NamedThreadFactory; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * the factory to create executor + * + * @author qian.lqlq + * @version $Id: ExecutorFactory.java, v 0.1 2018-03-08 14:50 qian.lqlq Exp $ + */ +public class ExecutorFactory { + + public static final ThreadPoolExecutor EXECUTOR; + private static final Logger LOGGER = LoggerFactory.getLogger(ExecutorFactory.class); + + static { + BlockingQueue workQueue = new ArrayBlockingQueue<>(10); + EXECUTOR = new ThreadPoolExecutor(20, 300, 1, TimeUnit.HOURS, workQueue, + new NamedThreadFactory("CommonExecutor")) { + + /** + * @see ThreadPoolExecutor#afterExecute(Runnable, Throwable) + */ + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + if (t != null) { + LOGGER.error("[CommonThreadPool] ThreadPoolUncaughtException:{}", + t.getMessage(), t); + } + } + }; + } + + /** + * get executor + * @return + */ + public static ThreadPoolExecutor getCommonExecutor() { + return EXECUTOR; + } + + /** + * new thread pool + * @param size + * @param name + * @return + */ + public static Executor newFixedThreadPool(int size, String name) { + return new ThreadPoolExecutor(size, size, 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), new NamedThreadFactory(name)); + } + + /** + * new scheduled thread pool + * @param size + * @param name + * @return + */ + public static ScheduledExecutorService newScheduledThreadPool(int size, String name) { + return new ScheduledThreadPoolExecutor(size, new NamedThreadFactory(name)); + } + + /** + * new single thread executor + * @param name + * @return + */ + public static Executor newSingleThreadExecutor(String name) { + return new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), + new NamedThreadFactory(name)); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataNodeStatus.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataNodeStatus.java new file mode 100644 index 000000000..3273ec221 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataNodeStatus.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.node; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.util.LocalServerStatusEnum; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DataNodeStatus { + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeStatus.class); + private volatile LocalServerStatusEnum status = LocalServerStatusEnum.INITIAL; + + public LocalServerStatusEnum getStatus() { + return status; + } + + public void setStatus(LocalServerStatusEnum status) { + LocalServerStatusEnum originStatus = this.status; + this.status = status; + LOGGER.info("[DataNodeStatus] status change from {} to {}", originStatus.name(), + status.name()); + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataServerNode.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataServerNode.java new file mode 100644 index 000000000..f7bff800e --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/node/DataServerNode.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.node; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.consistency.hash.HashNode; + +/** + * + * @author qian.lqlq + * @version $Id: DataServerNode.java, v 0.1 2018-03-13 18:29 qian.lqlq Exp $ + */ +public class DataServerNode implements HashNode { + + private String ip; + + private String dataCenter; + + private Connection connection; + + /** + * constructor + * @param ip + * @param dataCenter + * @param connection + */ + public DataServerNode(String ip, String dataCenter, Connection connection) { + this.ip = ip; + this.dataCenter = dataCenter; + this.connection = connection; + } + + @Override + public String getNodeName() { + return ip; + } + + /** + * Getter method for property ip. + * + * @return property value of ip + */ + public String getIp() { + return ip; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Getter method for property connection. + * + * @return property value of connection + */ + public Connection getConnection() { + return connection; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DataServerNode{"); + sb.append("ip='").append(ip).append('\''); + sb.append(", dataCenter='").append(dataCenter); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/DataNodeExchanger.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/DataNodeExchanger.java new file mode 100644 index 000000000..23b9865c3 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/DataNodeExchanger.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DataNodeExchanger implements NodeExchanger { + private static final Logger LOGGER = LoggerFactory + .getLogger(DataNodeExchanger.class); + + @Autowired + private Exchange boltExchange; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Resource(name = "dataClientHandlers") + private Collection dataClientHandlers; + + @Override + public Response request(Request request) { + Channel channel = this.connect(request.getRequestUrl()); + Client client = boltExchange.getClient(Exchange.DATA_SERVER_TYPE); + LOGGER.info("DataNode Exchanger request={},url={},callbackHandler={}", request.getRequestBody(), + request.getRequestUrl(), request.getCallBackHandler()); + + if (null != request.getCallBackHandler()) { + client.sendCallback(channel, request.getRequestBody(), + request.getCallBackHandler(), + dataServerBootstrapConfig.getRpcTimeout()); + return () -> Response.ResultStatus.SUCCESSFUL; + } else { + final Object result = client.sendSync(channel, request.getRequestBody(), + dataServerBootstrapConfig.getRpcTimeout()); + return () -> result; + } + } + + public Channel connect(URL url) { + Client client = boltExchange.getClient(Exchange.DATA_SERVER_TYPE); + if (client == null) { + synchronized (this) { + client = boltExchange.getClient(Exchange.DATA_SERVER_TYPE); + if (client == null) { + client = boltExchange.connect(Exchange.DATA_SERVER_TYPE, url, + dataClientHandlers.toArray(new ChannelHandler[dataClientHandlers.size()])); + } + } + } + + Channel channel = client.getChannel(url); + if (channel == null) { + synchronized (this) { + channel = client.getChannel(url); + if (channel == null) { + channel = client.connect(url); + } + } + } + + return channel; + } + + @Override + public Client connectServer() { + throw new UnsupportedOperationException(); + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/MetaNodeExchanger.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/MetaNodeExchanger.java new file mode 100644 index 000000000..607beec97 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/MetaNodeExchanger.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class MetaNodeExchanger implements NodeExchanger { + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaNodeExchanger.class); + + @Autowired + private Exchange boltExchange; + + @Autowired + private IMetaServerService metaServerService; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Resource(name = "metaClientHandlers") + private Collection metaClientHandlers; + + @Override + public Response request(Request request) { + Channel channel = connect(request.getRequestUrl()); + Client client = boltExchange.getClient(Exchange.META_SERVER_TYPE); + LOGGER.info("MetaNode Exchanger request={},url={},callbackHandler={}", request.getRequestBody(), + request.getRequestUrl(), request.getCallBackHandler()); + + try { + final Object result = client.sendSync(channel, request.getRequestBody(), + dataServerBootstrapConfig.getRpcTimeout()); + return () -> result; + } catch (Exception e) { + //retry + URL url = new URL(metaServerService.refreshLeader().getIp(), + dataServerBootstrapConfig.getMetaServerPort()); + channel = client.getChannel(url); + if (channel == null) { + channel = client.connect(url); + } + LOGGER.warn("MetaNode Exchanger request send error!It will be retry once!Request url:{}", url); + + final Object result = client.sendSync(channel, request.getRequestBody(), + dataServerBootstrapConfig.getRpcTimeout()); + return () -> result; + } + } + + public Channel connect(URL url) { + Client client = boltExchange.getClient(Exchange.META_SERVER_TYPE); + if (client == null) { + synchronized (this) { + client = boltExchange.getClient(Exchange.META_SERVER_TYPE); + if (client == null) { + client = boltExchange.connect(Exchange.META_SERVER_TYPE, url, + metaClientHandlers.toArray(new ChannelHandler[metaClientHandlers.size()])); + } + } + } + //try to connect data + Channel channel = client.getChannel(url); + if (channel == null) { + synchronized (this) { + channel = client.getChannel(url); + if (channel == null) { + channel = client.connect(url); + } + } + } + + return channel; + } + + @Override + public Client connectServer() { + throw new UnsupportedOperationException(); + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerConnectionFactory.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerConnectionFactory.java new file mode 100644 index 000000000..6cb2d8f9b --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerConnectionFactory.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver; + +import com.alipay.remoting.Connection; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * the factory to hold connections that other dataservers connected to local server + * + * @author qian.lqlq + * @version $Id: DataServerConnectionFactory.java, v 0.1 2018-03-07 17:52 qian.lqlq Exp $ + */ +public class DataServerConnectionFactory { + + /** + * collection of connections + * key:ip + */ + private final Map MAP = new ConcurrentHashMap<>(); + + /** + * register connection + * + * @param connection + */ + public void register(Connection connection) { + MAP.put(connection.getRemoteIP(), connection); + } + + /** + * remove connection by specific ip + * + * @param connection + */ + public void remove(Connection connection) { + MAP.remove(connection.getRemoteIP()); + } + + /** + * get connection by ip + * + * @param ip + * @return + */ + public Connection getConnection(String ip) { + return MAP.get(ip); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerNodeFactory.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerNodeFactory.java new file mode 100644 index 000000000..53a484bea --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/DataServerNodeFactory.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.consistency.hash.ConsistentHash; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.node.DataServerNode; +import com.google.common.collect.Lists; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * the factory to hold other dataservers and connection connected to them + * + * @author qian.lqlq + * @version $Id: DataServerNodeFactory.java, v 0.1 2018-03-13 18:45 qian.lqlq Exp $ + */ +public class DataServerNodeFactory { + + /** + * row: dataCenter + * column: ip + * value dataServerNode + */ + private static final Map> MAP = new ConcurrentHashMap<>(); + + /** + * key: dataCenter + * value: consistentHash + */ + private static final Map> CONSISTENT_HASH_MAP = new ConcurrentHashMap<>(); + + private static AtomicBoolean init = new AtomicBoolean( + false); + + /** + * add a dataserver to cache + * + * @param dataServerNode + */ + public static void register(DataServerNode dataServerNode, + DataServerConfig dataServerBootstrapConfig) { + String dataCenter = dataServerNode.getDataCenter(); + if (!MAP.containsKey(dataCenter)) { + MAP.put(dataCenter, new ConcurrentHashMap<>()); + } + MAP.get(dataCenter).put(dataServerNode.getIp(), dataServerNode); + refreshConsistent(dataCenter, dataServerBootstrapConfig); + } + + /** + * refresh instance of consistentHash + * + * @param dataCenter + */ + public static void refreshConsistent(String dataCenter, + DataServerConfig dataServerBootstrapConfig) { + List dataServerNodes = Lists.newArrayList(MAP.get(dataCenter).values()); + if (dataServerBootstrapConfig.getLocalDataCenter().equals(dataCenter)) { + if (!MAP.get(dataCenter).keySet().contains(DataServerConfig.IP)) { + dataServerNodes.add(new DataServerNode(DataServerConfig.IP, + dataServerBootstrapConfig.getLocalDataCenter(), null)); + } + } + CONSISTENT_HASH_MAP.put(dataCenter, + new ConsistentHash<>(dataServerBootstrapConfig.getNumberOfReplicas(), dataServerNodes)); + } + + /** + * for single node consistentHash + * @param dataServerBootstrapConfig + */ + public static void initConsistent(DataServerConfig dataServerBootstrapConfig) { + if (init.compareAndSet(false, true)) { + List dataServerNodes = Lists.newArrayList(); + dataServerNodes.add(new DataServerNode(DataServerConfig.IP, dataServerBootstrapConfig + .getLocalDataCenter(), null)); + CONSISTENT_HASH_MAP.put(dataServerBootstrapConfig.getLocalDataCenter(), + new ConsistentHash<>(dataServerBootstrapConfig.getNumberOfReplicas(), + dataServerNodes)); + } + } + + /** + * get dataserver by specific datacenter and ip + * + * @param dataCenter + * @param ip + * @return + */ + public static DataServerNode getDataServerNode(String dataCenter, String ip) { + if (MAP.containsKey(dataCenter)) { + Map map = MAP.get(dataCenter); + if (map.containsKey(ip)) { + return map.get(ip); + } + } + return null; + } + + /** + * get dataservers by specific datacenter + * + * @param dataCenter + * @return + */ + public static Map getDataServerNodes(String dataCenter) { + if (MAP.containsKey(dataCenter)) { + return MAP.get(dataCenter); + } else { + return new HashMap<>(); + } + } + + /** + * get ip of dataservers by specific datacenter + * + * @param dataCenter + * @return + */ + public static Set getIps(String dataCenter) { + if (MAP.containsKey(dataCenter)) { + Map map = MAP.get(dataCenter); + if (map != null) { + return map.keySet(); + } + } + return new HashSet<>(); + } + + /** + * remove dataserver by specific datacenter and ip + * + * @param dataCenter + * @param ip + */ + public static void remove(String dataCenter, String ip, + DataServerConfig dataServerBootstrapConfig) { + if (MAP.containsKey(dataCenter)) { + Map map = MAP.get(dataCenter); + if (map != null) { + DataServerNode dataServerNode = map.get(ip); + Connection connection = dataServerNode.getConnection(); + if (connection != null && connection.isFine()) { + connection.close(); + } + map.remove(ip); + } + } + refreshConsistent(dataCenter, dataServerBootstrapConfig); + } + + /** + * remove dataservers by specific datacenter + * + * @param dataCenter + */ + public static void remove(String dataCenter) { + getDataServerNodes(dataCenter).values().stream().map(DataServerNode::getConnection) + .filter(connection -> connection != null && connection.isFine()).forEach(Connection::close); + MAP.remove(dataCenter); + CONSISTENT_HASH_MAP.remove(dataCenter); + } + + /** + * get dataserver by specific datacenter and dataInfoId + * + * @param dataCenter + * @param dataInfoId + * @return + */ + public static DataServerNode computeDataServerNode(String dataCenter, String dataInfoId) { + ConsistentHash consistentHash = CONSISTENT_HASH_MAP.get(dataCenter); + if (consistentHash != null) { + return CONSISTENT_HASH_MAP.get(dataCenter).getNodeFor(dataInfoId); + } + return null; + } + + public static List computeDataServerNodes(String dataCenter, String dataInfoId, + int backupNodes) { + ConsistentHash consistentHash = CONSISTENT_HASH_MAP.get(dataCenter); + if (consistentHash != null) { + return CONSISTENT_HASH_MAP.get(dataCenter).getNUniqueNodesFor(dataInfoId, backupNodes); + } + return null; + } + + /** + * get all datacenters + * + * @return + */ + public static Set getAllDataCenters() { + return MAP.keySet(); + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/GetSyncDataHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/GetSyncDataHandler.java new file mode 100644 index 000000000..c315110ee --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/GetSyncDataHandler.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author qian.lqlq + * @version $Id: GetSyncDataHandler.java, v 0.1 2018-03-08 14:18 qian.lqlq Exp $ + */ +public class GetSyncDataHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(GetSyncDataHandler.class); + + @Autowired + private DataNodeExchanger dataNodeExchanger; + + /** + * + * + * @param callback + */ + public void syncData(SyncDataCallback callback) { + int tryCount = callback.getRetryCount(); + if (tryCount > 0) { + try { + callback.setRetryCount(--tryCount); + dataNodeExchanger.request(new Request() { + @Override + public Object getRequestBody() { + return callback.getRequest(); + } + + @Override + public URL getRequestUrl() { + return new URL(callback.getConnection().getRemoteIP(), callback + .getConnection().getRemotePort()); + } + + @Override + public CallbackHandler getCallBackHandler() { + return new CallbackHandler() { + @Override + public void onCallback(Channel channel, Object message) { + callback.onResponse(message); + } + + @Override + public void onException(Channel channel, Throwable exception) { + callback.onException(exception); + } + }; + } + }); + } catch (Exception e) { + LOGGER.error("[GetSyncDataHandler] send sync data request failed", e); + } + } else { + LOGGER.info("[GetSyncDataHandler] sync data retry for three times"); + } + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/SyncDataCallback.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/SyncDataCallback.java new file mode 100644 index 000000000..a5785f314 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/SyncDataCallback.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver; + +import com.alipay.remoting.Connection; +import com.alipay.remoting.InvokeCallback; +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.change.DataChangeTypeEnum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import org.springframework.util.CollectionUtils; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.Executor; + +/** + * + * @author qian.lqlq + * @version $Id: SyncDataCallback.java, v 0.1 2018-03-08 14:22 qian.lqlq Exp $ + */ +public class SyncDataCallback implements InvokeCallback { + + private static final Logger LOGGER = LoggerFactory.getLogger(SyncDataCallback.class); + + private static final Executor EXECUTOR = ExecutorFactory.newFixedThreadPool(20, + SyncDataCallback.class.getSimpleName()); + + private static final int RETRY_COUNT = 3; + + private Connection connection; + + private SyncDataRequest request; + + private GetSyncDataHandler getSyncDataHandler; + + private int retryCount; + + private DataChangeEventCenter dataChangeEventCenter; + + /** + * constructor + * @param connection + * @param request + */ + public SyncDataCallback(GetSyncDataHandler getSyncDataHandler, Connection connection, + SyncDataRequest request, DataChangeEventCenter dataChangeEventCenter) { + this.getSyncDataHandler = getSyncDataHandler; + this.connection = connection; + this.request = request; + this.retryCount = RETRY_COUNT; + this.dataChangeEventCenter = dataChangeEventCenter; + } + + @Override + public void onResponse(Object obj) { + GenericResponse response = (GenericResponse) obj; + if (!response.isSuccess()) { + getSyncDataHandler.syncData(this); + } else { + SyncData syncData = response.getData(); + Collection datums = syncData.getDatums(); + DataSourceTypeEnum dataSourceTypeEnum = DataSourceTypeEnum.valueOf(request + .getDataSourceType()); + LOGGER + .info( + "[SyncDataCallback] get syncDatas,datums size={},wholeTag={},dataCenter={},dataInfoId={}", + datums.size(), syncData.getWholeDataTag(), syncData.getDataCenter(), + syncData.getDataInfoId()); + if (syncData.getWholeDataTag()) { + //handle all data, replace cache with these datum directly + for (Datum datum : datums) { + if (datum == null) { + datum = new Datum(); + datum.setDataInfoId(syncData.getDataInfoId()); + datum.setDataCenter(syncData.getDataCenter()); + } + processDatum(datum); + dataChangeEventCenter.sync(DataChangeTypeEnum.COVER, dataSourceTypeEnum, datum); + break; + } + } else { + //handle incremental data one by one + if (!CollectionUtils.isEmpty(datums)) { + for (Datum datum : datums) { + if (datum != null) { + processDatum(datum); + dataChangeEventCenter.sync(DataChangeTypeEnum.MERGE, + dataSourceTypeEnum, datum); + } + } + } else { + LOGGER.info("[SyncDataCallback] get no syncDatas"); + } + } + } + } + + private void processDatum(Datum datum) { + if (datum != null) { + Map publisherMap = datum.getPubMap(); + + if (publisherMap != null && !publisherMap.isEmpty()) { + publisherMap.forEach((registerId, publisher) -> Publisher.processPublisher(publisher)); + } + } + } + + @Override + public void onException(Throwable e) { + GenericResponse genericResponse = new GenericResponse(); + genericResponse.fillFailed(e.getMessage()); + onResponse(genericResponse); + } + + @Override + public Executor getExecutor() { + return EXECUTOR; + } + + /** + * Getter method for property connection. + * + * @return property value of connection + */ + public Connection getConnection() { + return connection; + } + + /** + * Getter method for property request. + * + * @return property value of request + */ + public SyncDataRequest getRequest() { + return request; + } + + /** + * Getter method for property retryCount. + * + * @return property value of retryCount + */ + public int getRetryCount() { + return retryCount; + } + + /** + * Setter method for property retryCount. + * + * @param retryCount value to be assigned to property retryCount + */ + public void setRetryCount(int retryCount) { + this.retryCount = retryCount; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/DataSyncServerConnectionHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/DataSyncServerConnectionHandler.java new file mode 100644 index 000000000..3519b398e --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/DataSyncServerConnectionHandler.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.handler; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DataSyncServerConnectionHandler extends AbstractServerHandler { + @Autowired + private DataServerConnectionFactory dataServerConnectionFactory; + + @Override + public ChannelHandler.HandlerType getType() { + return ChannelHandler.HandlerType.LISENTER; + } + + @Override + public void connected(Channel channel) throws RemotingException { + super.connected(channel); + dataServerConnectionFactory.register(((BoltChannel) channel).getConnection()); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + super.disconnected(channel); + dataServerConnectionFactory.remove(((BoltChannel) channel).getConnection()); + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } + + @Override + public void checkParam(Object request) throws RuntimeException { + + } + + @Override + public Object doHandle(Channel channel, Object request) { + return null; + } + + @Override + public Object buildFailedResponse(String msg) { + return null; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/FetchDataHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/FetchDataHandler.java new file mode 100644 index 000000000..76c9c0b33 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/FetchDataHandler.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.handler; + +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.GetDataRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import com.alipay.sofa.registry.util.ParaCheckUtil; + +import java.util.Map; + +/** + * processor to get specific data + * + * @author qian.lqlq + * @version $Id: GetDataProcessor.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class FetchDataHandler extends AbstractClientHandler { + + @Override + public void checkParam(GetDataRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getDataInfoId(), "GetDataRequest.dataInfoId"); + } + + @Override + public Object doHandle(Channel channel, GetDataRequest request) { + return new GenericResponse>().fillSucceed(DatumCache + .getDatumGroupByDataCenter(request.getDataCenter(), request.getDataInfoId())); + } + + @Override + public GenericResponse> buildFailedResponse(String msg) { + return new GenericResponse>().fillFailed(msg); + } + + @Override + public Class interest() { + return GetDataRequest.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyDataSyncHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyDataSyncHandler.java new file mode 100644 index 000000000..5938070bb --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyDataSyncHandler.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.handler; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.NotifyDataSyncRequest; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.remoting.dataserver.GetSyncDataHandler; +import com.alipay.sofa.registry.server.data.remoting.dataserver.SyncDataCallback; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import com.alipay.sofa.registry.server.data.util.ThreadPoolExecutorDataServer; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author qian.lqlq + * @version $Id: NotifyDataSyncProcessor.java, v 0.1 2018-03-06 20:04 qian.lqlq Exp $ + */ +public class NotifyDataSyncHandler extends AbstractClientHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotifyDataSyncHandler.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private GetSyncDataHandler getSyncDataHandler; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + private Executor executor = ExecutorFactory.newFixedThreadPool(10, + NotifyDataSyncHandler.class.getSimpleName()); + + private ThreadPoolExecutor notifyExecutor; + + @Override + public void checkParam(NotifyDataSyncRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getDataInfoId(), "request.dataInfoId"); + } + + @Override + public Object doHandle(Channel channel, NotifyDataSyncRequest request) { + final Connection connection = ((BoltChannel) channel).getConnection(); + executor.execute(() -> { + String dataInfoId = request.getDataInfoId(); + String dataCenter = request.getDataCenter(); + Datum datum = DatumCache.get(dataCenter, dataInfoId); + Long version = (datum == null) ? null : datum.getVersion(); + Long requestVersion = request.getVersion(); + if (version == null || requestVersion == 0L || version < requestVersion) { + LOGGER.info( + "[NotifyDataSyncProcessor] begin get sync data, currentVersion={},request={}", version, + request); + getSyncDataHandler + .syncData(new SyncDataCallback(getSyncDataHandler, connection, new SyncDataRequest(dataInfoId, + dataCenter, version, request.getDataSourceType()), dataChangeEventCenter)); + } else { + LOGGER.info( + "[NotifyDataSyncHandler] not need to sync data, version={}", version); + } + }); + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public Class interest() { + return NotifyDataSyncRequest.class; + } + + @Override + public Executor getExecutor() { + if (notifyExecutor == null) { + notifyExecutor = new ThreadPoolExecutorDataServer("NotifyDataSyncProcessorExecutor", + dataServerBootstrapConfig.getNotifyDataSyncExecutorMinPoolSize(), + dataServerBootstrapConfig.getNotifyDataSyncExecutorMaxPoolSize(), + dataServerBootstrapConfig.getNotifyDataSyncExecutorKeepAliveTime(), + TimeUnit.SECONDS, new ArrayBlockingQueue<>( + dataServerBootstrapConfig.getNotifyDataSyncExecutorQueueSize()), + new NamedThreadFactory("DataServer-NotifyDataSyncProcessor-executor", true)); + } + return notifyExecutor; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyFetchDatumHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyFetchDatumHandler.java new file mode 100644 index 000000000..cb11bf076 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyFetchDatumHandler.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.handler; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.GetDataRequest; +import com.alipay.sofa.registry.common.model.dataserver.NotifyFetchDatumRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.change.DataChangeTypeEnum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.util.TimeUtil; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Map; +import java.util.Map.Entry; + +/** + * + * @author qian.lqlq + * @version $Id: NotifyFetchDatumProcessor.java, v 0.1 2018-04-29 15:10 qian.lqlq Exp $ + */ +public class NotifyFetchDatumHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(NotifyFetchDatumHandler.class); + + @Autowired + private DataServerCache dataServerCache; + + @Autowired + private DataServerConnectionFactory dataServerConnectionFactory; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + @Autowired + private DataServerConfig dataServerConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Override + public void checkParam(NotifyFetchDatumRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getIp(), "ip"); + } + + @Override + public Object doHandle(Channel channel, NotifyFetchDatumRequest request) { + ParaCheckUtil.checkNotBlank(request.getIp(), "ip"); + Map> versionMap = request.getDataVersionMap(); + long version = request.getChangeVersion(); + String ip = request.getIp(); + if (version >= dataServerCache.getCurVersion()) { + if (versionMap.isEmpty()) { + LOGGER + .info( + "[NotifyFetchDatumHandler] get changeVersion map is empty,change version is {},current version is {},ip is {}", + version, dataServerCache.getCurVersion(), ip); + dataServerCache.synced(version, ip); + } else { + ExecutorFactory.getCommonExecutor().execute(() -> { + for (Entry> dataCenterEntry : versionMap.entrySet()) { + String dataCenter = dataCenterEntry.getKey(); + Map map = dataCenterEntry.getValue(); + for (Entry dataInfoEntry : map.entrySet()) { + String dataInfoId = dataInfoEntry.getKey(); + Datum datum = DatumCache.get(dataCenter, dataInfoId); + if (datum != null) { + long inVersion = dataInfoEntry.getValue(); + long currentVersion = datum.getVersion(); + if (currentVersion > inVersion) { + LOGGER.info( + + "[NotifyFetchDatumHandler] ignore fetch because changeVersion {} is less than {},dataInfoId={},dataCenter={}", + inVersion, currentVersion, dataInfoId, dataCenter); + continue; + } else if (datum.getVersion() == dataInfoEntry.getValue()) { + //if version same,maybe remove publisher all by LocalDataServerCleanHandler,so must fetch from other node + if (!datum.getPubMap().isEmpty()) { + continue; + } + } + } + fetchDatum(ip, dataCenter, dataInfoId); + } + } + dataServerCache.synced(version, ip); + }); + } + } else { + LOGGER.info( + "[NotifyFetchDatumHandler] ignore notify because changeVersion {} is less than {},ip is {}", + version, dataServerCache.getCurVersion(), ip); + } + return CommonResponse.buildSuccessResponse(); + } + + /** + * 拉取数据 + * + * @param targetIp + * @param dataCenter + * @param dataInfoId + */ + private void fetchDatum(String targetIp, String dataCenter, String dataInfoId) { + while ((dataServerCache.getDataServers(dataServerConfig.getLocalDataCenter()).keySet()) + .contains(targetIp)) { + Connection connection = dataServerConnectionFactory.getConnection(targetIp); + if (connection == null || !connection.isFine()) { + throw new RuntimeException(String.format("connection of %s is not available", + targetIp)); + } + try { + Server syncServer = boltExchange.getServer(dataServerBootstrapConfig + .getSyncDataPort()); + GenericResponse> response = (GenericResponse>) syncServer + .sendSync(syncServer.getChannel(connection.getRemoteAddress()), + new GetDataRequest(dataInfoId, dataCenter), + dataServerBootstrapConfig.getRpcTimeout()); + if (response.isSuccess()) { + Datum datum = response.getData().get(dataCenter); + if (datum != null) { + dataChangeEventCenter.sync(DataChangeTypeEnum.COVER, + DataSourceTypeEnum.BACKUP, datum); + LOGGER + .info( + "[NotifyFetchDatumHandler] fetch datum success,dataInfoId={},dataCenter={},targetIp={}", + datum.getDataInfoId(), datum.getDataCenter(), targetIp); + } + break; + } else { + throw new RuntimeException(response.getMessage()); + } + } catch (Exception e) { + LOGGER.error("[NotifyFetchDatumHandler] fetch datum error", e); + TimeUtil.randomDelay(500); + } + } + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return NotifyFetchDatumRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyOnlineHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyOnlineHandler.java new file mode 100644 index 000000000..dd7af7408 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/NotifyOnlineHandler.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.NotifyOnlineRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author qian.lqlq + * @version $Id: NotifyOnlineProcessor.java, v 0.1 2018-04-29 14:36 qian.lqlq Exp $ + */ +public class NotifyOnlineHandler extends AbstractServerHandler { + + @Autowired + private DataServerCache dataServerCache; + + @Override + public void checkParam(NotifyOnlineRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getIp(), "ip"); + } + + @Override + public Object doHandle(Channel channel, NotifyOnlineRequest request) { + long version = request.getVersion(); + if (version >= dataServerCache.getCurVersion()) { + dataServerCache.addNotWorkingServer(version, request.getIp()); + } + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return NotifyOnlineRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/SyncDataHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/SyncDataHandler.java new file mode 100644 index 000000000..68fd19e51 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/handler/SyncDataHandler.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.handler; + +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.datasync.SyncDataService; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SyncDataProcessor.java, v 0.1 2018-03-08 20:02 shangyu.wh Exp $ + */ +public class SyncDataHandler extends AbstractServerHandler { + + @Autowired + private SyncDataService syncDataService; + + @Override + public void checkParam(SyncDataRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getDataInfoId(), "request.dataInfoId"); + ParaCheckUtil.checkNotBlank(request.getDataCenter(), "request.dataCenter"); + ParaCheckUtil.checkNotBlank(String.valueOf(request.getVersion()), "request.currentVersion"); + } + + @Override + public Object doHandle(Channel channel, SyncDataRequest request) { + SyncData syncData = syncDataService.getSyncDataChange(request); + return new GenericResponse().fillSucceed(syncData); + } + + @Override + public GenericResponse buildFailedResponse(String msg) { + return new GenericResponse().fillFailed(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return SyncDataRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/AbstractTask.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/AbstractTask.java new file mode 100644 index 000000000..64f80fc16 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/AbstractTask.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.task; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author qian.lqlq + * @version $Id: AbstractTask.java, v 0.1 2018-03-07 21:24 qian.lqlq Exp $ + */ +public abstract class AbstractTask implements Runnable { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTask.class); + + /** + * get name of task + * + * @return + */ + public String getName() { + return this.getClass().getSimpleName(); + } + + @Override + public void run() { + try { + handle(); + } catch (Throwable e) { + LOGGER.error("[{}] task execute failed", getName(), e); + } + } + + /** + * biz handle + */ + public abstract void handle(); + + /** + * get delay of task + * + * @return + */ + public abstract int getDelay(); + + /** + * get initial delay of task + * + * @return + */ + public abstract int getInitialDelay(); + + /** + * get unit of delay time or initial delay time + * + * @return + */ + public abstract TimeUnit getTimeUnit(); + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ConnectionRefreshTask.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ConnectionRefreshTask.java new file mode 100644 index 000000000..6a19451ca --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ConnectionRefreshTask.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.task; + +import com.alipay.sofa.registry.server.data.cache.DataServerChangeItem; +import com.alipay.sofa.registry.server.data.event.DataServerChangeEvent; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author qian.lqlq + * @version $Id: ConnectionRefreshTask.java, v 0.1 2018-03-12 21:10 qian.lqlq Exp $ + */ +public class ConnectionRefreshTask extends AbstractTask { + + @Autowired + private IMetaServerService metaServerService; + + @Autowired + private EventCenter eventCenter; + + @Override + public void handle() { + DataServerChangeItem dataServerChangeItem = metaServerService.getDateServers(); + if (dataServerChangeItem != null) { + eventCenter.post(new DataServerChangeEvent(dataServerChangeItem)); + } + } + + @Override + public int getDelay() { + return 30; + } + + @Override + public int getInitialDelay() { + return 0; + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.SECONDS; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ReNewNodeTask.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ReNewNodeTask.java new file mode 100644 index 000000000..6fda74933 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/dataserver/task/ReNewNodeTask.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.dataserver.task; + +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ReNewNodeTask.java, v 0.1 2018-04-02 20:56 shangyu.wh Exp $ + */ +public class ReNewNodeTask extends AbstractTask { + + @Autowired + private IMetaServerService metaServerService; + + @Override + public void handle() { + metaServerService.reNewNodeTask(); + } + + @Override + public int getDelay() { + return 3; + } + + @Override + public int getInitialDelay() { + return 0; + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.SECONDS; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractClientHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractClientHandler.java new file mode 100644 index 000000000..8f48d5166 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractClientHandler.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +/** + * + * @author shangyu.wh + * @version $Id: ClientHandler.java, v 0.1 2017-11-28 18:06 shangyu.wh Exp $ + */ +public abstract class AbstractClientHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractClientHandler.class); + + @Override + public void connected(Channel channel) { + if (channel != null && channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node connected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) { + if (channel != null && !channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node disconnected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + protected abstract NodeType getConnectNodeType(); + + @Override + public void caught(Channel channel, T message, Throwable exception) { + + } + + @Override + public void received(Channel channel, T message) { + + } + + @Override + public Object reply(Channel channel, T request) { + try { + logRequest(request); + checkParam(request); + return doHandle(channel, request); + } catch (Exception e) { + LOGGER.error("[{}] handle request failed", getClassName(), e); + return buildFailedResponse(e.getMessage()); + } + } + + /** + * check params if valid + * + * @param request + * @throws RuntimeException + */ + public abstract void checkParam(T request) throws RuntimeException; + + /** + * execute + * + * @param request + * @return + */ + public abstract Object doHandle(Channel channel, T request); + + /** + * build failed response + * + * @param msg + * @return + */ + public abstract Object buildFailedResponse(String msg); + + /** + * print request + * + * @param request + */ + protected void logRequest(T request) { + log(request.toString()); + } + + /** + * print info log + * + * @param log + */ + protected void log(String log) { + LOGGER.info(new StringBuilder("[").append(getClassName()).append("] ").append(log) + .toString()); + } + + @Override + public Class interest() { + return null; + } + + /** + * get simple name of this class + * + * @return + */ + private String getClassName() { + return this.getClass().getSimpleName(); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractServerHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractServerHandler.java new file mode 100644 index 000000000..34630ed39 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/handler/AbstractServerHandler.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; + +/** + * + * @author shangyu.wh + * @version $Id: ServerHandler.java, v 0.1 2017-11-28 18:06 shangyu.wh Exp $ + */ +public abstract class AbstractServerHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractServerHandler.class); + + @Override + public void connected(Channel channel) throws RemotingException { + if (channel != null && channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node connected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + if (channel != null && !channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node disconnected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + protected NodeType getConnectNodeType() { + return NodeType.DATA; + } + + @Override + public void caught(Channel channel, T message, Throwable exception) { + + } + + @Override + public void received(Channel channel, T message) { + + } + + @Override + public Object reply(Channel channel, T request) { + try { + logRequest(channel, request); + checkParam(request); + + return doHandle(channel, request); + } catch (Exception e) { + LOGGER.error("[{}] handle request failed", getClassName(), e); + return buildFailedResponse(e.getMessage()); + } + } + + @Override + public Class interest() { + return null; + } + + /** + * check params if valid + * + * @param request + * @throws RuntimeException + */ + public abstract void checkParam(T request) throws RuntimeException; + + /** + * execute + * + * @param request + * @return + */ + public abstract Object doHandle(Channel channel, T request); + + /** + * build failed response + * + * @param msg + * @return + */ + public abstract Object buildFailedResponse(String msg); + + /** + * print request + * + * @param request + */ + protected void logRequest(Channel channel, T request) { + log(request.toString()); + if (channel != null) { + log(new StringBuilder("Remote:").append(channel.getRemoteAddress()).append(" Request:") + .append(request).toString()); + } else { + log(request.toString()); + } + } + + /** + * print info log + * + * @param log + */ + protected void log(String log) { + LOGGER.info(new StringBuilder("[").append(getClassName()).append("] ").append(log) + .toString()); + } + + /** + * get simple name of this class + * + * @return + */ + private String getClassName() { + return this.getClass().getSimpleName(); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/DefaultMetaServiceImpl.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/DefaultMetaServiceImpl.java new file mode 100644 index 000000000..dd9ecdc49 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/DefaultMetaServiceImpl.java @@ -0,0 +1,302 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.metaserver; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.GetNodesRequest; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.ReNewNodesRequest; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DataServerChangeItem; +import com.alipay.sofa.registry.server.data.node.DataServerNode; +import com.alipay.sofa.registry.server.data.remoting.MetaNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerNodeFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +/** + * + * @author qian.lqlq + * @version $Id: DefaultMetaServiceImpl.java, v 0.1 2018-03-07 20:41 qian.lqlq Exp $ + */ +public class DefaultMetaServiceImpl implements IMetaServerService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultMetaServiceImpl.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private MetaNodeExchanger metaNodeExchanger; + + @Autowired + private MetaServerConnectionFactory metaServerConnectionFactory; + + private RaftClient raftClient; + + private AtomicBoolean clientStart = new AtomicBoolean(false); + + @Override + public Map> getMetaServerMap() { + HashMap> map = new HashMap<>(); + Set set = dataServerBootstrapConfig.getMetaServerIpAddresses(); + + Map connectionMap = metaServerConnectionFactory + .getConnections(dataServerBootstrapConfig.getLocalDataCenter()); + Connection connection = null; + try { + if (connectionMap.isEmpty()) { + connection = ((BoltChannel) metaNodeExchanger.connect(new URL( + set.iterator().next(), dataServerBootstrapConfig.getMetaServerPort()))) + .getConnection(); + } else { + connection = connectionMap.values().iterator().next(); + } + + GetNodesRequest request = new GetNodesRequest(NodeType.META); + final Connection finalConnection = connection; + Object obj = metaNodeExchanger.request(new Request() { + @Override + public Object getRequestBody() { + return request; + } + + @Override + public URL getRequestUrl() { + return new URL(finalConnection.getRemoteIP(), finalConnection.getRemotePort()); + } + }).getResult(); + if (obj instanceof NodeChangeResult) { + NodeChangeResult result = (NodeChangeResult) obj; + + Map> metaNodesMap = result.getNodes(); + if (metaNodesMap != null && !metaNodesMap.isEmpty()) { + Map metaNodeMap = metaNodesMap.get(dataServerBootstrapConfig + .getLocalDataCenter()); + if (metaNodeMap != null && !metaNodeMap.isEmpty()) { + map.put(dataServerBootstrapConfig.getLocalDataCenter(), + metaNodeMap.keySet()); + } else { + LOGGER + .error( + "[DefaultMetaServiceImpl] refresh connections from metaServer {} has no result!", + connection.getRemoteIP()); + } + } + } + } catch (Exception e) { + String con = connection != null ? connection.getRemoteIP() : "null"; + LOGGER.error("[DefaultMetaServiceImpl] refresh connections from metaServer error : {}", + con, e); + LOGGER + .warn( + "[DefaultMetaServiceImpl] refresh connections from metaServer error,refresh leader : {}", + con); + } + return map; + } + + @Override + public DataServerNode getDataServer(String dataCenter, String dataInfoId) { + return DataServerNodeFactory.computeDataServerNode(dataCenter, dataInfoId); + } + + @Override + public List getDataServers(String dataCenter, String dataInfoId) { + return DataServerNodeFactory.computeDataServerNodes(dataCenter, dataInfoId, + dataServerBootstrapConfig.getStoreNodes()); + } + + @Override + public DataServerChangeItem getDateServers() { + Map connectionMap = metaServerConnectionFactory + .getConnections(dataServerBootstrapConfig.getLocalDataCenter()); + String leader = getLeader().getIp(); + if (connectionMap.containsKey(leader)) { + Connection connection = connectionMap.get(leader); + if (connection.isFine()) { + try { + GetNodesRequest request = new GetNodesRequest(NodeType.DATA); + Object obj = metaNodeExchanger.request(new Request() { + @Override + public Object getRequestBody() { + return request; + } + + @Override + public URL getRequestUrl() { + return new URL(connection.getRemoteIP(), connection.getRemotePort()); + } + }).getResult(); + if (obj instanceof NodeChangeResult) { + NodeChangeResult result = (NodeChangeResult) obj; + Map versionMap = result.getDataCenterListVersions(); + versionMap.put(result.getLocalDataCenter(), result.getVersion()); + return new DataServerChangeItem(result.getNodes(), versionMap); + } + } catch (Exception e) { + LOGGER.error( + "[ConnectionRefreshTask] refresh connections from metaServer error : {}", + leader, e); + String newip = refreshLeader().getIp(); + LOGGER + .warn( + "[ConnectionRefreshTask] refresh connections from metaServer error,refresh leader : {}", + newip); + + } + } + } + String newip = refreshLeader().getIp(); + LOGGER.warn( + "[ConnectionRefreshTask] refresh connections metaServer not fine,refresh leader : {}", + newip); + return null; + } + + @Override + public List getOtherDataCenters() { + Set all = new HashSet<>(DataServerNodeFactory.getAllDataCenters()); + all.remove(dataServerBootstrapConfig.getLocalDataCenter()); + return new ArrayList<>(all); + } + + @Override + public void reNewNodeTask() { + Map connectionMap = metaServerConnectionFactory + .getConnections(dataServerBootstrapConfig.getLocalDataCenter()); + for (Entry connectEntry : connectionMap.entrySet()) { + String ip = connectEntry.getKey(); + //just send to leader + if (ip.equals(getLeader().getIp())) { + Connection connection = connectEntry.getValue(); + if (connection.isFine()) { + try { + ReNewNodesRequest reNewNodesRequest = new ReNewNodesRequest<>( + new DataNode(new URL(DataServerConfig.IP), + dataServerBootstrapConfig.getLocalDataCenter())); + metaNodeExchanger.request(new Request() { + @Override + public Object getRequestBody() { + return reNewNodesRequest; + } + + @Override + public URL getRequestUrl() { + return new URL(connection.getRemoteIP(), connection.getRemotePort()); + } + }).getResult(); + } catch (Exception e) { + LOGGER.error("[ReNewNodeTask] reNew data node to metaServer error : {}", + ip, e); + String newip = refreshLeader().getIp(); + LOGGER + .warn( + "[ReNewNodeTask] reNew data node to metaServer error,leader refresh: {}", + newip); + } + } else { + String newip = refreshLeader().getIp(); + LOGGER + .warn( + "[ReNewNodeTask] reNew data node to metaServer not fine,leader refresh: {}", + newip); + } + } + } + } + + @Override + public void startRaftClient() { + try { + if (clientStart.compareAndSet(false, true)) { + String serverConf = getServerConfig(); + raftClient = new RaftClient(getGroup(), serverConf); + raftClient.start(); + } + } catch (Exception e) { + LOGGER.error("Start raft client error!", e); + throw new RuntimeException("Start raft client error!", e); + } + } + + private String getServerConfig() { + String ret = ""; + Set ips = dataServerBootstrapConfig.getMetaServerIpAddresses(); + if (ips != null && !ips.isEmpty()) { + ret = ips.stream().map(ip -> ip + ":" + ValueConstants.RAFT_SERVER_PORT) + .collect(Collectors.joining(",")); + } + if (ret.isEmpty()) { + throw new IllegalArgumentException("Init raft server config error!"); + } + return ret; + } + + private String getGroup() { + return ValueConstants.RAFT_SERVER_GROUP + "_" + + dataServerBootstrapConfig.getLocalDataCenter(); + } + + @Override + public PeerId getLeader() { + if (raftClient == null) { + startRaftClient(); + } + PeerId leader = raftClient.getLeader(); + if (leader == null) { + LOGGER.error("[DefaultMetaServiceImpl] register MetaServer get no leader!"); + throw new RuntimeException( + "[DefaultMetaServiceImpl] register MetaServer get no leader!"); + } + return leader; + } + + @Override + public PeerId refreshLeader() { + if (raftClient == null) { + startRaftClient(); + } + PeerId leader = raftClient.refreshLeader(); + if (leader == null) { + LOGGER.error("[RaftClientManager] refresh MetaServer get no leader!"); + throw new RuntimeException("[RaftClientManager] refresh MetaServer get no leader!"); + } + return leader; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/IMetaServerService.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/IMetaServerService.java new file mode 100644 index 000000000..e98f8e453 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/IMetaServerService.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.metaserver; + +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.registry.server.data.cache.DataServerChangeItem; +import com.alipay.sofa.registry.server.data.node.DataServerNode; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The interface Meta server service. + * @author qian.lqlq + * @version $Id : IMetaServerService.java, v 0.1 2018-03-07 20:41 qian.lqlq Exp $ + */ +public interface IMetaServerService { + + /** + * Gets meta server map. + * + * @return meta server map + */ + Map> getMetaServerMap(); + + /** + * Gets data server. + * + * @param dataCenter the data center + * @param dataInfoId the data info id + * @return data server + */ + DataServerNode getDataServer(String dataCenter, String dataInfoId); + + /** + * Gets data servers. + * + * @param dataCenter the data center + * @param dataInfoId the data info id + * @return the data servers + */ + List getDataServers(String dataCenter, String dataInfoId); + + /** + * Gets date servers. + * + * @return date servers + */ + DataServerChangeItem getDateServers(); + + /** + * Gets other data centers. + * + * @return other data centers + */ + List getOtherDataCenters(); + + /** + * scheduler update data server expireTime + */ + void reNewNodeTask(); + + /** + * start raft client for get leader send request + */ + void startRaftClient(); + + /** + * get raft leader + * @return + */ + PeerId getLeader(); + + /** + * renew a leader + * @return + */ + PeerId refreshLeader(); +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/MetaServerConnectionFactory.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/MetaServerConnectionFactory.java new file mode 100644 index 000000000..22fd4dc12 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/MetaServerConnectionFactory.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.metaserver; + +import com.alipay.remoting.Connection; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author qian.lqlq + * @version $Id: MetaServerConnectionFactory.java, v 0.1 2018年03月13日 15:44 qian.lqlq Exp $ + */ +public class MetaServerConnectionFactory { + + private final Map> MAP = new ConcurrentHashMap<>(); + + /** + * + * @param dataCenter + * @param ip + * @param connection + */ + public void register(String dataCenter, String ip, Connection connection) { + + Map connectionMap = MAP.get(dataCenter); + if (connectionMap == null) { + Map newConnectionMap = new ConcurrentHashMap<>(); + connectionMap = MAP.putIfAbsent(dataCenter, newConnectionMap); + if (connectionMap == null) { + connectionMap = newConnectionMap; + } + } + + connectionMap.put(ip, connection); + } + + /** + * + * @param dataCenter + * @param ip + * @return + */ + public Connection getConnection(String dataCenter, String ip) { + if (MAP.containsKey(dataCenter)) { + Map map = MAP.get(dataCenter); + if (map.containsKey(ip)) { + return map.get(ip); + } + } + return null; + } + + /** + * + * @param dataCenter + * @return + */ + public Map getConnections(String dataCenter) { + if (MAP.containsKey(dataCenter)) { + return MAP.get(dataCenter); + } + return new HashMap<>(); + } + + /** + * + * @param dataCenter + * @return + */ + public Set getIps(String dataCenter) { + if (MAP.containsKey(dataCenter)) { + Map map = MAP.get(dataCenter); + if (map != null) { + return map.keySet(); + } + } + return new HashSet<>(); + } + + /** + * + * @param dataCenter + */ + public void remove(String dataCenter) { + Map map = getConnections(dataCenter); + if (!map.isEmpty()) { + for (Connection connection : map.values()) { + if (connection.isFine()) { + connection.close(); + } + } + } + MAP.remove(dataCenter); + } + + /** + * + * @param dataCenter + * @param ip + */ + public void remove(String dataCenter, String ip) { + if (MAP.containsKey(dataCenter)) { + Map map = MAP.get(dataCenter); + if (map != null) { + map.remove(ip); + } + } + } + + /** + * + * @return + */ + public Set getAllDataCenters() { + return MAP.keySet(); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/ServerChangeHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/ServerChangeHandler.java new file mode 100644 index 000000000..0174f5776 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/ServerChangeHandler.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.metaserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.event.DataServerChangeEvent; +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.event.MetaServerChangeEvent; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: ServerChangeProcessor.java, v 0.1 2018-03-13 14:16 qian.lqlq Exp $ + */ +public class ServerChangeHandler extends AbstractClientHandler { + + @Autowired + private EventCenter eventCenter; + + @Autowired + private DataServerConfig dataServerConfig; + + @Override + public void checkParam(NodeChangeResult request) throws RuntimeException { + + } + + @Override + public Object doHandle(Channel channel, NodeChangeResult request) { + ExecutorFactory.getCommonExecutor().execute(() -> { + if (request.getNodeType() == NodeType.DATA) { + eventCenter.post(new DataServerChangeEvent(request.getNodes(), + request.getDataCenterListVersions())); + } else if (request.getNodeType() == NodeType.META) { + Map> metaNodesMap = request.getNodes(); + if (metaNodesMap != null && !metaNodesMap.isEmpty()) { + Map metaNodeMap = metaNodesMap.get(dataServerConfig.getLocalDataCenter()); + if (metaNodeMap != null && !metaNodeMap.isEmpty()) { + HashMap> map = new HashMap<>(); + map.put(dataServerConfig.getLocalDataCenter(), metaNodeMap.keySet()); + eventCenter.post(new MetaServerChangeEvent(map)); + } + } + } + }); + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public Class interest() { + return NodeChangeResult.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/StatusConfirmHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/StatusConfirmHandler.java new file mode 100644 index 000000000..e5bb46f86 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/handler/StatusConfirmHandler.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.metaserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.metaserver.StatusConfirmRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.cache.DataServerCache; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractClientHandler; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: StatusConfirmProcessor.java, v 0.1 2018-04-02 21:14 shangyu.wh Exp $ + */ +public class StatusConfirmHandler extends AbstractClientHandler { + + @Autowired + private DataServerCache dataServerCache; + + @Override + public void checkParam(StatusConfirmRequest request) throws RuntimeException { + + } + + @Override + public Object doHandle(Channel channel, StatusConfirmRequest request) { + dataServerCache.notifiedAll(); + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public Class interest() { + return StatusConfirmRequest.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/task/ConnectionRefreshMetaTask.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/task/ConnectionRefreshMetaTask.java new file mode 100644 index 000000000..a36967ba0 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/metaserver/task/ConnectionRefreshMetaTask.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.metaserver.task; + +import com.alipay.sofa.registry.server.data.event.EventCenter; +import com.alipay.sofa.registry.server.data.event.MetaServerChangeEvent; +import com.alipay.sofa.registry.server.data.remoting.dataserver.task.AbstractTask; +import com.alipay.sofa.registry.server.data.remoting.metaserver.IMetaServerService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ConnectionRefreshMetaTask.java, v 0.1 2018-06-29 18:16 shangyu.wh Exp $ + */ +public class ConnectionRefreshMetaTask extends AbstractTask { + + @Autowired + private IMetaServerService metaServerService; + + @Autowired + private EventCenter eventCenter; + + @Override + public void handle() { + eventCenter.post(new MetaServerChangeEvent(metaServerService.getMetaServerMap())); + } + + @Override + public int getDelay() { + return 10; + } + + @Override + public int getInitialDelay() { + return 0; + } + + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.SECONDS; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/SessionServerConnectionFactory.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/SessionServerConnectionFactory.java new file mode 100644 index 000000000..e8072e5ca --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/SessionServerConnectionFactory.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect.DisconnectEventHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect.SessionServerDisconnectEvent; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * the factory to hold sesseionserver connections + * + * @author qian.lqlq + * @version $Id: SessionServerConnectionFactory.java, v 0.1 2017-12-06 15:48 qian.lqlq Exp $ + */ +public class SessionServerConnectionFactory { + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionServerConnectionFactory.class); + + private static final int DELAY = 30 * 1000; + + /** + * collection of connections + * key : processId + * value : connection + */ + private final Map MAP = new ConcurrentHashMap<>(); + + /** + * key : sessionserver host + * value: sesseionserver processId + */ + private final Map PROCESSID_MAP = new ConcurrentHashMap<>(); + + /** + * key : sessionserver processId + * value: ip:port of clients + */ + private final Map> PROCESSID_CLIENT_MAP = new ConcurrentHashMap<>(); + + @Autowired + private DisconnectEventHandler disconnectEventHandler; + + /** + * register connection + * + * @param processId + * @param clientHosts + * @param connection + */ + public void register(String processId, Set clientHosts, Connection connection) { + String serverHost = NetUtil.toAddressString(connection.getRemoteAddress()); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("session({}, processId={}) registered", serverHost, processId); + } + MAP.put(processId, new Pair(serverHost, connection)); + Set ret = PROCESSID_CLIENT_MAP.getOrDefault(processId, null); + if (ret == null) { + PROCESSID_CLIENT_MAP.putIfAbsent(processId, new HashSet<>()); + } + PROCESSID_CLIENT_MAP.get(processId).addAll(clientHosts); + PROCESSID_MAP.put(serverHost, processId); + } + + /** + * + * @param processId + * @param clientAddress + */ + public void registerClient(String processId, String clientAddress) { + Set ret = PROCESSID_CLIENT_MAP.getOrDefault(processId, null); + if (ret == null) { + PROCESSID_CLIENT_MAP.putIfAbsent(processId, new HashSet<>()); + } + PROCESSID_CLIENT_MAP.get(processId).add(clientAddress); + } + + /** + * remove connection by specific host + */ + public void removeProcess(String sessionServerHost) { + String processId = PROCESSID_MAP.remove(sessionServerHost); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("session({}, processId={}) unregistered", sessionServerHost, processId); + } + if (processId != null) { + disconnectEventHandler.receive(new SessionServerDisconnectEvent(processId, + sessionServerHost, DELAY)); + } + } + + /** + * + * @param processId + */ + public Set removeClients(String processId) { + return PROCESSID_CLIENT_MAP.remove(processId); + } + + /** + * + * @param processId + * @return + */ + public boolean removeProcessIfMatch(String processId, String sessionServerHost) { + return MAP.remove(processId, new Pair(sessionServerHost, null)); + } + + /** + * get all connections + * + * @return + */ + public List getConnections() { + return MAP.size() <= 0 ? + Collections.EMPTY_LIST : + MAP.values().stream().map(Pair::getConnection).collect(Collectors.toList()); + } + + /** + * convenient class to store sessionServerHost and connection + */ + private static class Pair { + private String sessionServerHost; + private Connection connection; + + private Pair(String sessionServerHost, Connection connection) { + this.sessionServerHost = sessionServerHost; + this.connection = connection; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Pair pair = (Pair) o; + + return sessionServerHost.equals(pair.sessionServerHost); + } + + @Override + public int hashCode() { + return sessionServerHost.hashCode(); + } + + /** + * Getter method for property connection. + * + * @return property value of connection + */ + private Connection getConnection() { + return connection; + } + + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/ClientDisconnectEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/ClientDisconnectEvent.java new file mode 100644 index 000000000..3659db591 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/ClientDisconnectEvent.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect; + +/** + * + * @author qian.lqlq + * @version $Id: ClientDisconnectEvent.java, v 0.1 2018-04-14 18:22 qian.lqlq Exp $ + */ +public class ClientDisconnectEvent extends DisconnectEvent { + + private String host; + + /** + * constructor + * @param host + * @param registerTimestamp + * @param timeoutMs + */ + public ClientDisconnectEvent(String host, long registerTimestamp, int timeoutMs) { + this.host = host; + setRegisterTimestamp(registerTimestamp); + setGmtOccur(System.currentTimeMillis()); + setTimeoutMs(timeoutMs); + setType(DisconnectTypeEnum.CLIENT); + } + + /** + * Getter method for property host. + * + * @return property value of host + */ + public String getHost() { + return host; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEvent.java new file mode 100644 index 000000000..557ebee68 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEvent.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * + * @author qian.lqlq + * @version $Id: DisconnectEvent.java, v 0.1 2018-04-14 18:22 qian.lqlq Exp $ + */ +public class DisconnectEvent implements Delayed { + + private int timeoutMs; + + private long gmtOccur; + + private long registerTimestamp; + + private DisconnectTypeEnum type; + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(getGmtOccur() + getTimeoutMs() - System.currentTimeMillis(), + TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(Delayed o) { + if (o == this) { + return 0; + } + if (o instanceof DisconnectEvent) { + DisconnectEvent other = (DisconnectEvent) o; + if (this.gmtOccur < other.gmtOccur) { + return -1; + } else if (this.gmtOccur > other.gmtOccur) { + return 1; + } else { + return 0; + } + } + return -1; + } + + /** + * Getter method for property timeoutMs. + * + * @return property value of timeoutMs + */ + public int getTimeoutMs() { + return timeoutMs; + } + + /** + * Setter method for property timeoutMs. + * + * @param timeoutMs value to be assigned to property timeoutMs + */ + public void setTimeoutMs(int timeoutMs) { + this.timeoutMs = timeoutMs; + } + + /** + * Getter method for property gmtOccur. + * + * @return property value of gmtOccur + */ + public long getGmtOccur() { + return gmtOccur; + } + + /** + * Setter method for property gmtOccur. + * + * @param gmtOccur value to be assigned to property gmtOccur + */ + public void setGmtOccur(long gmtOccur) { + this.gmtOccur = gmtOccur; + } + + /** + * Getter method for property registerTimestamp. + * + * @return property value of registerTimestamp + */ + public long getRegisterTimestamp() { + return registerTimestamp; + } + + /** + * Setter method for property registerTimestamp. + * + * @param registerTimestamp value to be assigned to property registerTimestamp + */ + public void setRegisterTimestamp(long registerTimestamp) { + this.registerTimestamp = registerTimestamp; + } + + /** + * Getter method for property type. + * + * @return property value of type + */ + public DisconnectTypeEnum getType() { + return type; + } + + /** + * Setter method for property type. + * + * @param type value to be assigned to property type + */ + public void setType(DisconnectTypeEnum type) { + this.type = type; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEventHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEventHandler.java new file mode 100644 index 000000000..f262b420f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectEventHandler.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.change.event.ClientChangeEvent; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.executor.ExecutorFactory; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Set; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Executor; + +/** + * @author qian.lqlq + * @version $Id: ClientDisconnectEventHandler.java, v 0.1 2017-12-07 15:32 qian.lqlq Exp $ + */ +public class DisconnectEventHandler implements InitializingBean { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DisconnectEventHandler.class); + + /** + * a DelayQueue that contains client disconnect events + */ + private final DelayQueue EVENT_QUEUE = new DelayQueue<>(); + + @Autowired + private SessionServerConnectionFactory sessionServerConnectionFactory; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + @Autowired + private DataServerConfig dataServerConfig; + + /** + * receive disconnect event of client + * + * @param event + */ + public void receive(DisconnectEvent event) { + if (event.getType() == DisconnectTypeEnum.SESSION_SERVER) { + SessionServerDisconnectEvent sessionServerDisconnectEvent = (SessionServerDisconnectEvent) event; + LOGGER.info("receive session off event: sessionServerHost={}, processId={}", + sessionServerDisconnectEvent.getSessionServerHost(), + sessionServerDisconnectEvent.getProcessId()); + } + EVENT_QUEUE.add(event); + } + + @Override + public void afterPropertiesSet() { + LOGGER.info("begin start DisconnectEventHandler"); + Executor executor = ExecutorFactory + .newSingleThreadExecutor(DisconnectEventHandler.class.getSimpleName()); + executor.execute(() -> { + while (true) { + try { + DisconnectEvent disconnectEvent = EVENT_QUEUE.take(); + if (disconnectEvent.getType() == DisconnectTypeEnum.SESSION_SERVER) { + SessionServerDisconnectEvent event = (SessionServerDisconnectEvent) disconnectEvent; + String processId = event.getProcessId(); + //check processId confirm remove,and not be registered again when delay time + String sessionServerHost = event.getSessionServerHost(); + if (sessionServerConnectionFactory + .removeProcessIfMatch(processId, sessionServerHost)) { + Set clientHosts = sessionServerConnectionFactory + .removeClients(processId); + + LOGGER.info("session off is triggered: sessionServerHost={}, clientHost={}, processId={}", + sessionServerHost, + clientHosts, processId); + + if (clientHosts != null && !clientHosts.isEmpty()) { + for (String host : clientHosts) { + unPub(host, event.getRegisterTimestamp()); + } + } + } else { + LOGGER.info("session off is canceled: sessionServerHost={}, processId={}", + sessionServerHost, processId); + } + } else { + ClientDisconnectEvent event = (ClientDisconnectEvent) disconnectEvent; + unPub(event.getHost(), event.getRegisterTimestamp()); + } + } catch (Throwable e) { + LOGGER.error("handle client disconnect event failed", e); + } + } + }); + LOGGER.info("start DisconnectEventHandler success"); + } + + /** + * + * @param host + * @param registerTimestamp + */ + private void unPub(String host, long registerTimestamp) { + dataChangeEventCenter.onChange(new ClientChangeEvent(host, dataServerConfig + .getLocalDataCenter(), registerTimestamp)); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectTypeEnum.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectTypeEnum.java new file mode 100644 index 000000000..314ab870f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/DisconnectTypeEnum.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect; + +/** + * + * @author qian.lqlq + * @version $Id: DisconnectTypeEnum.java, v 0.1 2018-04-15 14:58 qian.lqlq Exp $ + */ +public enum DisconnectTypeEnum { + /** */ + CLIENT, + /** */ + SESSION_SERVER +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/SessionServerDisconnectEvent.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/SessionServerDisconnectEvent.java new file mode 100644 index 000000000..be8bbaf6e --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/disconnect/SessionServerDisconnectEvent.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect; + +/** + * + * @author qian.lqlq + * @version $Id: SessionServerDisconnectEvent.java, v 0.1 2018-04-14 18:22 qian.lqlq Exp $ + */ +public class SessionServerDisconnectEvent extends DisconnectEvent { + + private String processId; + + private String sessionServerHost; + + /** + * constructor + * @param processId + * @param timeoutMs + */ + public SessionServerDisconnectEvent(String processId, String sessionServerHost, int timeoutMs) { + this.processId = processId; + this.sessionServerHost = sessionServerHost; + setGmtOccur(System.currentTimeMillis()); + setRegisterTimestamp(getGmtOccur()); + setTimeoutMs(timeoutMs); + setType(DisconnectTypeEnum.SESSION_SERVER); + } + + /** + * Getter method for property processId. + * + * @return property value of processId + */ + public String getProcessId() { + return processId; + } + + /** + * Getter method for property sessionServerHost. + * + * @return property value of sessionServerHost + */ + public String getSessionServerHost() { + return sessionServerHost; + } + +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardService.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardService.java new file mode 100644 index 000000000..43931d46c --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardService.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.forward; + +import com.alipay.remoting.exception.RemotingException; + +/** + * The interface Forward service. + * @author zhuoyu.sjw + * @version $Id : ForwardService.java, v 0.1 2018-06-16 17:41 zhuoyu.sjw Exp $$ + */ +public interface ForwardService { + + /** + * Need forward boolean. + * + * @param dataInfoId the data info id + * @return the boolean + */ + boolean needForward(String dataInfoId); + + /** + * Forward request object. + * + * @param dataInfoId the data info id + * @param request the request + * @return the object + * @throws RemotingException the remoting exception + * @throws InterruptedException the interrupted exception + */ + Object forwardRequest(String dataInfoId, Object request) throws RemotingException, + InterruptedException; +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardServiceImpl.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardServiceImpl.java new file mode 100644 index 000000000..7228bc03d --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/forward/ForwardServiceImpl.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.forward; + +import com.alipay.remoting.exception.RemotingException; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.node.DataNodeStatus; +import com.alipay.sofa.registry.server.data.node.DataServerNode; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerNodeFactory; +import com.alipay.sofa.registry.server.data.util.LocalServerStatusEnum; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +/** + * The type Forward service. + * @author zhuoyu.sjw + * @version $Id : ForwardServiceImpl.java, v 0.1 2018-06-16 17:44 zhuoyu.sjw Exp $$ + */ +public class ForwardServiceImpl implements ForwardService { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory.getLogger(ForwardServiceImpl.class); + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private DataNodeStatus dataNodeStatus; + + @Autowired + private DataNodeExchanger dataNodeExchanger; + + /** + * @see ForwardService#needForward(String) + */ + @Override + public boolean needForward(String dataInfoId) { + return dataNodeStatus.getStatus() != LocalServerStatusEnum.WORKING; + } + + /** + * @see ForwardService#forwardRequest(String, Object) + */ + @Override + public Object forwardRequest(String dataInfoId, Object request) throws RemotingException { + try { + // 1. get store nodes + List dataServerNodes = DataServerNodeFactory.computeDataServerNodes( + dataServerBootstrapConfig.getLocalDataCenter(), dataInfoId, + dataServerBootstrapConfig.getStoreNodes()); + + // 2. find next node + if (null == dataServerNodes || dataServerNodes.size() <= 0) { + throw new RuntimeException("No available server to forward"); + } + + boolean next = false; + String localIp = NetUtil.getLocalAddress().getHostAddress(); + DataServerNode nextNode = null; + for (DataServerNode dataServerNode : dataServerNodes) { + if (next) { + nextNode = dataServerNode; + break; + } + if (null != localIp && localIp.equals(dataServerNode.getIp())) { + next = true; + } + } + + if (null == nextNode || null == nextNode.getConnection()) { + throw new RuntimeException("No available connection to forward"); + } + + LOGGER.info("[forward] target: {}, dataInfoId: {}, request: {}, allNodes: {}", + nextNode.getIp(), dataInfoId, request, dataServerNodes); + + // 3. invoke and return result + final DataServerNode finalNextNode = nextNode; + return dataNodeExchanger.request(new Request() { + @Override + public Object getRequestBody() { + return request; + } + + @Override + public URL getRequestUrl() { + return new URL(finalNextNode.getConnection().getRemoteIP(), finalNextNode + .getConnection().getRemotePort()); + } + }).getResult(); + } catch (Exception e) { + throw new RemotingException("ForwardServiceImpl forwardRequest error", e); + } + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/ClientOffHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/ClientOffHandler.java new file mode 100644 index 000000000..2ebd53d7f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/ClientOffHandler.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.ClientOffRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect.ClientDisconnectEvent; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.disconnect.DisconnectEventHandler; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +/** + * processor to remove data of specific clients immediately + * + * @author qian.lqlq + * @version $Id: ClientOffProcessor.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class ClientOffHandler extends AbstractServerHandler { + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + @Autowired + private DisconnectEventHandler disconnectEventHandler; + + @Override + public void checkParam(ClientOffRequest request) throws RuntimeException { + ParaCheckUtil.checkNotEmpty(request.getHosts(), "ClientOffRequest.hosts"); + } + + @Override + public Object doHandle(Channel channel, ClientOffRequest request) { + List hosts = request.getHosts(); + for (String host : hosts) { + disconnectEventHandler.receive(new ClientDisconnectEvent(host, request.getGmtOccur(), + dataServerBootstrapConfig.getClientOffDelayMs() * 10)); + } + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return ClientOffRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/DataServerConnectionHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/DataServerConnectionHandler.java new file mode 100644 index 000000000..6f41e1f95 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/DataServerConnectionHandler.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DataServerConnectionHandler extends AbstractServerHandler { + @Autowired + private SessionServerConnectionFactory sessionServerConnectionFactory; + + @Override + public ChannelHandler.HandlerType getType() { + return ChannelHandler.HandlerType.LISENTER; + } + + @Override + public void connected(Channel channel) throws RemotingException { + super.connected(channel); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + super.disconnected(channel); + sessionServerConnectionFactory.removeProcess(NetUtil.toAddressString(channel + .getRemoteAddress())); + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } + + @Override + public void checkParam(Object request) throws RuntimeException { + } + + @Override + public Object doHandle(Channel channel, Object request) { + return null; + } + + @Override + public Object buildFailedResponse(String msg) { + return null; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataHandler.java new file mode 100644 index 000000000..76682983e --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataHandler.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.GetDataRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.forward.ForwardService; +import com.alipay.sofa.registry.server.data.util.ThreadPoolExecutorDataServer; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * processor to get specific data + * + * @author qian.lqlq + * @version $Id: GetDataProcessor.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class GetDataHandler extends AbstractServerHandler { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory.getLogger(GetDataHandler.class); + @Autowired + private ForwardService forwardService; + + @Autowired + private DataServerConfig dataServerBootstrapConfig; + + private ThreadPoolExecutor getDataProcessorExecutor; + + @Override + public void checkParam(GetDataRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getDataInfoId(), "GetDataRequest.dataInfoId"); + } + + @Override + public Object doHandle(Channel channel, GetDataRequest request) { + String dataInfoId = request.getDataInfoId(); + if (forwardService.needForward(dataInfoId)) { + try { + LOGGER.warn("[forward] Get data request forward, request: {}", request); + return forwardService.forwardRequest(dataInfoId, request); + } catch (Exception e) { + LOGGER.error("[forward] getData request error, request: {}", request, e); + GenericResponse response = new GenericResponse(); + response.setSuccess(false); + response.setMessage(e.getMessage()); + return response; + } + } + + return new GenericResponse>().fillSucceed(DatumCache + .getDatumGroupByDataCenter(request.getDataCenter(), dataInfoId)); + } + + @Override + public GenericResponse> buildFailedResponse(String msg) { + return new GenericResponse>().fillFailed(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return GetDataRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } + + @Override + public Executor getExecutor() { + if (getDataProcessorExecutor == null) { + getDataProcessorExecutor = new ThreadPoolExecutorDataServer("GetDataProcessorExecutor", + dataServerBootstrapConfig.getGetDataExecutorMinPoolSize(), + dataServerBootstrapConfig.getGetDataExecutorMaxPoolSize(), + dataServerBootstrapConfig.getGetDataExecutorKeepAliveTime(), TimeUnit.SECONDS, + new ArrayBlockingQueue<>(dataServerBootstrapConfig.getGetDataExecutorQueueSize()), + new NamedThreadFactory("DataServer-GetDataProcessor-executor", true)); + } + return getDataProcessorExecutor; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataVersionsHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataVersionsHandler.java new file mode 100644 index 000000000..e2fa8e4e4 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/GetDataVersionsHandler.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.GetDataVersionRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.cache.DatumCache; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.util.ParaCheckUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * processor to get versions of specific dataInfoIds + * + * @author qian.lqlq + * @version $Id: GetDataVersionsProcessor.java, v 0.1 2017-12-06 19:56 qian.lqlq Exp $ + */ +public class GetDataVersionsHandler extends AbstractServerHandler { + @Override + protected void logRequest(Channel channel, GetDataVersionRequest request) { + } + + @Override + public void checkParam(GetDataVersionRequest request) throws RuntimeException { + ParaCheckUtil.checkNotEmpty(request.getDataInfoIds(), "GetDataVersionRequest.dataInfoIds"); + } + + @Override + public Object doHandle(Channel channel, GetDataVersionRequest request) { + Map> map = new HashMap<>(); + List dataInfoIds = request.getDataInfoIds(); + for (String dataInfoId : dataInfoIds) { + Map datumMap = DatumCache.get(dataInfoId); + Set> entrySet = datumMap.entrySet(); + for (Entry entry : entrySet) { + String dataCenter = entry.getKey(); + Datum datum = entry.getValue(); + if (datum != null) { + if (!map.containsKey(dataCenter)) { + map.put(dataCenter, new HashMap<>()); + } + map.get(dataCenter).put(dataInfoId, datum.getVersion()); + } + } + } + return new GenericResponse>>().fillSucceed(map); + } + + @Override + public GenericResponse>> buildFailedResponse(String msg) { + return new GenericResponse>>().fillFailed(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return GetDataVersionRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/PublishDataHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/PublishDataHandler.java new file mode 100644 index 000000000..94caad81e --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/PublishDataHandler.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.PublishType; +import com.alipay.sofa.registry.common.model.dataserver.PublishDataRequest; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.forward.ForwardService; +import com.alipay.sofa.registry.server.data.util.ThreadPoolExecutorDataServer; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * processor to publish data + * + * @author qian.lqlq + * @version $Id: ForwardPublishDataProcessor.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class PublishDataHandler extends AbstractServerHandler { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory + .getLogger(PublishDataHandler.class); + + @Autowired + private ForwardService forwardService; + + @Autowired + private SessionServerConnectionFactory sessionServerConnectionFactory; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + @Autowired + private DataServerConfig dataServerConfig; + + private ThreadPoolExecutor publishExecutor; + + public PublishDataHandler(DataServerConfig dataServerConfig) { + + publishExecutor = new ThreadPoolExecutorDataServer("PublishProcessorExecutor", + dataServerConfig.getPublishExecutorMinPoolSize(), + dataServerConfig.getPublishExecutorMaxPoolSize(), + dataServerConfig.getNotifyDataSyncExecutorKeepAliveTime(), TimeUnit.SECONDS, + new ArrayBlockingQueue<>(dataServerConfig.getPublishExecutorQueueSize()), + new NamedThreadFactory("DataServer-PublishProcessorExecutor-executor", true)); + } + + @Override + public void checkParam(PublishDataRequest request) throws RuntimeException { + Publisher publisher = request.getPublisher(); + ParaCheckUtil.checkNotNull(publisher, "PublishDataRequest.publisher"); + ParaCheckUtil.checkNotBlank(publisher.getDataId(), "publisher.dataId"); + ParaCheckUtil.checkNotBlank(publisher.getInstanceId(), "publisher.instanceId"); + ParaCheckUtil.checkNotBlank(publisher.getGroup(), "publisher.group"); + ParaCheckUtil.checkNotBlank(publisher.getDataInfoId(), "publisher.dataInfoId"); + ParaCheckUtil.checkNotNull(publisher.getVersion(), "publisher.version"); + ParaCheckUtil.checkNotBlank(publisher.getRegisterId(), "publisher.registerId"); + + if (publisher.getPublishType() != PublishType.TEMPORARY) { + ParaCheckUtil.checkNotNull(publisher.getSourceAddress(), "publisher.sourceAddress"); + } + } + + @Override + public Object doHandle(Channel channel, PublishDataRequest request) { + Publisher publisher = Publisher.processPublisher(request.getPublisher()); + if (forwardService.needForward(publisher.getDataInfoId())) { + LOGGER.warn("[forward] Publish request refused, request: {}", request); + CommonResponse response = new CommonResponse(); + response.setSuccess(false); + response.setMessage("Request refused, Server status is not working"); + return response; + } + + dataChangeEventCenter.onChange(publisher, dataServerConfig.getLocalDataCenter()); + if (publisher.getPublishType() != PublishType.TEMPORARY) { + sessionServerConnectionFactory.registerClient(request.getSessionServerProcessId(), + publisher.getSourceAddress().getAddressString()); + } + + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return new CommonResponse(false, msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return PublishDataRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } + + @Override + public Executor getExecutor() { + return publishExecutor; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/SessionServerRegisterHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/SessionServerRegisterHandler.java new file mode 100644 index 000000000..a136fa06f --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/SessionServerRegisterHandler.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.SessionServerRegisterRequest; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.SessionServerConnectionFactory; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author qian.lqlq + * @version $Id: SessionServerRegisterProcessor.java, v 0.1 2018年04月14日 17:32 qian.lqlq Exp $ + */ +public class SessionServerRegisterHandler extends + AbstractServerHandler { + + @Autowired + private SessionServerConnectionFactory sessionServerConnectionFactory; + + @Override + public void checkParam(SessionServerRegisterRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getProcessId(), "processId"); + } + + @Override + public Object doHandle(Channel channel, SessionServerRegisterRequest request) { + Set clientHosts = request.getClientHosts(); + if (clientHosts == null) { + clientHosts = new HashSet<>(); + } + sessionServerConnectionFactory.register(request.getProcessId(), clientHosts, + ((BoltChannel) channel).getConnection()); + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return SessionServerRegisterRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/UnPublishDataHandler.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/UnPublishDataHandler.java new file mode 100644 index 000000000..2a297ed6b --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/remoting/sessionserver/handler/UnPublishDataHandler.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.remoting.sessionserver.handler; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.UnPublishDataRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.UnPublisher; +import com.alipay.sofa.registry.server.data.change.event.DataChangeEventCenter; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.data.remoting.sessionserver.forward.ForwardService; +import com.alipay.sofa.registry.util.ParaCheckUtil; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * processor to unPublish specific data + * + * @author qian.lqlq + * @version $Id: UnPublishDataProcessor.java, v 0.1 2017-12-01 15:48 qian.lqlq Exp $ + */ +public class UnPublishDataHandler extends AbstractServerHandler { + + /** LOGGER */ + private static final Logger LOGGER = LoggerFactory.getLogger(UnPublishDataHandler.class); + + @Autowired + private ForwardService forwardService; + + @Autowired + private DataChangeEventCenter dataChangeEventCenter; + + @Autowired + private DataServerConfig dataServerConfig; + + @Override + public void checkParam(UnPublishDataRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getDataInfoId(), "UnPublishDataRequest.dataInfoId"); + ParaCheckUtil.checkNotBlank(request.getRegisterId(), "UnPublishDataRequest.registerId"); + } + + @Override + public Object doHandle(Channel channel, UnPublishDataRequest request) { + if (forwardService.needForward(request.getDataInfoId())) { + LOGGER.warn("[forward] UnPublish request refused, request: {}", request); + CommonResponse response = new CommonResponse(); + response.setSuccess(false); + response.setMessage("Request refused, Server status is not working"); + return response; + } + + dataChangeEventCenter.onChange( + new UnPublisher(request.getDataInfoId(), request.getRegisterId(), request + .getRegisterTimestamp()), dataServerConfig.getLocalDataCenter()); + return CommonResponse.buildSuccessResponse(); + } + + @Override + public CommonResponse buildFailedResponse(String msg) { + return CommonResponse.buildFailedResponse(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return UnPublishDataRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/DataDigestResource.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/DataDigestResource.java new file mode 100644 index 000000000..786bf7af0 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/DataDigestResource.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.resource; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.server.data.cache.DatumCache; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +/** + * + * @author shangyu.wh + * @version $Id: DataDigestResource.java, v 0.1 2018-10-19 16:16 shangyu.wh Exp $ + */ +@Path("digest") +public class DataDigestResource { + + @GET + @Path("datum/query") + @Produces(MediaType.APPLICATION_JSON) + public Map getDatumByDataInfoId(@QueryParam("dataId") String dataId, + @QueryParam("group") String group, + @QueryParam("instanceId") String instanceId, + @QueryParam("dataCenter") String dataCenter) { + Map retList = new HashMap<>(); + + if (!isBlank(dataId) && !isBlank(instanceId) && !isBlank(group)) { + + String dataInfoId = DataInfo.toDataInfoId(dataId, instanceId, group); + if (isBlank(dataCenter)) { + retList = DatumCache.get(dataInfoId); + } else { + retList.put(dataCenter, DatumCache.get(dataCenter, dataInfoId)); + } + + } + return retList; + } + + @POST + @Path("connect/query") + @Produces(MediaType.APPLICATION_JSON) + public Map> getPublishersByConnectId(Map map) { + Map> ret = new HashMap<>(); + if (map != null && !map.isEmpty()) { + map.forEach((ip, port) -> { + String connectId = NetUtil.genHost(ip, Integer.valueOf(port)); + if (!connectId.isEmpty()) { + Map publisherMap = DatumCache.getByHost(connectId); + if (publisherMap != null && !publisherMap.isEmpty()) { + ret.put(connectId, publisherMap); + } + } + }); + } + return ret; + } + + @GET + @Path("datum/count") + @Produces(MediaType.APPLICATION_JSON) + public String getDatumCount() { + StringBuilder sb = new StringBuilder("CacheDigest"); + try { + + Map> allMap = DatumCache.getAll(); + if (!allMap.isEmpty()) { + for (Entry> dataCenterEntry : allMap.entrySet()) { + String dataCenter = dataCenterEntry.getKey(); + Map datumMap = dataCenterEntry.getValue(); + sb.append(String.format(" [Datum] size of datum in %s is %s", + dataCenter, datumMap.size())); + int pubCount = datumMap.values().stream().map(Datum::getPubMap) + .filter(map -> map != null && !map.isEmpty()).mapToInt(Map::size).sum(); + sb.append(String.format(",[Publisher] size of publisher in %s is %s", + dataCenter, pubCount)); + } + } else { + sb.append(" datum cache is empty"); + } + + } catch (Throwable t) { + sb.append(" cache digest error!"); + } + + return sb.toString(); + } + + private boolean isBlank(String dataInfoId) { + return dataInfoId == null || dataInfoId.isEmpty(); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/HealthResource.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/HealthResource.java new file mode 100644 index 000000000..c61a8bcf8 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/resource/HealthResource.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.resource; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerBootstrap; +import com.alipay.sofa.registry.server.data.node.DataNodeStatus; +import com.alipay.sofa.registry.server.data.util.LocalServerStatusEnum; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author shangyu.wh + * @version $Id: HealthResource.java, v 0.1 2018-10-19 14:56 shangyu.wh Exp $ + */ +@Path("health") +public class HealthResource { + + @Autowired + private DataServerBootstrap dataServerBootstrap; + + @Autowired + private DataNodeStatus dataNodeStatus; + + @GET + @Path("check") + @Produces(MediaType.APPLICATION_JSON) + public CommonResponse checkHealth() { + + CommonResponse response; + + StringBuilder sb = new StringBuilder("DataServerBoot "); + + boolean start = dataServerBootstrap.getServerForSessionStarted().get(); + boolean ret = start; + sb.append("severForSession:").append(start); + + start = dataServerBootstrap.getServerForDataSyncStarted().get(); + ret = ret && start; + sb.append(", severForDataSync:").append(start); + + start = dataServerBootstrap.getHttpServerStarted().get(); + ret = ret && start; + sb.append(", httpServer:").append(start); + + start = dataServerBootstrap.getSchedulerStarted().get(); + ret = ret && start; + sb.append(", schedulerStarted:").append(start); + + start = dataNodeStatus.getStatus() == LocalServerStatusEnum.WORKING; + ret = ret && start; + sb.append(", status:").append(dataNodeStatus.getStatus()); + + if (ret) { + response = CommonResponse.buildSuccessResponse(sb.toString()); + } else { + response = CommonResponse.buildFailedResponse(sb.toString()); + } + + return response; + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/DelayItem.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/DelayItem.java new file mode 100644 index 000000000..07df17fa5 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/DelayItem.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.util; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +/** + * + * @author shangyu.wh + * @version $Id: DelayItem.java, v 0.1 2018-03-08 15:37 shangyu.wh Exp $ + */ +public class DelayItem implements Delayed { + + private static final AtomicLong SEQUENCER = new AtomicLong(0); + private final long sequenceNumber; + private final T item; + + private final long time; + + /** + * constructor + * @param submit + * @param timeout + */ + public DelayItem(T submit, long timeout) { + this.time = now() + timeout; + this.item = submit; + this.sequenceNumber = SEQUENCER.getAndIncrement(); + } + + /** + * get current time + * @return + */ + static long now() { + return System.currentTimeMillis(); + } + + @Override + public long getDelay(TimeUnit unit) { + return unit.convert(time - now(), TimeUnit.MILLISECONDS); + } + + /** + * Getter method for property item. + * + * @return property value of item + */ + public T getItem() { + return item; + } + + @Override + public int compareTo(Delayed other) { + if (other == this) { + return 0; + } + if (other instanceof DelayItem) { + DelayItem x = (DelayItem) other; + long diff = time - x.time; + if (diff < 0) { + return -1; + } else if (diff > 0) { + return 1; + } else if (sequenceNumber < x.sequenceNumber) { + return -1; + } else { + return 1; + } + } + long d = (getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS)); + return (d == 0) ? 0 : ((d < 0) ? -1 : 1); + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/LocalServerStatusEnum.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/LocalServerStatusEnum.java new file mode 100644 index 000000000..800eab4fe --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/LocalServerStatusEnum.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.util; + +/** + * + * @author qian.lqlq + * @version $Id: LocalServerStatusEnum.java, v 0.1 2018-04-29 13:49 qian.lqlq Exp $ + */ +public enum LocalServerStatusEnum { + /** */ + INITIAL, + /** */ + WORKING +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/ThreadPoolExecutorDataServer.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/ThreadPoolExecutorDataServer.java new file mode 100644 index 000000000..427e15f4b --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/ThreadPoolExecutorDataServer.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.util; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ThreadPoolExecutorDataServer.java, v 0.1 2018-10-25 20:40 shangyu.wh Exp $ + */ +public class ThreadPoolExecutorDataServer extends ThreadPoolExecutor { + + private static final Logger LOGGER = LoggerFactory + .getLogger(ThreadPoolExecutorDataServer.class); + + private String executorName; + + public ThreadPoolExecutorDataServer(String executorName, int corePoolSize, int maximumPoolSize, + long keepAliveTime, TimeUnit unit, + BlockingQueue workQueue, + ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + this.executorName = executorName; + } + + @Override + public String toString() { + return super.toString() + executorName; + } + + @Override + public void execute(Runnable command) { + try { + super.execute(command); + } catch (RejectedExecutionException e) { + LOGGER.error("Processor session executor {} Rejected Execution!command {}", this, + command.getClass(), e); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/TimeUtil.java b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/TimeUtil.java new file mode 100644 index 000000000..1a6a44ce2 --- /dev/null +++ b/server/server/data/src/main/java/com/alipay/sofa/registry/server/data/util/TimeUtil.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data.util; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.util.Random; + +/** + * + * @author qian.lqlq + * @version $Id: TimeUtil.java, v 0.1 2018-03-12 21:05 qian.lqlq Exp $ + */ +public class TimeUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(TimeUtil.class); + + /** + * random delay some time + * @param max + */ + public static void randomDelay(int max) { + Random random = new Random(); + int randomNum = random.nextInt(max); + try { + Thread.sleep(randomNum); + } catch (InterruptedException e) { + LOGGER.error("[TimeUtil] random delay error", e); + } + } +} \ No newline at end of file diff --git a/server/server/data/src/main/resources/application.properties b/server/server/data/src/main/resources/application.properties new file mode 100644 index 000000000..77c9484d3 --- /dev/null +++ b/server/server/data/src/main/resources/application.properties @@ -0,0 +1,17 @@ +spring.main.banner-mode=LOG +#nodes.metaNode=: +#nodes.localDataCenter= + +#data.server.logging.level=INFO +#data.server.logging.home=/home/admin/logs/registry/data +data.server.port=9620 +data.server.syncDataPort=9621 +data.server.httpServerPort=9622 +data.server.queueCount=4 +data.server.queueSize=10240 +data.server.notifyIntervalMs=500 +data.server.rpcTimeout=3000 +data.server.metaServerPort=9611 +data.server.storeNodes=3 +data.server.numberOfReplicas=1000 + diff --git a/server/server/data/src/main/resources/banner.txt b/server/server/data/src/main/resources/banner.txt new file mode 100644 index 000000000..fa9a967e8 --- /dev/null +++ b/server/server/data/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + + ____ _ ____ + | _ \ __ _| |_ __ _ / ___| ___ _ ____ _____ _ __ + | | | |/ _` | __/ _` | \___ \ / _ \ '__\ \ / / _ \ '__| + | |_| | (_| | || (_| | ___) | __/ | \ V / __/ | + |____/ \__,_|\__\__,_| |____/ \___|_| \_/ \___|_| + \ No newline at end of file diff --git a/server/server/data/src/main/resources/logback-spring.xml b/server/server/data/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..eab8360d6 --- /dev/null +++ b/server/server/data/src/main/resources/logback-spring.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + + + + + true + + ERROR + + ${DATA_LOG_HOME}/common-error.log + + ${DATA_LOG_HOME}/common-error.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/common-default.log + + ${DATA_LOG_HOME}/common-default.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/registry-raft.log + + ${DATA_LOG_HOME}/registry-raft.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/registry-data.log + + ${DATA_LOG_HOME}/registry-data.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/registry-startup.log + + ${DATA_LOG_HOME}/registry-startup.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/datum-change.log + + ${DATA_LOG_HOME}/datum-change.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/cache-digest.log + + ${DATA_LOG_HOME}/cache-digest.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/registry-http.log + + ${DATA_LOG_HOME}/registry-http.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/BackupTriadTest.java b/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/BackupTriadTest.java new file mode 100644 index 000000000..ba4bba93a --- /dev/null +++ b/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/BackupTriadTest.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerConfig; +import com.alipay.sofa.registry.server.data.cache.BackupTriad; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/16 + */ +public class BackupTriadTest { + @Test + public void doTest() { + List nodeList = new ArrayList<>(); + nodeList.add(new DataNode(new URL("192.168.0.1", 9632), "DefaultDataCenter")); + nodeList.add(new DataNode(new URL("192.168.0.2", 9632), "DefaultDataCenter")); + nodeList.add(new DataNode(new URL("192.168.0.3", 9632), "DefaultDataCenter")); + BackupTriad backupTriad = new BackupTriad("TestDataInfoId", nodeList); + assertFalse(backupTriad.containsSelf()); + + List newTriad = new ArrayList<>(); + newTriad.add(new DataNode(new URL("192.168.0.2", 9632), "DefaultDataCenter")); + newTriad.add(new DataNode(new URL("192.168.0.4", 9632), "DefaultDataCenter")); + Set notWorking = new HashSet<>(); + notWorking.add("192.168.0.2"); + assertEquals(2, backupTriad.getNewJoined(newTriad, notWorking).size()); + assertEquals( + "DataNode{ip=192.168.0.2, dataCenter='DefaultDataCenter', regionId='null', nodeStatus=INIT, registrationTimestamp=0}", + backupTriad.getNewJoined(newTriad, notWorking).get(0).toString()); + assertEquals( + "DataNode{ip=192.168.0.4, dataCenter='DefaultDataCenter', regionId='null', nodeStatus=INIT, registrationTimestamp=0}", + backupTriad.getNewJoined(newTriad, notWorking).get(1).toString()); + + assertEquals("TestDataInfoId", backupTriad.getDataInfoId()); + backupTriad.setDataInfoId("AnotherTestDataInfoId"); + assertEquals("AnotherTestDataInfoId", backupTriad.getDataInfoId()); + + nodeList = new ArrayList<>(); + nodeList.add(new DataNode(new URL("192.168.0.1", 9632), "DefaultDataCenter")); + nodeList.add(new DataNode(new URL(DataServerConfig.IP, 9632), "DefaultDataCenter")); + backupTriad.setTriad(nodeList); + assertTrue(backupTriad.containsSelf()); + assertEquals(2, backupTriad.getTriad().size()); + assertEquals( + "DataNode{ip=192.168.0.1, dataCenter='DefaultDataCenter', regionId='null', nodeStatus=INIT, registrationTimestamp=0}", + backupTriad.getTriad().get(0).toString()); + assertEquals( + "DataNode{ip=" + + DataServerConfig.IP + + ", dataCenter='DefaultDataCenter', regionId='null', nodeStatus=INIT, registrationTimestamp=0}", + backupTriad.getTriad().get(1).toString()); + assertTrue(backupTriad.toString().contains( + "BackupTriad{dataInfoId='AnotherTestDataInfoId', ipSetOfNode=") + && backupTriad.toString().contains("192.168.0.1") + && backupTriad.toString().contains(DataServerConfig.IP)); + } +} diff --git a/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TestSyncData.java b/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TestSyncData.java new file mode 100644 index 000000000..d1cf8ebad --- /dev/null +++ b/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TestSyncData.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.datasync.Operator; +import com.alipay.sofa.registry.server.data.datasync.sync.Acceptor; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: TestSyncData.java, v 0.1 2018-03-08 19:48 shangyu.wh Exp $ + */ +public class TestSyncData { + + private static Datum datum1; + private static Datum datum2; + private static Datum datum3; + private static Datum datum4; + private static Datum datum5; + + @Before + public void setup() { + //add + datum1 = new Datum(); + datum1.setVersion(1234); + datum1.setDataCenter("DefaultDataCenter"); + datum1.setDataInfoId("11"); + datum1.setInstanceId("1"); + + datum2 = new Datum(); + datum2.setVersion(5678); + datum2.setDataCenter("DefaultDataCenter"); + datum2.setDataInfoId("11"); + datum2.setInstanceId("2"); + + datum3 = new Datum(); + datum3.setVersion(1111); + datum3.setDataCenter("DefaultDataCenter"); + datum3.setDataInfoId("33"); + datum3.setInstanceId("3"); + + datum4 = new Datum(); + datum4.setVersion(2222); + datum4.setDataCenter("zui"); + datum4.setDataInfoId("11"); + datum4.setInstanceId("4"); + + datum5 = new Datum(); + datum5.setVersion(9999); + datum5.setDataCenter("DefaultDataCenter"); + datum5.setDataInfoId("11"); + datum5.setInstanceId("5"); + } + + @Test + public void testAcceptExpired() throws InterruptedException { + Acceptor acceptor = new Acceptor(30, "11", "DefaultDataCenter"); + + Operator operator1 = new Operator(System.currentTimeMillis(), 0L, datum1, + DataSourceTypeEnum.SYNC); + Thread.sleep(1000); + Operator operator2 = new Operator(System.currentTimeMillis(), operator1.getVersion(), + datum2, DataSourceTypeEnum.SYNC); + Thread.sleep(2000); + Operator operator5 = new Operator(System.currentTimeMillis(), operator2.getVersion(), + datum5, DataSourceTypeEnum.SYNC); + + acceptor.appendOperator(operator1); + acceptor.appendOperator(operator2); + acceptor.appendOperator(operator5); + + acceptor.checkExpired(3); + + Assert.assertEquals(2, acceptor.getAllOperators().size()); + Assert.assertTrue(acceptor.getLastVersion().equals(operator5.getVersion())); + + Collection operators = acceptor.getAllOperators(); + Operator[] ops = operators.toArray(new Operator[operators.size()]); + Assert.assertTrue(ops[0].getVersion().equals(operator2.getVersion())); + Assert.assertTrue(ops[1].getVersion().equals(operator5.getVersion())); + } +} \ No newline at end of file diff --git a/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TimeUtilTest.java b/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TimeUtilTest.java new file mode 100644 index 000000000..31890236b --- /dev/null +++ b/server/server/data/src/test/java/com/alipay/sofa/registry/server/data/TimeUtilTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.data; + +import com.alipay.sofa.registry.server.data.util.TimeUtil; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/16 + */ +public class TimeUtilTest { + @Test + public void doTest() { + long startTime = System.currentTimeMillis(); + for (int i = 0; i < 10; i++) { + TimeUtil.randomDelay(200); + } + assertTrue((System.currentTimeMillis() - startTime) < 2000); + } +} diff --git a/server/server/data/src/test/resources/logback-test.xml b/server/server/data/src/test/resources/logback-test.xml new file mode 100644 index 000000000..349319ca3 --- /dev/null +++ b/server/server/data/src/test/resources/logback-test.xml @@ -0,0 +1,75 @@ + + + + + + + + + + true + + INFO + + + ERROR + DENY + + ${LOG_HOME}/registry-data.log + + ${LOG_HOME}/registry-data.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + UTF-8 + + + + + true + + ERROR + + ${LOG_HOME}/common-error.log + + ${LOG_HOME}/common-error.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}#%L] - %m%n + UTF-8 + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/server/integration/pom.xml b/server/server/integration/pom.xml new file mode 100644 index 000000000..d5cd0191d --- /dev/null +++ b/server/server/integration/pom.xml @@ -0,0 +1,66 @@ + + + + com.alipay.sofa + registry-server + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-server-integration + + + ../../../ + + + + + com.alipay.sofa + registry-server-session + + + com.alipay.sofa + registry-server-meta + + + com.alipay.sofa + registry-server-data + + + commons-io + commons-io + + + org.springframework.boot + spring-boot-starter + + + + + registry-server-integration + + + org.springframework.boot + spring-boot-maven-plugin + + ./target + executable + + + + + repackage + + + false + + + + + + + + \ No newline at end of file diff --git a/server/server/integration/src/main/java/com/alipay/sofa/registry/server/integration/RegistryApplication.java b/server/server/integration/src/main/java/com/alipay/sofa/registry/server/integration/RegistryApplication.java new file mode 100644 index 000000000..7f9f9dd64 --- /dev/null +++ b/server/server/integration/src/main/java/com/alipay/sofa/registry/server/integration/RegistryApplication.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.integration; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.jersey.JerseyClient; +import com.alipay.sofa.registry.server.data.DataApplication; +import com.alipay.sofa.registry.server.data.bootstrap.DataServerBootstrap; +import com.alipay.sofa.registry.server.meta.MetaApplication; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerBootstrap; +import com.alipay.sofa.registry.server.session.SessionApplication; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerBootstrap; +import com.alipay.sofa.registry.util.PropertySplitter; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ConfigurableApplicationContext; + +import java.util.Collection; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class RegistryApplication { + private static final Logger LOGGER = LoggerFactory + .getLogger(RegistryApplication.class); + private static final String META_HTTP_SERVER_PORT = "meta.server.httpServerPort"; + private static final String DATA_HTTP_SERVER_PORT = "data.server.httpServerPort"; + private static final String SESSION_HTTP_SERVER_PORT = "session.server.httpServerPort"; + private static final String META_NODES = "nodes.metaNode"; + private static final String NODES_LOCAL_DATA_CENTER = "nodes.localDataCenter"; + + private static ConfigurableApplicationContext metaApplicationContext; + private static ConfigurableApplicationContext sessionApplicationContext; + private static ConfigurableApplicationContext dataApplicationContext; + + public static void main(String[] args) throws Exception { + // setup DefaultUncaughtExceptionHandler + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { + LOGGER.error(String.format("UncaughtException in Thread(%s): %s", t.getName(), e.getMessage()), e); + }); + + // start registry application + ConfigurableApplicationContext commonContext = + new SpringApplicationBuilder(RegistryApplication.class).run(args); + + // get all server address list + Collection serverList = getServerList(commonContext); + + // start meta + metaApplicationContext = new SpringApplicationBuilder(MetaApplication.class).parent(commonContext).run(); + + // wait meta cluster start + waitClusterStart(serverList, + Integer.parseInt(commonContext.getEnvironment().getProperty(META_HTTP_SERVER_PORT))); + + // start data + dataApplicationContext = new SpringApplicationBuilder(DataApplication.class).parent(commonContext).run(); + + // wait data cluster start + waitClusterStart(serverList, + Integer.parseInt(commonContext.getEnvironment().getProperty(DATA_HTTP_SERVER_PORT))); + + // start session + sessionApplicationContext = new SpringApplicationBuilder(SessionApplication.class).parent(commonContext).run(); + + // wait session cluster start + waitClusterStart(serverList, + Integer.parseInt(commonContext.getEnvironment().getProperty(SESSION_HTTP_SERVER_PORT))); + } + + public static void stop() { + if (sessionApplicationContext != null) { + sessionApplicationContext.getBean("sessionServerBootstrap", + SessionServerBootstrap.class).destroy(); + } + + if (dataApplicationContext != null) { + dataApplicationContext.getBean("dataServerBootstrap", DataServerBootstrap.class) + .destroy(); + } + + if (metaApplicationContext != null) { + metaApplicationContext.getBean("metaServerBootstrap", MetaServerBootstrap.class) + .destroy(); + } + } + + private static Collection getServerList(ConfigurableApplicationContext commonContext) { + String metaNodes = commonContext.getEnvironment().getProperty(META_NODES); + String localDataCenter = commonContext.getEnvironment() + .getProperty(NODES_LOCAL_DATA_CENTER); + return new PropertySplitter().mapOfList(metaNodes).get(localDataCenter); + } + + private static void waitClusterStart(Collection serverList, int httpPort) + throws Exception { + for (String serverAddress : serverList) { + while (true) { + if (nodeHealthCheck(serverAddress, httpPort)) { + LOGGER.info("{}:{} health check success.", serverAddress, httpPort); + break; + } + LOGGER.error("{}:{} health check failed.", serverAddress, httpPort); + Thread.sleep(1000); + } + } + } + + private static boolean nodeHealthCheck(String serverAddress, int httpPort) { + try { + JerseyClient jerseyClient = JerseyClient.getInstance(); + Channel channel = jerseyClient.connect(new URL(serverAddress, httpPort)); + return channel.getWebTarget().path("health/check").request(APPLICATION_JSON) + .get(CommonResponse.class).isSuccess(); + } catch (Throwable t) { + LOGGER.error("{}:{} health check failed.", serverAddress, httpPort, t); + return false; + } + } + + public static ConfigurableApplicationContext getMetaApplicationContext() { + return metaApplicationContext; + } + + public static ConfigurableApplicationContext getSessionApplicationContext() { + return sessionApplicationContext; + } + + public static ConfigurableApplicationContext getDataApplicationContext() { + return dataApplicationContext; + } +} diff --git a/server/server/integration/src/main/resources/application.properties b/server/server/integration/src/main/resources/application.properties new file mode 100644 index 000000000..08a6b78f2 --- /dev/null +++ b/server/server/integration/src/main/resources/application.properties @@ -0,0 +1,53 @@ +spring.main.banner-mode=LOG +#nodes.metaNode=: +#nodes.localDataCenter= +#nodes.localRegion= +#server.logging.home=/home/admin/logs/registry + +#meta.server.logging.level=INFO +#meta.server.logging.home=/home/admin/logs/registry/meta +meta.server.sessionServerPort=9610 +meta.server.dataServerPort=9611 +meta.server.metaServerPort=9612 +meta.server.raftServerPort=9614 +meta.server.httpServerPort=9615 +meta.server.raftGroup=MetaServerRaftGroup + +#data.server.logging.level=INFO +#data.server.logging.home=/home/admin/logs/registry/data +data.server.port=9620 +data.server.syncDataPort=9621 +data.server.httpServerPort=9622 +data.server.queueCount=4 +data.server.queueSize=10240 +data.server.notifyIntervalMs=500 +data.server.rpcTimeout=3000 +data.server.metaServerPort=9611 +data.server.storeNodes=3 +data.server.numberOfReplicas=1000 + +#session.server.logging.level=INFO +#session.server.logging.home=/home/admin/logs/registry/session +session.server.serverPort=9600 +session.server.serverSyncPort=9601 +session.server.httpServerPort=9603 +session.server.metaServerPort=9610 +session.server.dataServerPort=9620 +session.server.serverDescription=dev session server +session.server.sessionServerRegion=DEFAULT_ZONE +session.server.sessionServerDataCenter=DefaultDataCenter +session.server.syncHeartbeat.fixedDelay=30000 +session.server.syncExceptionData.fixedDelay=30000 +session.server.printTask.fixedDelay=30000 +session.server.schedulerCheckVersionTimeout=3 +session.server.schedulerCheckVersionFirstDelay=3 +session.server.schedulerCheckVersionExpBackOffBound=10 +session.server.schedulerHeartbeatTimeout=30 +session.server.schedulerHeartbeatFirstDelay=30 +session.server.schedulerHeartbeatExpBackOffBound=10 +session.server.schedulerFetchDataTimeout=3 +session.server.schedulerFetchDataFirstDelay=3 +session.server.schedulerFetchDataExpBackOffBound=10 +#session.server.invalidForeverZones=; +#session.server.invalidIgnoreDataidRegex= +#session.server.pushEmptyDataDataIdPrefixes= \ No newline at end of file diff --git a/server/server/integration/src/main/resources/banner.txt b/server/server/integration/src/main/resources/banner.txt new file mode 100644 index 000000000..0564d00f2 --- /dev/null +++ b/server/server/integration/src/main/resources/banner.txt @@ -0,0 +1,9 @@ + +______ _ _ _____ +| ___ \ (_) | | / ___| +| |_/ /___ __ _ _ ___| |_ _ __ _ _ \ `--. ___ _ ____ _____ _ __ +| // _ \/ _` | / __| __| '__| | | | `--. \/ _ \ '__\ \ / / _ \ '__| +| |\ \ __/ (_| | \__ \ |_| | | |_| | /\__/ / __/ | \ V / __/ | +\_| \_\___|\__, |_|___/\__|_| \__, | \____/ \___|_| \_/ \___|_| + __/ | __/ | + |___/ |___/ diff --git a/server/server/integration/src/main/resources/logback-spring.xml b/server/server/integration/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..167ae8744 --- /dev/null +++ b/server/server/integration/src/main/resources/logback-spring.xml @@ -0,0 +1,538 @@ + + + + + + + + + + + + + + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + + + + + true + + ERROR + + ${LOG_HOME}/common-error.log + + ${LOG_HOME}/common-error.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${LOG_HOME}/common-default.log + + ${LOG_HOME}/common-default.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${LOG_HOME}/registry-raft.log + + ${LOG_HOME}/registry-raft.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${LOG_HOME}/registry-startup.log + + ${LOG_HOME}/registry-startup.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-meta.log + + ${META_LOG_HOME}/registry-meta.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-connect.log + + ${META_LOG_HOME}/registry-connect.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-raft-metrics.log + + ${META_LOG_HOME}/registry-raft-metrics.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-http.log + + ${META_LOG_HOME}/registry-http.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/registry-data.log + + ${DATA_LOG_HOME}/registry-data.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/datum-change.log + + ${DATA_LOG_HOME}/datum-change.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/cache-digest.log + + ${DATA_LOG_HOME}/cache-digest.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/profile-digest.log + + ${DATA_LOG_HOME}/profile-digest.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${DATA_LOG_HOME}/registry-http.log + + ${DATA_LOG_HOME}/registry-http.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-session.log + + ${SESSION_LOG_HOME}/registry-session.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-connect.log + + ${SESSION_LOG_HOME}/registry-connect.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-console.log + + ${SESSION_LOG_HOME}/registry-console.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-exchange.log + + ${SESSION_LOG_HOME}/registry-exchange.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-push.log + + ${SESSION_LOG_HOME}/registry-push.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-profile-digest.log + + ${SESSION_LOG_HOME}/registry-profile-digest.log.%d{yyyy-MM-dd} + 10 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + 0 + 1024 + + + + + 0 + 1024 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/server/meta/pom.xml b/server/server/meta/pom.xml new file mode 100644 index 000000000..9c8ded95a --- /dev/null +++ b/server/server/meta/pom.xml @@ -0,0 +1,122 @@ + + + + com.alipay.sofa + registry-server + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-server-meta + + + ../../../ + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + com.alipay.sofa + registry-remoting-api + + + com.google.guava + guava + + + com.alipay.sofa + registry-common-util + + + com.alipay.sofa + registry-remoting-bolt + + + com.alipay.sofa + registry-remoting-http + + + com.alipay.sofa + registry-common-model + + + com.alipay.sofa.common + sofa-common-tools + + + com.alipay.sofa + hessian + + + io.netty + netty-all + + + org.hibernate + hibernate-validator + + + org.glassfish.jersey.media + jersey-media-json-jackson + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.powermock + powermock-module-junit4 + test + + + org.powermock + powermock-api-mockito + test + + + com.alipay.sofa + registry-store-jraft + + + + + registry-server-meta + + + org.springframework.boot + spring-boot-maven-plugin + + ./target + executable + + + + + repackage + + + false + + + + + + + diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/MetaApplication.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/MetaApplication.java new file mode 100644 index 000000000..0869d1851 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/MetaApplication.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.EnableMetaServer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * + * @author zhuoyu.sjw + * @version $Id: MetaApplication.java, v 0.1 2017-11-13 19:03 zhuoyu.sjw Exp $$ + */ +@EnableMetaServer +@SpringBootApplication +public class MetaApplication { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaApplication.class); + + public static void main(String[] args) { + // setup DefaultUncaughtExceptionHandler + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { + LOGGER.error(String.format("UncaughtException in Thread(%s): %s", t.getName(), e.getMessage()), e); + }); + + SpringApplication.run(MetaApplication.class, args); + } +} diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/AbstractNodeConfigBean.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/AbstractNodeConfigBean.java new file mode 100644 index 000000000..c5b8e78a5 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/AbstractNodeConfigBean.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractNodeConfigBean.java, v 0.1 2018-05-03 16:14 shangyu.wh Exp $ + */ +public abstract class AbstractNodeConfigBean implements NodeConfig { + + private static final Logger LOGGER = LoggerFactory + .getLogger(AbstractNodeConfigBean.class); + + protected Map> metaNodeIP; + + private Map dataCenterMetaIPCache = new HashMap<>(); + + /** + * Getter method for property metaNodeIP. + * + * @return property value of metaNodeIP + */ + @Override + public Map> getMetaNodeIP() { + if (metaNodeIP == null || metaNodeIP.isEmpty()) { + metaNodeIP = convertToIP(getMetaNode()); + } + return metaNodeIP; + } + + private Map> convertToIP(Map> input) { + + Map> ret = new HashMap<>(); + try { + + if (input != null) { + input.forEach((dataCenter, domains) -> { + if (domains != null) { + List ipList = new ArrayList<>(); + domains.forEach((domain) -> { + if (domain != null) { + String ip = NetUtil.getIPAddressFromDomain(domain); + if (ip == null) { + LOGGER.error("Node config convert domain {} error!", domain); + throw new RuntimeException("Node config convert domain {" + domain + "} error!"); + } + ipList.add(ip); + } + }); + ret.put(dataCenter, ipList); + } + }); + } + } catch (Exception e) { + LOGGER.error("Node config convert domain error!", e); + throw new RuntimeException("Node config convert domain error!", e); + } + return ret; + } + + @Override + public String getMetaDataCenter(String metaIpAddress) { + if (metaIpAddress == null || metaIpAddress.isEmpty()) { + LOGGER.error("IpAddress:" + metaIpAddress + " cannot be null!"); + return null; + } + + String dataCenterRet = dataCenterMetaIPCache.get(metaIpAddress); + + if (dataCenterRet == null || dataCenterRet.isEmpty()) { + Map> metaList = getMetaNodeIP(); + + AtomicReference ret = new AtomicReference<>(); + metaList.forEach((dataCenter, list) -> { + if (list.contains(metaIpAddress)) { + ret.set(dataCenter); + } + }); + + if (ret.get() == null) { + LOGGER.error("node ipAddress:" + metaIpAddress + " cannot be found on config list!"); + } + dataCenterRet = ret.get(); + } + return dataCenterRet; + } + + @Override + public Set getDataCenterMetaServers(String dataCenterIn) { + Map> metaMap = getMetaNodeIP(); + Set metaServerIpSet = new HashSet<>(); + if (metaMap != null && metaMap.size() > 0) { + Collection list = metaMap.get(dataCenterIn); + if (list != null) { + metaServerIpSet.addAll(list); + } + + } + return metaServerIpSet; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/EnableMetaServer.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/EnableMetaServer.java new file mode 100644 index 000000000..f2126b7ca --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/EnableMetaServer.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author shangyu.wh + * @version $Id: EnableMetaServer.java, v 0.1 2018-01-16 11:26 shangyu.wh Exp $ + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(MetaServerConfiguration.class) +public @interface EnableMetaServer { +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerBootstrap.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerBootstrap.java new file mode 100644 index 000000000..613b338cf --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerBootstrap.java @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.meta.executor.ExecutorManager; +import com.alipay.sofa.registry.server.meta.remoting.RaftExchanger; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +import javax.annotation.Resource; +import javax.ws.rs.Path; +import javax.ws.rs.ext.Provider; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author shangyu.wh + * @version $Id: MetaServerBootstrap.java, v 0.1 2018-01-16 11:28 shangyu.wh Exp $ + */ +public class MetaServerBootstrap { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaServerBootstrap.class); + + @Autowired + private MetaServerConfig metaServerConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private Exchange jerseyExchange; + + @Autowired + private ExecutorManager executorManager; + + @Resource(name = "sessionServerHandlers") + private Collection sessionServerHandlers; + + @Resource(name = "dataServerHandlers") + private Collection dataServerHandlers; + + @Resource(name = "metaServerHandlers") + private Collection metaServerHandlers; + + @Autowired + private ResourceConfig jerseyResourceConfig; + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private RaftExchanger raftExchanger; + + private Server sessionServer; + + private Server dataServer; + + private Server metaServer; + + private Server httpServer; + + private AtomicBoolean sessionStart = new AtomicBoolean(false); + + private AtomicBoolean dataStart = new AtomicBoolean(false); + + private AtomicBoolean metaStart = new AtomicBoolean(false); + + private AtomicBoolean httpStart = new AtomicBoolean(false); + + /** + * Do initialized. + */ + public void doInitialized() { + try { + openSessionRegisterServer(); + + openDataRegisterServer(); + + openMetaRegisterServer(); + + openHttpServer(); + + initRaft(); + + Runtime.getRuntime().addShutdownHook(new Thread(this::doStop)); + } catch (Throwable e) { + LOGGER.error("Bootstrap Meta Server got error!", e); + throw new RuntimeException("Bootstrap Meta Server got error!", e); + } + } + + public void destroy() { + doStop(); + } + + private void doStop() { + try { + LOGGER.info("{} Shutting down Meta Server..", new Date().toString()); + + executorManager.stopScheduler(); + + TaskDispatchers.stopDefaultSingleTaskDispatcher(); + + stopServer(); + + } catch (Throwable e) { + LOGGER.error("Shutting down Meta Server error!", e); + } + LOGGER.info("{} Meta server is now shutdown...", new Date().toString()); + } + + private void openSessionRegisterServer() { + try { + if (sessionStart.compareAndSet(false, true)) { + sessionServer = boltExchange + .open( + new URL(NetUtil.getLocalAddress().getHostAddress(), metaServerConfig + .getSessionServerPort()), sessionServerHandlers + .toArray(new ChannelHandler[sessionServerHandlers.size()])); + + LOGGER.info("Open session node register server port {} success!", + metaServerConfig.getSessionServerPort()); + } + } catch (Exception e) { + sessionStart.set(false); + LOGGER.error("Open session node register server port {} error!", + metaServerConfig.getSessionServerPort(), e); + throw new RuntimeException("Open session node register server error!", e); + } + } + + private void openDataRegisterServer() { + try { + if (dataStart.compareAndSet(false, true)) { + dataServer = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(), + metaServerConfig.getDataServerPort()), dataServerHandlers + .toArray(new ChannelHandler[dataServerHandlers.size()])); + + LOGGER.info("Open data node register server port {} success!", + metaServerConfig.getDataServerPort()); + } + } catch (Exception e) { + dataStart.set(false); + LOGGER.error("Open data node register server port {} error!", + metaServerConfig.getDataServerPort(), e); + throw new RuntimeException("Open data node register server error!", e); + } + } + + private void openMetaRegisterServer() { + try { + if (metaStart.compareAndSet(false, true)) { + metaServer = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(), + metaServerConfig.getMetaServerPort()), metaServerHandlers + .toArray(new ChannelHandler[metaServerHandlers.size()])); + + LOGGER.info("Open meta server port {} success!", + metaServerConfig.getMetaServerPort()); + } + } catch (Exception e) { + metaStart.set(false); + LOGGER + .error("Open meta server port {} error!", metaServerConfig.getMetaServerPort(), e); + throw new RuntimeException("Open meta server error!", e); + } + } + + private void openHttpServer() { + try { + if (httpStart.compareAndSet(false, true)) { + bindResourceConfig(); + httpServer = jerseyExchange.open( + new URL(NetUtil.getLocalAddress().getHostAddress(), metaServerConfig + .getHttpServerPort()), new ResourceConfig[] { jerseyResourceConfig }); + LOGGER.info("Open http server port {} success!", + metaServerConfig.getHttpServerPort()); + } + } catch (Exception e) { + httpStart.set(false); + LOGGER + .error("Open http server port {} error!", metaServerConfig.getHttpServerPort(), e); + throw new RuntimeException("Open http server error!", e); + } + } + + private void bindResourceConfig() { + registerInstances(Path.class); + registerInstances(Provider.class); + } + + private void registerInstances(Class annotationType) { + Map beans = applicationContext.getBeansWithAnnotation(annotationType); + if (beans != null && beans.size() > 0) { + beans.forEach((beanName, bean) -> jerseyResourceConfig.registerInstances(bean)); + } + } + + private void initRaft() { + raftExchanger.startRaftServer(executorManager); + LOGGER.info("Raft server port {} start success!group {}", + metaServerConfig.getRaftServerPort(), metaServerConfig.getRaftGroup()); + + raftExchanger.startRaftClient(); + LOGGER.info("Raft client connect success!"); + + raftExchanger.startCliService(); + LOGGER.info("Raft start CliService success!"); + + } + + private void stopServer() { + if (sessionServer != null && sessionServer.isOpen()) { + sessionServer.close(); + } + if (dataServer != null && dataServer.isOpen()) { + dataServer.close(); + } + if (metaServer != null && metaServer.isOpen()) { + metaServer.close(); + } + if (httpServer != null && httpServer.isOpen()) { + httpServer.close(); + } + if (raftExchanger != null) { + raftExchanger.shutdown(); + } + } + + /** + * Getter method for property sessionStart. + * + * @return property value of sessionStart + */ + public AtomicBoolean getSessionStart() { + return sessionStart; + } + + /** + * Getter method for property dataStart. + * + * @return property value of dataStart + */ + public AtomicBoolean getDataStart() { + return dataStart; + } + + /** + * Getter method for property metaStart. + * + * @return property value of metaStart + */ + public AtomicBoolean getMetaStart() { + return metaStart; + } + + /** + * Getter method for property httpStart. + * + * @return property value of httpStart + */ + public AtomicBoolean getHttpStart() { + return httpStart; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfig.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfig.java new file mode 100644 index 000000000..d4b09b38b --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfig.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +/** + * + * @author shangyu.wh + * @version $Id: MetaServerConfig.java, v 0.1 2018-01-16 10:58 shangyu.wh Exp $ + */ +public interface MetaServerConfig { + int getSessionServerPort(); + + int getDataServerPort(); + + int getMetaServerPort(); + + int getHttpServerPort(); + + int getRaftServerPort(); + + int getSchedulerHeartbeatTimeout(); + + int getSchedulerHeartbeatFirstDelay(); + + int getSchedulerHeartbeatExpBackOffBound(); + + int getSchedulerGetDataChangeTimeout(); + + int getSchedulerGetDataChangeFirstDelay(); + + int getSchedulerGetDataChangeExpBackOffBound(); + + int getSchedulerConnectMetaServerTimeout(); + + int getSchedulerConnectMetaServerFirstDelay(); + + int getSchedulerConnectMetaServerExpBackOffBound(); + + int getSchedulerCheckNodeListChangePushTimeout(); + + int getSchedulerCheckNodeListChangePushFirstDelay(); + + int getSchedulerCheckNodeListChangePushExpBackOffBound(); + + int getDataNodeExchangeTimeout(); + + int getSessionNodeExchangeTimeout(); + + int getMetaNodeExchangeTimeout(); + + DecisionMode getDecisionMode(); + + int getDataCenterChangeNotifyTaskRetryTimes(); + + int getDataNodeChangePushTaskRetryTimes(); + + int getGetDataCenterChangeListTaskRetryTimes(); + + int getReceiveStatusConfirmNotifyTaskRetryTimes(); + + int getSessionNodeChangePushTaskRetryTimes(); + + String getRaftGroup(); + + String getRaftDataPath(); + + boolean isEnableMetrics(); + + /** + * decision mode enum + */ + enum DecisionMode { + RUNTIME, OFF + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfigBean.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfigBean.java new file mode 100644 index 000000000..bb484c923 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfigBean.java @@ -0,0 +1,602 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.io.File; + +/** + * + * @author shangyu.wh + * @version $Id: MetaServerConfigBean.java, v 0.1 2018-01-16 11:01 shangyu.wh Exp $ + */ +@ConfigurationProperties(prefix = MetaServerConfigBean.PREFIX) +public class MetaServerConfigBean implements MetaServerConfig { + + public static final String PREFIX = "meta.server"; + + private int sessionServerPort = 9610; + + private int dataServerPort = 9611; + + private int metaServerPort = 9612; + + private int httpServerPort = 9615; + + private int schedulerHeartbeatTimeout = 3; + + private int schedulerHeartbeatFirstDelay = 3; + + private int schedulerHeartbeatExpBackOffBound = 10; + + private int schedulerGetDataChangeTimeout = 10; + + private int schedulerGetDataChangeFirstDelay = 10; + + private int schedulerGetDataChangeExpBackOffBound = 20; + + private int schedulerConnectMetaServerTimeout = 3; + + private int schedulerConnectMetaServerFirstDelay = 3; + + private int schedulerConnectMetaServerExpBackOffBound = 10; + + private int schedulerCheckNodeListChangePushTimeout = 3; + + private int schedulerCheckNodeListChangePushFirstDelay = 1; + + private int schedulerCheckNodeListChangePushExpBackOffBound = 10; + + private int dataNodeExchangeTimeout = 3000; + + private int sessionNodeExchangeTimeout = 3000; + + private int metaNodeExchangeTimeout = 3000; + + private int dataCenterChangeNotifyTaskRetryTimes = 3; + + private int dataNodeChangePushTaskRetryTimes = 1; + + private int getDataCenterChangeListTaskRetryTimes = 3; + + private int receiveStatusConfirmNotifyTaskRetryTimes = 3; + + private int sessionNodeChangePushTaskRetryTimes = 3; + + /** + * Whether to enable metrics for node. + */ + private boolean enableMetrics = true; + + private DecisionMode decisionMode; + + private String raftDataPath = System + .getProperty("user.home") + + File.separator + + "raftData"; + + @Override + public int getSessionServerPort() { + return sessionServerPort; + } + + /** + * Setter method for property sessionServerPort. + * + * @param sessionServerPort value to be assigned to property sessionServerPort + */ + public void setSessionServerPort(int sessionServerPort) { + this.sessionServerPort = sessionServerPort; + } + + @Override + public int getDataServerPort() { + return dataServerPort; + } + + /** + * Setter method for property dataServerPort. + * + * @param dataServerPort value to be assigned to property dataServerPort + */ + public void setDataServerPort(int dataServerPort) { + this.dataServerPort = dataServerPort; + } + + @Override + public int getHttpServerPort() { + return httpServerPort; + } + + /** + * Setter method for property httpServerPort. + * + * @param httpServerPort value to be assigned to property httpServerPort + */ + public void setHttpServerPort(int httpServerPort) { + this.httpServerPort = httpServerPort; + } + + /** + * Getter method for property schedulerHeartbeatTimeout. + * + * @return property value of schedulerHeartbeatTimeout + */ + @Override + public int getSchedulerHeartbeatTimeout() { + return schedulerHeartbeatTimeout; + } + + /** + * Setter method for property schedulerHeartbeatTimeout. + * + * @param schedulerHeartbeatTimeout value to be assigned to property schedulerHeartbeatTimeout + */ + public void setSchedulerHeartbeatTimeout(int schedulerHeartbeatTimeout) { + this.schedulerHeartbeatTimeout = schedulerHeartbeatTimeout; + } + + /** + * Getter method for property schedulerHeartbeatFirstDelay. + * + * @return property value of schedulerHeartbeatFirstDelay + */ + @Override + public int getSchedulerHeartbeatFirstDelay() { + return schedulerHeartbeatFirstDelay; + } + + /** + * Setter method for property schedulerHeartbeatFirstDelay. + * + * @param schedulerHeartbeatFirstDelay value to be assigned to property schedulerHeartbeatFirstDelay + */ + public void setSchedulerHeartbeatFirstDelay(int schedulerHeartbeatFirstDelay) { + this.schedulerHeartbeatFirstDelay = schedulerHeartbeatFirstDelay; + } + + /** + * Getter method for property schedulerHeartbeatExpBackOffBound. + * + * @return property value of schedulerHeartbeatExpBackOffBound + */ + @Override + public int getSchedulerHeartbeatExpBackOffBound() { + return schedulerHeartbeatExpBackOffBound; + } + + /** + * Setter method for property schedulerHeartbeatExpBackOffBound. + * + * @param schedulerHeartbeatExpBackOffBound value to be assigned to property schedulerHeartbeatExpBackOffBound + */ + public void setSchedulerHeartbeatExpBackOffBound(int schedulerHeartbeatExpBackOffBound) { + this.schedulerHeartbeatExpBackOffBound = schedulerHeartbeatExpBackOffBound; + } + + @Override + public DecisionMode getDecisionMode() { + return decisionMode; + } + + /** + * Setter method for property decisionMode. + * + * @param decisionMode value to be assigned to property decisionMode + */ + public void setDecisionMode(DecisionMode decisionMode) { + this.decisionMode = decisionMode; + } + + /** + * Getter method for property dataNodeExchangeTimeout. + * + * @return property value of dataNodeExchangeTimeout + */ + @Override + public int getDataNodeExchangeTimeout() { + return dataNodeExchangeTimeout; + } + + /** + * Setter method for property dataNodeExchangeTimeout. + * + * @param dataNodeExchangeTimeout value to be assigned to property dataNodeExchangeTimeout + */ + public void setDataNodeExchangeTimeout(int dataNodeExchangeTimeout) { + this.dataNodeExchangeTimeout = dataNodeExchangeTimeout; + } + + /** + * Getter method for property sessionNodeExchangeTimeout. + * + * @return property value of sessionNodeExchangeTimeout + */ + @Override + public int getSessionNodeExchangeTimeout() { + return sessionNodeExchangeTimeout; + } + + /** + * Setter method for property sessionNodeExchangeTimeout. + * + * @param sessionNodeExchangeTimeout value to be assigned to property sessionNodeExchangeTimeout + */ + public void setSessionNodeExchangeTimeout(int sessionNodeExchangeTimeout) { + this.sessionNodeExchangeTimeout = sessionNodeExchangeTimeout; + } + + /** + * Getter method for property schedulerConnectMetaServerTimeout. + * + * @return property value of schedulerConnectMetaServerTimeout + */ + @Override + public int getSchedulerConnectMetaServerTimeout() { + return schedulerConnectMetaServerTimeout; + } + + /** + * Setter method for property schedulerConnectMetaServerTimeout. + * + * @param schedulerConnectMetaServerTimeout value to be assigned to property schedulerConnectMetaServerTimeout + */ + public void setSchedulerConnectMetaServerTimeout(int schedulerConnectMetaServerTimeout) { + this.schedulerConnectMetaServerTimeout = schedulerConnectMetaServerTimeout; + } + + /** + * Getter method for property schedulerConnectMetaServerFirstDelay. + * + * @return property value of schedulerConnectMetaServerFirstDelay + */ + @Override + public int getSchedulerConnectMetaServerFirstDelay() { + return schedulerConnectMetaServerFirstDelay; + } + + /** + * Setter method for property schedulerConnectMetaServerFirstDelay. + * + * @param schedulerConnectMetaServerFirstDelay value to be assigned to property schedulerConnectMetaServerFirstDelay + */ + public void setSchedulerConnectMetaServerFirstDelay(int schedulerConnectMetaServerFirstDelay) { + this.schedulerConnectMetaServerFirstDelay = schedulerConnectMetaServerFirstDelay; + } + + /** + * Getter method for property schedulerConnectMetaServerExpBackOffBound. + * + * @return property value of schedulerConnectMetaServerExpBackOffBound + */ + @Override + public int getSchedulerConnectMetaServerExpBackOffBound() { + return schedulerConnectMetaServerExpBackOffBound; + } + + /** + * Setter method for property schedulerConnectMetaServerExpBackOffBound. + * + * @param schedulerConnectMetaServerExpBackOffBound value to be assigned to property schedulerConnectMetaServerExpBackOffBound + */ + public void setSchedulerConnectMetaServerExpBackOffBound(int schedulerConnectMetaServerExpBackOffBound) { + this.schedulerConnectMetaServerExpBackOffBound = schedulerConnectMetaServerExpBackOffBound; + } + + /** + * Getter method for property metaServerPort. + * + * @return property value of metaServerPort + */ + @Override + public int getMetaServerPort() { + return metaServerPort; + } + + /** + * Setter method for property metaServerPort. + * + * @param metaServerPort value to be assigned to property metaServerPort + */ + public void setMetaServerPort(int metaServerPort) { + this.metaServerPort = metaServerPort; + } + + /** + * Getter method for property metaNodeExchangeTimeout. + * + * @return property value of metaNodeExchangeTimeout + */ + @Override + public int getMetaNodeExchangeTimeout() { + return metaNodeExchangeTimeout; + } + + /** + * Setter method for property metaNodeExchangeTimeout. + * + * @param metaNodeExchangeTimeout value to be assigned to property metaNodeExchangeTimeout + */ + public void setMetaNodeExchangeTimeout(int metaNodeExchangeTimeout) { + this.metaNodeExchangeTimeout = metaNodeExchangeTimeout; + } + + /** + * Getter method for property dataCenterChangeNotifyTaskRetryTimes. + * + * @return property value of dataCenterChangeNotifyTaskRetryTimes + */ + @Override + public int getDataCenterChangeNotifyTaskRetryTimes() { + return dataCenterChangeNotifyTaskRetryTimes; + } + + /** + * Setter method for property dataCenterChangeNotifyTaskRetryTimes. + * + * @param dataCenterChangeNotifyTaskRetryTimes value to be assigned to property dataCenterChangeNotifyTaskRetryTimes + */ + public void setDataCenterChangeNotifyTaskRetryTimes(int dataCenterChangeNotifyTaskRetryTimes) { + this.dataCenterChangeNotifyTaskRetryTimes = dataCenterChangeNotifyTaskRetryTimes; + } + + /** + * Getter method for property dataNodeChangePushTaskRetryTimes. + * + * @return property value of dataNodeChangePushTaskRetryTimes + */ + @Override + public int getDataNodeChangePushTaskRetryTimes() { + return dataNodeChangePushTaskRetryTimes; + } + + /** + * Setter method for property dataNodeChangePushTaskRetryTimes. + * + * @param dataNodeChangePushTaskRetryTimes value to be assigned to property dataNodeChangePushTaskRetryTimes + */ + public void setDataNodeChangePushTaskRetryTimes(int dataNodeChangePushTaskRetryTimes) { + this.dataNodeChangePushTaskRetryTimes = dataNodeChangePushTaskRetryTimes; + } + + /** + * Getter method for property getDataCenterChangeListTaskRetryTimes. + * + * @return property value of getDataCenterChangeListTaskRetryTimes + */ + @Override + public int getGetDataCenterChangeListTaskRetryTimes() { + return getDataCenterChangeListTaskRetryTimes; + } + + /** + * Setter method for property getDataCenterChangeListTaskRetryTimes. + * + * @param getDataCenterChangeListTaskRetryTimes value to be assigned to property getDataCenterChangeListTaskRetryTimes + */ + public void setGetDataCenterChangeListTaskRetryTimes(int getDataCenterChangeListTaskRetryTimes) { + this.getDataCenterChangeListTaskRetryTimes = getDataCenterChangeListTaskRetryTimes; + } + + /** + * Getter method for property receiveStatusConfirmNotifyTaskRetryTimes. + * + * @return property value of receiveStatusConfirmNotifyTaskRetryTimes + */ + @Override + public int getReceiveStatusConfirmNotifyTaskRetryTimes() { + return receiveStatusConfirmNotifyTaskRetryTimes; + } + + /** + * Setter method for property receiveStatusConfirmNotifyTaskRetryTimes. + * + * @param receiveStatusConfirmNotifyTaskRetryTimes value to be assigned to property receiveStatusConfirmNotifyTaskRetryTimes + */ + public void setReceiveStatusConfirmNotifyTaskRetryTimes(int receiveStatusConfirmNotifyTaskRetryTimes) { + this.receiveStatusConfirmNotifyTaskRetryTimes = receiveStatusConfirmNotifyTaskRetryTimes; + } + + /** + * Getter method for property sessionNodeChangePushTaskRetryTimes. + * + * @return property value of sessionNodeChangePushTaskRetryTimes + */ + @Override + public int getSessionNodeChangePushTaskRetryTimes() { + return sessionNodeChangePushTaskRetryTimes; + } + + /** + * Setter method for property sessionNodeChangePushTaskRetryTimes. + * + * @param sessionNodeChangePushTaskRetryTimes value to be assigned to property sessionNodeChangePushTaskRetryTimes + */ + public void setSessionNodeChangePushTaskRetryTimes(int sessionNodeChangePushTaskRetryTimes) { + this.sessionNodeChangePushTaskRetryTimes = sessionNodeChangePushTaskRetryTimes; + } + + /** + * Getter method for property schedulerCheckNodeListChangePushTimeout. + * + * @return property value of schedulerCheckNodeListChangePushTimeout + */ + @Override + public int getSchedulerCheckNodeListChangePushTimeout() { + return schedulerCheckNodeListChangePushTimeout; + } + + /** + * Setter method for property schedulerCheckNodeListChangePushTimeout. + * + * @param schedulerCheckNodeListChangePushTimeout value to be assigned to property schedulerCheckNodeListChangePushTimeout + */ + public void setSchedulerCheckNodeListChangePushTimeout(int schedulerCheckNodeListChangePushTimeout) { + this.schedulerCheckNodeListChangePushTimeout = schedulerCheckNodeListChangePushTimeout; + } + + /** + * Getter method for property schedulerCheckNodeListChangePushFirstDelay. + * + * @return property value of schedulerCheckNodeListChangePushFirstDelay + */ + @Override + public int getSchedulerCheckNodeListChangePushFirstDelay() { + return schedulerCheckNodeListChangePushFirstDelay; + } + + /** + * Setter method for property schedulerCheckNodeListChangePushFirstDelay. + * + * @param schedulerCheckNodeListChangePushFirstDelay value to be assigned to property schedulerCheckNodeListChangePushFirstDelay + */ + public void setSchedulerCheckNodeListChangePushFirstDelay(int schedulerCheckNodeListChangePushFirstDelay) { + this.schedulerCheckNodeListChangePushFirstDelay = schedulerCheckNodeListChangePushFirstDelay; + } + + /** + * Getter method for property schedulerCheckNodeListChangePushExpBackOffBound. + * + * @return property value of schedulerCheckNodeListChangePushExpBackOffBound + */ + @Override + public int getSchedulerCheckNodeListChangePushExpBackOffBound() { + return schedulerCheckNodeListChangePushExpBackOffBound; + } + + /** + * Setter method for property schedulerCheckNodeListChangePushExpBackOffBound. + * + * @param schedulerCheckNodeListChangePushExpBackOffBound value to be assigned to property + * schedulerCheckNodeListChangePushExpBackOffBound + */ + public void setSchedulerCheckNodeListChangePushExpBackOffBound(int schedulerCheckNodeListChangePushExpBackOffBound) { + this.schedulerCheckNodeListChangePushExpBackOffBound = schedulerCheckNodeListChangePushExpBackOffBound; + } + + /** + * Getter method for property schedulerGetDataChangeTimeout. + * + * @return property value of schedulerGetDataChangeTimeout + */ + @Override + public int getSchedulerGetDataChangeTimeout() { + return schedulerGetDataChangeTimeout; + } + + /** + * Setter method for property schedulerGetDataChangeTimeout. + * + * @param schedulerGetDataChangeTimeout value to be assigned to property schedulerGetDataChangeTimeout + */ + public void setSchedulerGetDataChangeTimeout(int schedulerGetDataChangeTimeout) { + this.schedulerGetDataChangeTimeout = schedulerGetDataChangeTimeout; + } + + /** + * Getter method for property schedulerGetDataChangeFirstDelay. + * + * @return property value of schedulerGetDataChangeFirstDelay + */ + @Override + public int getSchedulerGetDataChangeFirstDelay() { + return schedulerGetDataChangeFirstDelay; + } + + /** + * Setter method for property schedulerGetDataChangeFirstDelay. + * + * @param schedulerGetDataChangeFirstDelay value to be assigned to property schedulerGetDataChangeFirstDelay + */ + public void setSchedulerGetDataChangeFirstDelay(int schedulerGetDataChangeFirstDelay) { + this.schedulerGetDataChangeFirstDelay = schedulerGetDataChangeFirstDelay; + } + + /** + * Getter method for property schedulerGetDataChangeExpBackOffBound. + * + * @return property value of schedulerGetDataChangeExpBackOffBound + */ + @Override + public int getSchedulerGetDataChangeExpBackOffBound() { + return schedulerGetDataChangeExpBackOffBound; + } + + /** + * Setter method for property schedulerGetDataChangeExpBackOffBound. + * + * @param schedulerGetDataChangeExpBackOffBound value to be assigned to property schedulerGetDataChangeExpBackOffBound + */ + public void setSchedulerGetDataChangeExpBackOffBound(int schedulerGetDataChangeExpBackOffBound) { + this.schedulerGetDataChangeExpBackOffBound = schedulerGetDataChangeExpBackOffBound; + } + + /** + * Getter method for property raftGroup. + * + * @return property value of raftGroup + */ + @Override + public String getRaftGroup() { + return ValueConstants.RAFT_SERVER_GROUP; + } + + /** + * Getter method for property raftServerPort. + * + * @return property value of raftServerPort + */ + @Override + public int getRaftServerPort() { + return ValueConstants.RAFT_SERVER_PORT; + } + + /** + * Getter method for property raftDataPath. + * + * @return property value of raftDataPath + */ + @Override + public String getRaftDataPath() { + return raftDataPath; + } + + /** + * Setter method for property raftDataPath. + * + * @param raftDataPath value to be assigned to property raftDataPath + */ + public void setRaftDataPath(String raftDataPath) { + this.raftDataPath = raftDataPath; + } + + @Override + public boolean isEnableMetrics() { + return enableMetrics; + } + + /** + * Setter method for property enableMetrics. + * + * @param enableMetrics value to be assigned to property enableMetrics + */ + public void setEnableMetrics(boolean enableMetrics) { + this.enableMetrics = enableMetrics; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfiguration.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfiguration.java new file mode 100644 index 000000000..745881be0 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerConfiguration.java @@ -0,0 +1,436 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import com.alipay.sofa.registry.jraft.service.PersistenceDataDBService; +import com.alipay.sofa.registry.remoting.bolt.exchange.BoltExchange; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.jersey.exchange.JerseyExchange; +import com.alipay.sofa.registry.server.meta.executor.ExecutorManager; +import com.alipay.sofa.registry.server.meta.listener.DataNodeChangePushTaskListener; +import com.alipay.sofa.registry.server.meta.listener.PersistenceDataChangeNotifyTaskListener; +import com.alipay.sofa.registry.server.meta.listener.ReceiveStatusConfirmNotifyTaskListener; +import com.alipay.sofa.registry.server.meta.listener.SessionNodeChangePushTaskListener; +import com.alipay.sofa.registry.server.meta.node.NodeService; +import com.alipay.sofa.registry.server.meta.node.impl.DataNodeServiceImpl; +import com.alipay.sofa.registry.server.meta.node.impl.MetaNodeServiceImpl; +import com.alipay.sofa.registry.server.meta.node.impl.SessionNodeServiceImpl; +import com.alipay.sofa.registry.server.meta.registry.MetaServerRegistry; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import com.alipay.sofa.registry.server.meta.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.meta.remoting.MetaClientExchanger; +import com.alipay.sofa.registry.server.meta.remoting.MetaServerExchanger; +import com.alipay.sofa.registry.server.meta.remoting.RaftExchanger; +import com.alipay.sofa.registry.server.meta.remoting.SessionNodeExchanger; +import com.alipay.sofa.registry.server.meta.remoting.connection.DataConnectionHandler; +import com.alipay.sofa.registry.server.meta.remoting.connection.MetaConnectionHandler; +import com.alipay.sofa.registry.server.meta.remoting.connection.SessionConnectionHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.DataNodeHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.FetchProvideDataRequestHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.GetChangeListRequestHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.GetNodesRequestHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.ReNewNodesRequestHandler; +import com.alipay.sofa.registry.server.meta.remoting.handler.SessionNodeHandler; +import com.alipay.sofa.registry.server.meta.repository.NodeConfirmStatusService; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.repository.VersionRepositoryService; +import com.alipay.sofa.registry.server.meta.repository.annotation.RaftAnnotationBeanPostProcessor; +import com.alipay.sofa.registry.server.meta.repository.service.DataConfirmStatusService; +import com.alipay.sofa.registry.server.meta.repository.service.DataRepositoryService; +import com.alipay.sofa.registry.server.meta.repository.service.MetaRepositoryService; +import com.alipay.sofa.registry.server.meta.repository.service.SessionConfirmStatusService; +import com.alipay.sofa.registry.server.meta.repository.service.SessionRepositoryService; +import com.alipay.sofa.registry.server.meta.repository.service.SessionVersionRepositoryService; +import com.alipay.sofa.registry.server.meta.resource.DecisionModeResource; +import com.alipay.sofa.registry.server.meta.resource.HealthResource; +import com.alipay.sofa.registry.server.meta.resource.MetaDigestResource; +import com.alipay.sofa.registry.server.meta.resource.MetaStoreResource; +import com.alipay.sofa.registry.server.meta.resource.PersistentDataResource; +import com.alipay.sofa.registry.server.meta.resource.StopPushDataResource; +import com.alipay.sofa.registry.server.meta.store.DataStoreService; +import com.alipay.sofa.registry.server.meta.store.MetaStoreService; +import com.alipay.sofa.registry.server.meta.store.SessionStoreService; +import com.alipay.sofa.registry.server.meta.store.StoreService; +import com.alipay.sofa.registry.server.meta.task.processor.DataNodeSingleTaskProcessor; +import com.alipay.sofa.registry.server.meta.task.processor.MetaNodeSingleTaskProcessor; +import com.alipay.sofa.registry.server.meta.task.processor.SessionNodeSingleTaskProcessor; +import com.alipay.sofa.registry.store.api.DBService; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.DefaultTaskListenerManager; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import com.alipay.sofa.registry.util.PropertySplitter; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: MetaServerConfiguration.java, v 0.1 2018-01-12 14:53 shangyu.wh Exp $ + */ +@Configuration +@Import(MetaServerInitializerConfiguration.class) +@EnableConfigurationProperties +public class MetaServerConfiguration { + + @Bean + @ConditionalOnMissingBean + public MetaServerBootstrap metaServerBootstrap() { + return new MetaServerBootstrap(); + } + + @Configuration + protected static class MetaServerConfigBeanConfiguration { + @Bean + @ConditionalOnMissingBean + public MetaServerConfig metaServerConfig() { + return new MetaServerConfigBean(); + } + + @Bean + public NodeConfig nodeConfig() { + return new NodeConfigBeanProperty(); + } + + @Bean(name = "PropertySplitter") + public PropertySplitter propertySplitter() { + return new PropertySplitter(); + } + } + + @Configuration + public static class MetaServerServiceConfiguration { + + @Bean + public Registry metaServerRegistry() { + return new MetaServerRegistry(); + } + + @Bean + public NodeService sessionNodeService() { + return new SessionNodeServiceImpl(); + } + + @Bean + public NodeService dataNodeService() { + return new DataNodeServiceImpl(); + } + + @Bean + public NodeService metaNodeService() { + return new MetaNodeServiceImpl(); + } + + @Bean + public ServiceFactory storeServiceFactory() { + return new ServiceFactory(); + } + + @Bean + public StoreService sessionStoreService() { + return new SessionStoreService(); + } + + @Bean + public StoreService dataStoreService() { + return new DataStoreService(); + } + + @Bean + public StoreService metaStoreService() { + return new MetaStoreService(); + } + + } + + @Configuration + public static class MetaServerRepositoryConfiguration { + @Bean + public RepositoryService dataRepositoryService() { + return new DataRepositoryService(); + } + + @Bean + public RepositoryService metaRepositoryService() { + return new MetaRepositoryService(); + } + + @Bean + public NodeConfirmStatusService dataConfirmStatusService() { + return new DataConfirmStatusService(); + } + + @Bean + public RepositoryService sessionRepositoryService() { + return new SessionRepositoryService(); + } + + @Bean + public VersionRepositoryService sessionVersionRepositoryService() { + return new SessionVersionRepositoryService(); + } + + @Bean + public NodeConfirmStatusService sessionConfirmStatusService() { + return new SessionConfirmStatusService(); + } + + @Bean + public RaftExchanger raftExchanger() { + return new RaftExchanger(); + } + + @Bean + public RaftAnnotationBeanPostProcessor raftAnnotationBeanPostProcessor() { + return new RaftAnnotationBeanPostProcessor(); + } + } + + @Configuration + public static class MetaServerRemotingConfiguration { + + @Bean + public Exchange boltExchange() { + return new BoltExchange(); + } + + @Bean + public Exchange jerseyExchange() { + return new JerseyExchange(); + } + + @Bean(name = "sessionServerHandlers") + public Collection sessionServerHandlers() { + Collection list = new ArrayList<>(); + list.add(sessionConnectionHandler()); + list.add(sessionNodeHandler()); + list.add(reNewNodesRequestHandler()); + list.add(getNodesRequestHandler()); + list.add(fetchProvideDataRequestHandler()); + return list; + } + + @Bean(name = "dataServerHandlers") + public Collection dataServerHandlers() { + Collection list = new ArrayList<>(); + list.add(dataConnectionHandler()); + list.add(getNodesRequestHandler()); + list.add(dataNodeHandler()); + list.add(reNewNodesRequestHandler()); + return list; + } + + @Bean(name = "metaServerHandlers") + public Collection metaServerHandlers() { + Collection list = new ArrayList<>(); + list.add(metaConnectionHandler()); + list.add(getChangeListRequestHandler()); + list.add(getNodesRequestHandler()); + return list; + } + + @Bean + public AbstractServerHandler sessionConnectionHandler() { + return new SessionConnectionHandler(); + } + + @Bean + public AbstractServerHandler dataConnectionHandler() { + return new DataConnectionHandler(); + } + + @Bean + public AbstractServerHandler metaConnectionHandler() { + return new MetaConnectionHandler(); + } + + @Bean + public AbstractServerHandler getChangeListRequestHandler() { + return new GetChangeListRequestHandler(); + } + + @Bean + public AbstractServerHandler getNodesRequestHandler() { + return new GetNodesRequestHandler(); + } + + @Bean + public AbstractServerHandler sessionNodeHandler() { + return new SessionNodeHandler(); + } + + @Bean + public AbstractServerHandler reNewNodesRequestHandler() { + return new ReNewNodesRequestHandler(); + } + + @Bean + public AbstractServerHandler dataNodeHandler() { + return new DataNodeHandler(); + } + + @Bean + public AbstractServerHandler fetchProvideDataRequestHandler() { + return new FetchProvideDataRequestHandler(); + } + + @Bean + public NodeExchanger sessionNodeExchanger() { + return new SessionNodeExchanger(); + } + + @Bean + public NodeExchanger dataNodeExchanger() { + return new DataNodeExchanger(); + } + + @Bean + public NodeExchanger metaServerExchanger() { + return new MetaServerExchanger(); + } + + @Bean + public MetaClientExchanger metaClientExchanger() { + return new MetaClientExchanger(); + } + } + + @Configuration + public static class ResourceConfiguration { + + @Bean + public ResourceConfig jerseyResourceConfig() { + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.register(JacksonFeature.class); + return resourceConfig; + } + + @Bean + public DecisionModeResource decisionModeResource() { + return new DecisionModeResource(); + } + + @Bean + public PersistentDataResource persistentDataResource() { + return new PersistentDataResource(); + } + + @Bean + public MetaDigestResource metaDigestResource() { + return new MetaDigestResource(); + } + + @Bean + public HealthResource healthResource() { + return new HealthResource(); + } + + @Bean + public MetaStoreResource metaStoreResource() { + return new MetaStoreResource(); + } + + @Bean + public StopPushDataResource stopPushDataResource() { + return new StopPushDataResource(); + } + } + + @Configuration + public static class MetaServerTaskConfiguration { + + @Bean + public TaskProcessor dataNodeSingleTaskProcessor() { + return new DataNodeSingleTaskProcessor(); + } + + @Bean + public TaskProcessor metaNodeSingleTaskProcessor() { + return new MetaNodeSingleTaskProcessor(); + } + + @Bean + public TaskProcessor sessionNodeSingleTaskProcessor() { + return new SessionNodeSingleTaskProcessor(); + } + + @Bean + public TaskListener sessionNodeChangePushTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new SessionNodeChangePushTaskListener( + sessionNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener dataNodeChangePushTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new DataNodeChangePushTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener receiveStatusConfirmNotifyTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new ReceiveStatusConfirmNotifyTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener persistenceDataChangeNotifyTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new PersistenceDataChangeNotifyTaskListener( + sessionNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListenerManager taskListenerManager() { + return new DefaultTaskListenerManager(); + } + } + + @Configuration + public static class ExecutorConfiguation { + + @Bean + public ExecutorManager executorManager(MetaServerConfig metaServerConfig) { + return new ExecutorManager(metaServerConfig); + } + + } + + @Configuration + public static class MetaDBConfiguration { + @Bean + public DBService persistenceDataDBService() { + return new PersistenceDataDBService(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerInitializerConfiguration.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerInitializerConfiguration.java new file mode 100644 index 000000000..1add54080 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/MetaServerInitializerConfiguration.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.SmartLifecycle; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author shangyu.wh + * @version $Id: MetaServerInitializerConfiguration.java, v 0.1 2018-01-16 11:27 shangyu.wh Exp $ + */ +public class MetaServerInitializerConfiguration implements SmartLifecycle { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaServerInitializerConfiguration.class); + + private AtomicBoolean running = new AtomicBoolean(false); + + @Autowired + private MetaServerBootstrap metaServerBootstrap; + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void start() { + + try { + metaServerBootstrap.doInitialized(); + LOGGER.info("Started MetaServer"); + + MetaServerInitializerConfiguration.this.running.set(true); + } catch (Exception ex) { + MetaServerInitializerConfiguration.this.running.set(false); + LOGGER.error("Could not initialize Meta server!", ex); + } + + } + + @Override + public void stop() { + this.running.set(false); + metaServerBootstrap.destroy(); + } + + @Override + public boolean isRunning() { + return this.running.get(); + } + + @Override + public int getPhase() { + return 0; + } + + @Override + public void stop(Runnable callback) { + callback.run(); + this.running.set(false); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfig.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfig.java new file mode 100644 index 000000000..dd8814868 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfig.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * + * @author shangyu.wh + * @version $Id: NodeConfig.java, v 0.1 2018-01-23 15:00 shangyu.wh Exp $ + */ +public interface NodeConfig { + + /** + * get other metaServer node + * + * @return + */ + Map> getMetaNode(); + + /** + * get other metaServer node ip + * @return + */ + Map> getMetaNodeIP(); + + /** + * local data Center id + * @return + */ + String getLocalDataCenter(); + + /** + * get dataCenter by meta node ipAddress + * @param metaIpAddress + * @return + */ + String getMetaDataCenter(String metaIpAddress); + + /** + * get datacenter meta servers + * @param dataCenter + * @return + */ + Set getDataCenterMetaServers(String dataCenter); + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfigBeanProperty.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfigBeanProperty.java new file mode 100644 index 000000000..4ee6a06ea --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/NodeConfigBeanProperty.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import org.springframework.beans.factory.annotation.Value; + +import java.util.Collection; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: NodeConfigBeanProperty.java, v 0.1 2018-05-03 16:21 shangyu.wh Exp $ + */ +public class NodeConfigBeanProperty extends AbstractNodeConfigBean { + + @Value("#{PropertySplitter.mapOfList('${nodes.metaNode}')}") + private Map> metaNode; + + @Value("${nodes.localDataCenter}") + private String localDataCenter; + + @Override + public Map> getMetaNode() { + return metaNode; + } + + /** + * Getter method for property localDataCenter. + * + * @return property value of localDataCenter + */ + @Override + public String getLocalDataCenter() { + return localDataCenter; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/ServiceFactory.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/ServiceFactory.java new file mode 100644 index 000000000..656324912 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/bootstrap/ServiceFactory.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.bootstrap; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.server.meta.node.NodeService; +import com.alipay.sofa.registry.server.meta.remoting.connection.NodeConnectManager; +import com.alipay.sofa.registry.server.meta.store.StoreService; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: StoreServiceFactory.java, v 0.1 2018-01-11 22:12 shangyu.wh Exp $ + */ +public class ServiceFactory implements ApplicationContextAware { + + private static Map storeServiceMap = new HashMap<>(); + + private static Map connectManagerMap = new HashMap<>(); + + private static Map nodeServiceMap = new HashMap<>(); + + /** + * get storeservice by node type + * @param nodeType + * @return + */ + public static StoreService getStoreService(NodeType nodeType) { + return storeServiceMap.get(nodeType); + } + + /** + * get node service by node type + * @param nodeType + * @return + */ + public static NodeService getNodeService(NodeType nodeType) { + return nodeServiceMap.get(nodeType); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + + Map map = applicationContext.getBeansOfType(StoreService.class); + + map.forEach((key, value) -> storeServiceMap.put(value.getNodeType(), value)); + + Map managerMap = applicationContext + .getBeansOfType(NodeConnectManager.class); + + managerMap.forEach((key, value) -> connectManagerMap.put(value.getNodeType(), value)); + + Map nodeServiceBeanMap = applicationContext + .getBeansOfType(NodeService.class); + + nodeServiceBeanMap.forEach((key, value) -> nodeServiceMap.put(value.getNodeType(), value)); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/executor/ExecutorManager.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/executor/ExecutorManager.java new file mode 100644 index 000000000..044572398 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/executor/ExecutorManager.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.executor; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import com.alipay.sofa.registry.server.meta.remoting.MetaClientExchanger; +import com.alipay.sofa.registry.server.meta.remoting.RaftExchanger; +import com.alipay.sofa.registry.task.scheduler.TimedSupervisorTask; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ExecutorManager.java, v 0.1 2018-01-16 15:51 shangyu.wh Exp $ + */ +public class ExecutorManager { + + private ScheduledExecutorService scheduler; + + private ThreadPoolExecutor heartbeatCheckExecutor; + + private ThreadPoolExecutor checkDataChangeExecutor; + + private ThreadPoolExecutor getOtherDataCenterChangeExecutor; + + private ThreadPoolExecutor connectMetaServerExecutor; + + private ThreadPoolExecutor checkNodeListChangePushExecutor; + + private ThreadPoolExecutor raftClientRefreshExecutor; + + private MetaServerConfig metaServerConfig; + + @Autowired + private Registry metaServerRegistry; + + @Autowired + private MetaClientExchanger metaClientExchanger; + + @Autowired + private RaftExchanger raftExchanger; + + /** + * constructor + * @param metaServerConfig + */ + public ExecutorManager(MetaServerConfig metaServerConfig) { + this.metaServerConfig = metaServerConfig; + } + + public void init() { + + scheduler = new ScheduledThreadPoolExecutor(6, new NamedThreadFactory("MetaScheduler")); + + heartbeatCheckExecutor = new ThreadPoolExecutor(1, 2, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("MetaScheduler-HeartbeatCheck")); + + checkDataChangeExecutor = new ThreadPoolExecutor(1, 2, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("MetaScheduler-CheckDataChange")); + + getOtherDataCenterChangeExecutor = new ThreadPoolExecutor(1, 2, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory( + "MetaScheduler-GetOtherDataCenterChange")); + + connectMetaServerExecutor = new ThreadPoolExecutor(1, 2, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("MetaScheduler-ConnectMetaServer")); + + checkNodeListChangePushExecutor = new ThreadPoolExecutor(1, 4, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory( + "MetaScheduler-CheckNodeListChangePush")); + + raftClientRefreshExecutor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("MetaScheduler-RaftClientRefresh")); + } + + public void startScheduler() { + + init(); + + scheduler.schedule( + new TimedSupervisorTask("HeartbeatCheck", scheduler, heartbeatCheckExecutor, + metaServerConfig.getSchedulerHeartbeatTimeout(), TimeUnit.SECONDS, + metaServerConfig.getSchedulerHeartbeatExpBackOffBound(), + () -> metaServerRegistry.evict()), + metaServerConfig.getSchedulerHeartbeatFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule(new TimedSupervisorTask("GetOtherDataCenterChange", scheduler, + getOtherDataCenterChangeExecutor, metaServerConfig.getSchedulerGetDataChangeTimeout(), + TimeUnit.SECONDS, metaServerConfig.getSchedulerGetDataChangeExpBackOffBound(), + () -> { + metaServerRegistry.getOtherDataCenterNodeAndUpdate(NodeType.DATA); + metaServerRegistry.getOtherDataCenterNodeAndUpdate(NodeType.META); + }), + metaServerConfig.getSchedulerGetDataChangeFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("ConnectMetaServer", scheduler, connectMetaServerExecutor, + metaServerConfig.getSchedulerConnectMetaServerTimeout(), TimeUnit.SECONDS, + metaServerConfig.getSchedulerConnectMetaServerExpBackOffBound(), + () -> metaClientExchanger.connectServer()), + metaServerConfig.getSchedulerConnectMetaServerFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("CheckSessionNodeListChangePush", scheduler, + checkNodeListChangePushExecutor, + metaServerConfig.getSchedulerCheckNodeListChangePushTimeout(), TimeUnit.SECONDS, + metaServerConfig.getSchedulerCheckNodeListChangePushExpBackOffBound(), + () -> metaServerRegistry.pushNodeListChange(NodeType.SESSION)), + metaServerConfig.getSchedulerCheckNodeListChangePushFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("CheckDataNodeListChangePush", scheduler, + checkNodeListChangePushExecutor, + metaServerConfig.getSchedulerCheckNodeListChangePushTimeout(), TimeUnit.SECONDS, + metaServerConfig.getSchedulerCheckNodeListChangePushExpBackOffBound(), + () -> metaServerRegistry.pushNodeListChange(NodeType.DATA)), + metaServerConfig.getSchedulerCheckNodeListChangePushFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("RaftClientRefresh", scheduler, + raftClientRefreshExecutor, + metaServerConfig.getSchedulerCheckNodeListChangePushTimeout(), TimeUnit.SECONDS, + metaServerConfig.getSchedulerCheckNodeListChangePushExpBackOffBound(), + () -> raftExchanger.refreshRaftClient()), + metaServerConfig.getSchedulerCheckNodeListChangePushFirstDelay(), TimeUnit.SECONDS); + + } + + public void stopScheduler() { + if (scheduler != null && !scheduler.isShutdown()) { + scheduler.shutdown(); + } + + if (heartbeatCheckExecutor != null && !heartbeatCheckExecutor.isShutdown()) { + heartbeatCheckExecutor.shutdown(); + } + + if (checkDataChangeExecutor != null && !checkDataChangeExecutor.isShutdown()) { + checkDataChangeExecutor.shutdown(); + } + + if (connectMetaServerExecutor != null && !connectMetaServerExecutor.isShutdown()) { + connectMetaServerExecutor.shutdown(); + } + + if (getOtherDataCenterChangeExecutor != null + && !getOtherDataCenterChangeExecutor.isShutdown()) { + getOtherDataCenterChangeExecutor.shutdown(); + } + + if (checkNodeListChangePushExecutor != null) { + checkNodeListChangePushExecutor.isShutdown(); + } + + if (raftClientRefreshExecutor != null) { + raftClientRefreshExecutor.isShutdown(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/DataNodeChangePushTaskListener.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/DataNodeChangePushTaskListener.java new file mode 100644 index 000000000..a146d7721 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/DataNodeChangePushTaskListener.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.listener; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.task.Constant; +import com.alipay.sofa.registry.server.meta.task.DataNodeChangePushTask; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeChangePushTaskListener.java, v 0.1 2018-01-24 12:19 shangyu.wh Exp $ + */ +public class DataNodeChangePushTaskListener implements TaskListener { + + private TaskDispatcher dataSingleTaskDispatcher; + + private TaskDispatcher sessionSingleTaskDispatcher; + + @Autowired + private MetaServerConfig metaServerConfig; + + /** + * constructor + * @param dataNodeSingleTaskProcessor + */ + public DataNodeChangePushTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + + dataSingleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.DATA_NODE_CHANGE_PUSH_TASK.getName() + "Data", dataNodeSingleTaskProcessor); + + sessionSingleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.DATA_NODE_CHANGE_PUSH_TASK.getName() + "Session", dataNodeSingleTaskProcessor); + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.DATA_NODE_CHANGE_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + NodeType nodeType = (NodeType) event.getAttribute(Constant.PUSH_TARGET_TYPE); + switch (nodeType) { + case SESSION: + MetaServerTask sessionNodeChangePushTask = new DataNodeChangePushTask( + NodeType.SESSION, metaServerConfig); + sessionNodeChangePushTask.setTaskEvent(event); + sessionSingleTaskDispatcher.dispatch(sessionNodeChangePushTask.getTaskId(), + sessionNodeChangePushTask, sessionNodeChangePushTask.getExpiryTime()); + break; + case DATA: + MetaServerTask dataNodeChangePushTask = new DataNodeChangePushTask(NodeType.DATA, + metaServerConfig); + dataNodeChangePushTask.setTaskEvent(event); + dataSingleTaskDispatcher.dispatch(dataNodeChangePushTask.getTaskId(), + dataNodeChangePushTask, dataNodeChangePushTask.getExpiryTime()); + break; + default: + break; + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/PersistenceDataChangeNotifyTaskListener.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/PersistenceDataChangeNotifyTaskListener.java new file mode 100644 index 000000000..f2e5714ed --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/PersistenceDataChangeNotifyTaskListener.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.listener; + +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.server.meta.task.PersistenceDataChangeNotifyTask; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataCenterChangeNotifyTaskListener.java, v 0.1 2018-02-12 12:26 shangyu.wh Exp $ + */ +public class PersistenceDataChangeNotifyTaskListener implements TaskListener { + + @Autowired + private MetaServerConfig metaServerConfig; + + private TaskDispatcher singleTaskDispatcher; + + /** + * constructor + * @param sessionNodeSingleTaskProcessor + */ + public PersistenceDataChangeNotifyTaskListener(TaskProcessor sessionNodeSingleTaskProcessor) { + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.PERSISTENCE_DATA_CHANGE_NOTIFY_TASK.getName(), sessionNodeSingleTaskProcessor); + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.PERSISTENCE_DATA_CHANGE_NOTIFY_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + MetaServerTask persistenceDataChangeNotifyTask = new PersistenceDataChangeNotifyTask( + metaServerConfig); + persistenceDataChangeNotifyTask.setTaskEvent(event); + singleTaskDispatcher.dispatch(persistenceDataChangeNotifyTask.getTaskId(), + persistenceDataChangeNotifyTask, persistenceDataChangeNotifyTask.getExpiryTime()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/ReceiveStatusConfirmNotifyTaskListener.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/ReceiveStatusConfirmNotifyTaskListener.java new file mode 100644 index 000000000..66b8dbe6b --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/ReceiveStatusConfirmNotifyTaskListener.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.listener; + +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.node.DataNodeService; +import com.alipay.sofa.registry.server.meta.node.NodeService; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.server.meta.task.ReceiveStatusConfirmNotifyTask; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: ReceiveStatusConfirmNotifyTaskListener.java, v 0.1 2018-03-24 17:34 shangyu.wh Exp $ + */ +public class ReceiveStatusConfirmNotifyTaskListener implements TaskListener { + + @Autowired + NodeService dataNodeService; + @Autowired + private MetaServerConfig metaServerConfig; + private TaskDispatcher singleTaskDispatcher; + + /** + * constructor + * @param dataNodeSingleTaskProcessor + */ + public ReceiveStatusConfirmNotifyTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.RECEIVE_STATUS_CONFIRM_NOTIFY_TASK.getName(), dataNodeSingleTaskProcessor); + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.RECEIVE_STATUS_CONFIRM_NOTIFY_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + MetaServerTask receiveStatusConfirmNotifyTask = new ReceiveStatusConfirmNotifyTask( + (DataNodeService) dataNodeService, metaServerConfig); + receiveStatusConfirmNotifyTask.setTaskEvent(event); + singleTaskDispatcher.dispatch(receiveStatusConfirmNotifyTask.getTaskId(), + receiveStatusConfirmNotifyTask, receiveStatusConfirmNotifyTask.getExpiryTime()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/SessionNodeChangePushTaskListener.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/SessionNodeChangePushTaskListener.java new file mode 100644 index 000000000..24dd13e3a --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/listener/SessionNodeChangePushTaskListener.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.listener; + +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.server.meta.task.SessionNodeChangePushTask; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeChangePushTaskListener.java, v 0.1 2018-01-15 14:47 shangyu.wh Exp $ + */ +public class SessionNodeChangePushTaskListener implements TaskListener { + + @Autowired + private MetaServerConfig metaServerConfig; + + private TaskDispatcher singleTaskDispatcher; + + /** + * constructor + * @param sessionNodeSingleTaskProcessor + */ + public SessionNodeChangePushTaskListener(TaskProcessor sessionNodeSingleTaskProcessor) { + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.SESSION_NODE_CHANGE_PUSH_TASK.getName(), sessionNodeSingleTaskProcessor); + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.SESSION_NODE_CHANGE_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + MetaServerTask sessionNodeChangePushTask = new SessionNodeChangePushTask(metaServerConfig); + sessionNodeChangePushTask.setTaskEvent(event); + singleTaskDispatcher.dispatch(sessionNodeChangePushTask.getTaskId(), + sessionNodeChangePushTask, sessionNodeChangePushTask.getExpiryTime()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/DataNodeService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/DataNodeService.java new file mode 100644 index 000000000..9fc3efccc --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/DataNodeService.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.StatusConfirmRequest; + +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeService.java, v 0.1 2018-01-23 19:09 shangyu.wh Exp $ + */ +public interface DataNodeService extends NodeService { + + void pushDataNodes(NodeChangeResult nodeChangeResult, Map targetNodes, + boolean confirm, String confirmNodeIp); + + void notifyStatusConfirm(StatusConfirmRequest statusConfirmRequest); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/MetaNodeService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/MetaNodeService.java new file mode 100644 index 000000000..31fd6bbe1 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/MetaNodeService.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node; + +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.GetChangeListRequest; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNodeService.java, v 0.1 2018-02-12 12:08 shangyu.wh Exp $ + */ +public interface MetaNodeService extends NodeService { + + DataCenterNodes getDataCenterNodes(GetChangeListRequest getChangeListRequest); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeOperator.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeOperator.java new file mode 100644 index 000000000..3270a531e --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeOperator.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: NodeOperator.java, v 0.1 2018-03-28 14:27 shangyu.wh Exp $ + */ +public class NodeOperator implements Serializable { + + private T node; + private DataOperator nodeOperate; + + public NodeOperator(T node, DataOperator nodeOperate) { + this.node = node; + this.nodeOperate = nodeOperate; + } + + /** + * Getter method for property node. + * + * @return property value of node + */ + public T getNode() { + return node; + } + + /** + * Setter method for property node. + * + * @param node value to be assigned to property node + */ + public void setNode(T node) { + this.node = node; + } + + /** + * Getter method for property nodeOperate. + * + * @return property value of nodeOperate + */ + public DataOperator getNodeOperate() { + return nodeOperate; + } + + /** + * Setter method for property nodeOperate. + * + * @param nodeOperate value to be assigned to property nodeOperate + */ + public void setNodeOperate(DataOperator nodeOperate) { + this.nodeOperate = nodeOperate; + } + + @Override + public String toString() { + return "NodeOperator{" + "node=" + node.getNodeUrl().getAddressString() + ", nodeOperate=" + + nodeOperate + '}'; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeService.java new file mode 100644 index 000000000..d96bf5116 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/NodeService.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node; + +import com.alipay.sofa.registry.common.model.Node.NodeType; + +/** + * + * @author shangyu.wh + * @version $Id: NodeService.java, v 0.1 2018-01-24 11:59 shangyu.wh Exp $ + */ +public interface NodeService { + + NodeType getNodeType(); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/SessionNodeService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/SessionNodeService.java new file mode 100644 index 000000000..102f368a6 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/SessionNodeService.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node; + +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; + +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeService.java, v 0.1 2018-01-15 17:00 shangyu.wh Exp $ + */ +public interface SessionNodeService extends NodeService { + + void pushSessions(NodeChangeResult nodeChangeResult, Map targetNodes, + String confirmNodeIp); + + void pushDataNodes(NodeChangeResult nodeChangeResult); + + void notifyProvideDataChange(NotifyProvideDataChange notifyProvideDataChange); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/DataNodeServiceImpl.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/DataNodeServiceImpl.java new file mode 100644 index 000000000..d7bb82df1 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/DataNodeServiceImpl.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node.impl; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.StatusConfirmRequest; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.DataNodeService; +import com.alipay.sofa.registry.server.meta.remoting.connection.NodeConnectManager; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.meta.store.StoreService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeServiceImpl.java, v 0.1 2018-01-23 19:11 shangyu.wh Exp $ + */ +public class DataNodeServiceImpl implements DataNodeService { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeServiceImpl.class); + + @Autowired + private NodeExchanger dataNodeExchanger; + + @Autowired + private StoreService dataStoreService; + + @Autowired + private AbstractServerHandler dataConnectionHandler; + + @Override + public NodeType getNodeType() { + return NodeType.DATA; + } + + @Override + public void pushDataNodes(NodeChangeResult nodeChangeResult, Map targetNodes, + boolean confirm, String confirmNodeIp) { + + if (nodeChangeResult != null) { + + List exceptions = new ArrayList<>(); + + NodeConnectManager nodeConnectManager = getNodeConnectManager(); + + Collection connections = nodeConnectManager.getConnections(null); + + // add register confirm + StoreService storeService = ServiceFactory.getStoreService(NodeType.DATA); + DataCenterNodes dataCenterNodes = storeService.getDataCenterNodes(); + Map registeredNodes = dataCenterNodes.getNodes(); + + if (registeredNodes == null || registeredNodes.isEmpty()) { + LOGGER.error("Push dataNode list error! No data node registered!"); + throw new RuntimeException("Push dataNode list error! No data node registered!"); + } + + for (InetSocketAddress address : connections) { + try { + if (targetNodes != null && !targetNodes.isEmpty()) { + if (!targetNodes.keySet().contains(address.getAddress().getHostAddress())) { + continue; + } + } else { + if (!registeredNodes.keySet().contains( + address.getAddress().getHostAddress())) { + continue; + } + } + + Request nodeChangeRequestRequest = new Request() { + @Override + public NodeChangeResult getRequestBody() { + return nodeChangeResult; + } + + @Override + public URL getRequestUrl() { + return new URL(address); + } + }; + LOGGER.info("pushDataNodes sent url {},node type {}", address, + nodeChangeResult.getNodeType()); + Response response = dataNodeExchanger.request(nodeChangeRequestRequest); + + if (confirm) { + Object result = response.getResult(); + if (result instanceof CommonResponse) { + CommonResponse genericResponse = (CommonResponse) result; + if (genericResponse.isSuccess()) { + confirmStatus(address, confirmNodeIp); + } else { + LOGGER.error("NodeChange notify get response fail!"); + throw new RuntimeException("NodeChange notify get response fail!"); + } + } else { + LOGGER + .error("NodeChange notify has not get response or response type illegal!"); + throw new RuntimeException( + "NodeChange notify has not get response or response type illegal!"); + } + } + + } catch (RequestException e) { + LOGGER.error("Push dataNode list error! " + e.getRequestMessage(), e); + exceptions.add(e); + } catch (RuntimeException e) { + LOGGER.error("Push dataNode list runtime error! ", e); + exceptions.add(e); + } + } + if (!exceptions.isEmpty()) { + throw new RuntimeException( + "DataNodeService push dataNode list error! errors count:" + exceptions.size()); + } + } + } + + @Override + public void notifyStatusConfirm(StatusConfirmRequest statusConfirmRequest) { + try { + + NodeConnectManager nodeConnectManager = getNodeConnectManager(); + Collection connections = nodeConnectManager.getConnections(null); + + for (InetSocketAddress address : connections) { + if (address.getAddress().getHostAddress() + .equals(statusConfirmRequest.getNode().getNodeUrl().getIpAddress())) { + + Request statusConfirmRequestRequest = new Request() { + @Override + public StatusConfirmRequest getRequestBody() { + return statusConfirmRequest; + } + + @Override + public URL getRequestUrl() { + return new URL(address); + } + }; + + dataNodeExchanger.request(statusConfirmRequestRequest); + + break; + } + } + + } catch (RequestException e) { + LOGGER.error("Notify status confirm error! " + e.getRequestMessage(), e); + throw new RuntimeException("Notify status confirm error! ", e); + } + } + + private void confirmStatus(InetSocketAddress address, String confirmNodeIp) { + String ipAddress = address.getAddress().getHostAddress(); + dataStoreService.confirmNodeStatus(ipAddress, confirmNodeIp); + } + + private NodeConnectManager getNodeConnectManager() { + if (!(dataConnectionHandler instanceof NodeConnectManager)) { + LOGGER.error("dataConnectionHandler inject is not NodeConnectManager instance!"); + throw new RuntimeException( + "dataConnectionHandler inject is not NodeConnectManager instance!"); + } + + return (NodeConnectManager) dataConnectionHandler; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/MetaNodeServiceImpl.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/MetaNodeServiceImpl.java new file mode 100644 index 000000000..e0aead477 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/MetaNodeServiceImpl.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node.impl; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.GetChangeListRequest; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.meta.node.MetaNodeService; +import com.alipay.sofa.registry.server.meta.remoting.MetaClientExchanger; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNodeServiceImpl.java, v 0.1 2018-02-12 14:13 shangyu.wh Exp $ + */ +public class MetaNodeServiceImpl implements MetaNodeService { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaNodeServiceImpl.class); + + @Autowired + private MetaClientExchanger metaClientExchanger; + + @Override + public DataCenterNodes getDataCenterNodes(GetChangeListRequest getChangeListRequest) { + try { + Request changeListRequest = new Request() { + + @Override + public GetChangeListRequest getRequestBody() { + return getChangeListRequest; + } + + @Override + public URL getRequestUrl() { + return metaClientExchanger.getDataCenterUrl(getChangeListRequest + .getDataCenterId()); + } + }; + + Response response = metaClientExchanger.request(changeListRequest); + Object result = response.getResult(); + if (result instanceof DataCenterNodes) { + return (DataCenterNodes) result; + } else { + LOGGER.error("getDataCenterNodes has not get response or response type illegal!"); + throw new RuntimeException( + "getDataCenterNodes has not get response or response type illegal!"); + } + + } catch (RequestException e) { + LOGGER.error("MetaNodeService get DataCenter Nodes error! " + e.getRequestMessage(), e); + throw new RuntimeException("MetaNodeService get DataCenter Nodes error! " + + e.getRequestMessage(), e); + } + } + + @Override + public NodeType getNodeType() { + return NodeType.META; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/SessionNodeServiceImpl.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/SessionNodeServiceImpl.java new file mode 100644 index 000000000..9e3da8ab4 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/node/impl/SessionNodeServiceImpl.java @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.node.impl; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.SessionNodeService; +import com.alipay.sofa.registry.server.meta.remoting.connection.NodeConnectManager; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.meta.store.StoreService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeServiceImpl.java, v 0.1 2018-01-15 17:18 shangyu.wh Exp $ + */ +public class SessionNodeServiceImpl implements SessionNodeService { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionNodeServiceImpl.class); + + @Autowired + private NodeExchanger sessionNodeExchanger; + + @Autowired + private StoreService sessionStoreService; + + @Autowired + private MetaServerConfig metaServerConfig; + + @Autowired + private AbstractServerHandler sessionConnectionHandler; + + @Override + public NodeType getNodeType() { + return NodeType.SESSION; + } + + @Override + public void pushSessions(NodeChangeResult nodeChangeResult, + Map sessionNodes, String confirmNodeIp) { + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("SessionNodeServiceImpl pushSessions sessionNodes:{}", nodeChangeResult); + } + NodeConnectManager nodeConnectManager = getNodeConnectManager(); + Collection connections = nodeConnectManager.getConnections(null); + + if (connections.size() == 0) { + LOGGER.warn("there are no client connected on session server port:{}", + metaServerConfig.getSessionServerPort()); + } + + if (sessionNodes == null || sessionNodes.isEmpty()) { + LOGGER.error("Push sessionNode list error! Input sessionNodes can't be null!"); + throw new RuntimeException( + "Push sessionNode list error! Input sessionNodes can't be null!"); + } + + for (InetSocketAddress connection : connections) { + + if (!sessionNodes.keySet().contains(connection.getAddress().getHostAddress())) { + continue; + } + + try { + Request nodeChangeRequest = new Request() { + + @Override + public NodeChangeResult getRequestBody() { + return nodeChangeResult; + } + + @Override + //all connect session + public URL getRequestUrl() { + return new URL(connection); + } + }; + + sessionNodeExchanger.request(nodeChangeRequest); + + //no error confirm receive + sessionStoreService.confirmNodeStatus(connection.getAddress().getHostAddress(), + confirmNodeIp); + + } catch (RequestException e) { + LOGGER.error("Push sessionNode list error! " + e.getRequestMessage(), e); + throw new RuntimeException("SessionNodeService push sessionNode list error!"); + } + } + + } + + @Override + public void pushDataNodes(NodeChangeResult nodeChangeResult) { + + NodeConnectManager nodeConnectManager = getNodeConnectManager(); + Collection connections = nodeConnectManager.getConnections(null); + + if (connections == null || connections.isEmpty()) { + LOGGER.error("Push sessionNode list error! No session node connected!"); + throw new RuntimeException("Push sessionNode list error! No session node connected!"); + } + + // add register confirm + StoreService storeService = ServiceFactory.getStoreService(NodeType.SESSION); + Map sessionNodes = storeService.getNodes(); + + if (sessionNodes == null || sessionNodes.isEmpty()) { + LOGGER.error("Push sessionNode list error! No session node registered!"); + throw new RuntimeException("Push sessionNode list error! No session node registered!"); + } + + for (InetSocketAddress connection : connections) { + + if (!sessionNodes.keySet().contains(connection.getAddress().getHostAddress())) { + continue; + } + + try { + Request nodeChangeRequestRequest = new Request() { + + @Override + public NodeChangeResult getRequestBody() { + return nodeChangeResult; + } + + @Override + public URL getRequestUrl() { + return new URL(connection); + } + }; + + sessionNodeExchanger.request(nodeChangeRequestRequest); + + } catch (RequestException e) { + LOGGER.error("Push sessionNode list error! " + e.getRequestMessage(), e); + throw new RuntimeException("SessionNodeService push dataNode list error!"); + } + } + } + + @Override + public void notifyProvideDataChange(NotifyProvideDataChange notifyProvideDataChange) { + + NodeConnectManager nodeConnectManager = getNodeConnectManager(); + Collection connections = nodeConnectManager.getConnections(null); + + if (connections == null || connections.isEmpty()) { + LOGGER.error("Push sessionNode list error! No session node connected!"); + throw new RuntimeException("Push sessionNode list error! No session node connected!"); + } + + // add register confirm + StoreService storeService = ServiceFactory.getStoreService(NodeType.SESSION); + Map sessionNodes = storeService.getNodes(); + + if (sessionNodes == null || sessionNodes.isEmpty()) { + LOGGER.error("Push sessionNode list error! No session node registered!"); + throw new RuntimeException("Push sessionNode list error! No session node registered!"); + } + + for (InetSocketAddress connection : connections) { + + if (!sessionNodes.keySet().contains(connection.getAddress().getHostAddress())) { + continue; + } + + try { + Request request = new Request() { + + @Override + public NotifyProvideDataChange getRequestBody() { + return notifyProvideDataChange; + } + + @Override + public URL getRequestUrl() { + return new URL(connection); + } + }; + + sessionNodeExchanger.request(request); + + } catch (RequestException e) { + LOGGER.error("Notify provide data change error! " + e.getRequestMessage(), e); + throw new RuntimeException("Notify provide data change error!"); + } + } + } + + private NodeConnectManager getNodeConnectManager() { + if (!(sessionConnectionHandler instanceof NodeConnectManager)) { + LOGGER.error("sessionConnectionHandler inject is not NodeConnectManager instance!"); + throw new RuntimeException( + "sessionConnectionHandler inject is not NodeConnectManager instance!"); + } + + return (NodeConnectManager) sessionConnectionHandler; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/MetaServerRegistry.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/MetaServerRegistry.java new file mode 100644 index 000000000..589c5ce4c --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/MetaServerRegistry.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.registry; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.store.StoreService; + +import java.util.Collection; +import java.util.List; + +/** + * factory func to operate StoreService + * @author shangyu.wh + * @version $Id: MetaServerRegistry.java, v 0.1 2018-01-11 21:38 shangyu.wh Exp $ + */ +public class MetaServerRegistry implements Registry { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaServerRegistry.class); + + @Override + public NodeChangeResult setNodes(List nodes) { + if (nodes == null || nodes.size() == 0) { + throw new IllegalArgumentException("Nodes is empty: " + nodes); + } + StoreService storeService = ServiceFactory.getStoreService(nodes.get(0).getNodeType()); + return storeService.setNodes(nodes); + } + + @Override + public NodeChangeResult register(Node node) { + StoreService storeService = ServiceFactory.getStoreService(node.getNodeType()); + return storeService.addNode(node); + } + + @Override + public void cancel(String connectId, NodeType nodeType) { + StoreService storeService = ServiceFactory.getStoreService(nodeType); + storeService.removeNode(connectId); + } + + @Override + public void evict() { + for (NodeType nodeType : NodeType.values()) { + StoreService storeService = ServiceFactory.getStoreService(nodeType); + if (storeService != null) { + Collection expiredNodes = storeService.getExpired(); + if (expiredNodes != null && !expiredNodes.isEmpty()) { + storeService.removeNodes(expiredNodes); + LOGGER.info("Expired Nodes {} be evicted!", expiredNodes); + } + } + } + } + + @Override + public void reNew(Node node, int duration) { + StoreService storeService = ServiceFactory.getStoreService(node.getNodeType()); + storeService.reNew(node, duration); + } + + @Override + public void getOtherDataCenterNodeAndUpdate(NodeType nodeType) { + StoreService storeService = ServiceFactory.getStoreService(nodeType); + storeService.getOtherDataCenterNodeAndUpdate(); + } + + @Override + public DataCenterNodes getDataCenterNodes(NodeType nodeType) { + StoreService storeService = ServiceFactory.getStoreService(nodeType); + return storeService.getDataCenterNodes(); + } + + @Override + public NodeChangeResult getAllNodes(NodeType nodeType) { + StoreService storeService = ServiceFactory.getStoreService(nodeType); + return storeService.getNodeChangeResult(); + } + + @Override + public void pushNodeListChange(NodeType nodeType) { + StoreService storeService = ServiceFactory.getStoreService(nodeType); + if (storeService != null) { + storeService.pushNodeListChange(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/Registry.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/Registry.java new file mode 100644 index 000000000..2bda79a84 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/registry/Registry.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.registry; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: Registry.java, v 0.1 2018-01-11 17:18 shangyu.wh Exp $ + */ +public interface Registry { + + /** + * replace all nodes + * + * @param nodes + * @return + */ + NodeChangeResult setNodes(List nodes); + + /** + * register new node + * one node unique id by connectId "ip:port" + * @return return dataList + * @param node + */ + NodeChangeResult register(T node); + + /** + * Disconnected node cancel it by connectId + * + * @param connectId "ip:port" + */ + void cancel(String connectId, NodeType nodeType); + + /** + * check and evict all node expired, + */ + void evict(); + + /** + * renew node expire time + * @param node + */ + void reNew(T node, int duration); + + /** + * get other dataCenter Nodes change scheduled + * @param nodeType + */ + void getOtherDataCenterNodeAndUpdate(NodeType nodeType); + + /** + * get DataCenter Nodes list contains version + * @param nodeType + * @return + */ + DataCenterNodes getDataCenterNodes(NodeType nodeType); + + /** + * get all dataCenter Node list by NodeType + * @param nodeType + * @return + */ + NodeChangeResult getAllNodes(NodeType nodeType); + + /** + * push node change result + */ + void pushNodeListChange(NodeType nodeType); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/DataNodeExchanger.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/DataNodeExchanger.java new file mode 100644 index 000000000..1ea35b9b2 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/DataNodeExchanger.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeExchanger.java, v 0.1 2018-01-23 19:18 shangyu.wh Exp $ + */ +public class DataNodeExchanger implements NodeExchanger { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeExchanger.class); + + @Autowired + private MetaServerConfig metaServerConfig; + + @Autowired + private Exchange boltExchange; + + @Override + public Response request(Request request) throws RequestException { + Response response = null; + try { + Server dataServer = boltExchange.getServer(metaServerConfig.getDataServerPort()); + + if (dataServer != null) { + URL url = request.getRequestUrl(); + if (url != null) { + + Channel channel = dataServer.getChannel(url); + + if (channel != null && channel.isConnected()) { + final Object result = dataServer.sendSync(channel, request.getRequestBody(), + metaServerConfig.getDataNodeExchangeTimeout()); + response = () -> result; + } else { + LOGGER.error("DataNode Exchanger get channel error! channel with url:" + url + + " can not be null or disconnected!"); + throw new RequestException( + "DataNode Exchanger get channel error! channel with url:" + url + + " can not be null or disconnected!", + request); + } + } + } + } catch (Exception e) { + LOGGER.error("DataNode Exchanger request data error!", e); + throw new RequestException("DataNode Exchanger request data error!", request, e); + } + return response; + } + + @Override + public Client connectServer() { + return null; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaClientExchanger.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaClientExchanger.java new file mode 100644 index 000000000..4c48f713e --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaClientExchanger.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.store.StoreService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: MetaClientExchanger.java, v 0.1 2018-02-12 17:24 shangyu.wh Exp $ + */ +public class MetaClientExchanger implements NodeExchanger { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaClientExchanger.class); + + @Autowired + private MetaServerConfig metaServerConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private NodeConfig nodeConfig; + + private Map dataCenterUrlMap = new ConcurrentHashMap<>(); + + private static final int RETRY_TIMES = 3; + + @Override + public Response request(Request request) throws RequestException { + Response response; + + try { + Client metaClient = boltExchange.getClient(Exchange.META_SERVER_TYPE); + URL url = request.getRequestUrl(); + + if (metaClient == null) { + LOGGER.warn( + "MetaClient Exchanger get metaServer connection {} error! Connection can not be null or disconnected!", + url); + metaClient = boltExchange.connect(Exchange.META_SERVER_TYPE, url, new ChannelHandler[0]); + } + + Channel channel = metaClient.getChannel(url); + if (channel == null) { + LOGGER.warn("MetaClient Exchanger get channel {} error or disconnected!", url); + channel = metaClient.connect(url); + } + + final Object result = metaClient.sendSync(channel, request.getRequestBody(), + metaServerConfig.getMetaNodeExchangeTimeout()); + response = () -> result; + } catch (Exception e) { + LOGGER.error("MetaClient Exchanger request data error!", e); + throw new RequestException("MetaClient Exchanger request data error!", request, e); + } + + return response; + } + + @Override + public Client connectServer() { + connectOtherMetaServer(); + return null; + } + + /** + * connect other datacenter's metaServer + */ + public void connectOtherMetaServer() { + Map> configMetaNodeIP = nodeConfig.getMetaNodeIP(); + + StoreService storeService = ServiceFactory.getStoreService(NodeType.META); + NodeChangeResult nodeChangeResult = storeService.getNodeChangeResult(); + Map> registerNodes = nodeChangeResult.getNodes(); + + configMetaNodeIP.forEach((dataCenter, ips) -> { + List metaIps = new ArrayList<>(); + if (!nodeConfig.getLocalDataCenter().equalsIgnoreCase(dataCenter)) { + if (registerNodes != null && registerNodes.get(dataCenter) != null) { + Map metaNodeMap = registerNodes.get(dataCenter); + metaIps.addAll(metaNodeMap.keySet()); + } else { + //first not receive other register + metaIps.addAll(ips); + } + Collections.shuffle(metaIps); + String ip = metaIps.iterator().next(); + try { + URL url = new URL(ip, metaServerConfig.getMetaServerPort()); + + Client metaClient = boltExchange.getClient(Exchange.META_SERVER_TYPE); + if (metaClient != null && metaClient.getChannel(url) != null) { + return; + } + + boltExchange.connect(Exchange.META_SERVER_TYPE, url, new ChannelHandler[0]); + dataCenterUrlMap.putIfAbsent(dataCenter, url); + LOGGER.info("Connect other meta server success! url:" + url); + } catch (Exception e) { + LOGGER.error("Connect other meta server error! IP:" + ip, e); + } + } + }); + } + + /** + * get datacenter's meta server url + * @param dataCenter + * @return + */ + public URL getDataCenterUrl(String dataCenter) { + try { + URL url = dataCenterUrlMap.get(dataCenter); + + if (url != null) { + Client metaClient = boltExchange.getClient(Exchange.META_SERVER_TYPE); + if (metaClient != null && metaClient.getChannel(url) != null) { + return url; + } + } + + Map> configMetaNodeIP = nodeConfig.getMetaNodeIP(); + StoreService storeService = ServiceFactory.getStoreService(NodeType.META); + Map> registerNodes = storeService.getNodeChangeResult() + .getNodes(); + + List metaIps = new ArrayList<>(); + if (registerNodes != null && registerNodes.get(dataCenter) != null) { + metaIps.addAll((registerNodes.get(dataCenter)).keySet()); + } else { + //first not receive other register + metaIps.addAll(configMetaNodeIP.get(dataCenter)); + } + Collections.shuffle(metaIps); + String ip = metaIps.iterator().next(); + URL newUrl = new URL(ip, metaServerConfig.getMetaServerPort()); + for (int i = 0; i <= RETRY_TIMES; i++) { + try { + boltExchange.connect(Exchange.META_SERVER_TYPE, newUrl, new ChannelHandler[0]); + + dataCenterUrlMap.put(dataCenter, newUrl); + + LOGGER.info("Connect other meta server success! url:" + newUrl); + } catch (Exception e) { + int remain = RETRY_TIMES - i; + if (remain > 0) { + LOGGER.error("Connect other meta server error!retry time remain {}", + remain, e); + TimeUnit.MILLISECONDS.sleep(1000); + } else { + LOGGER.error("Connect other meta server error!retry all error!", e); + throw new RuntimeException("Connect other meta server error!", e); + } + } + } + return newUrl; + } catch (Exception e) { + LOGGER.error("Get other meta server url error!", e); + throw new RuntimeException("Get other meta server url error!", e); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaServerExchanger.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaServerExchanger.java new file mode 100644 index 000000000..93c0857ee --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/MetaServerExchanger.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNodeExchanger.java, v 0.1 2018-02-12 14:22 shangyu.wh Exp $ + */ +public class MetaServerExchanger implements NodeExchanger { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaServerExchanger.class); + + @Autowired + private MetaServerConfig metaServerConfig; + + @Autowired + private Exchange boltExchange; + + @Override + public Response request(Request request) throws RequestException { + Response response = null; + try { + Server metaServer = boltExchange.getServer(metaServerConfig.getMetaServerPort()); + + if (metaServer != null) { + URL url = request.getRequestUrl(); + if (url != null) { + + Channel channel = metaServer.getChannel(url); + + if (channel != null && channel.isConnected()) { + final Object result = metaServer.sendSync(channel, request.getRequestBody(), + metaServerConfig.getDataNodeExchangeTimeout()); + response = () -> result; + } else { + LOGGER.error("MetaServer Exchanger get channel error! channel with url:" + + url + " can not be null or disconnected!"); + throw new RequestException( + "MetaServer Exchanger get channel error! channel with url:" + url + + " can not be null or disconnected!", + request); + } + } + } + } catch (Exception e) { + LOGGER.error("MetaServer Exchanger request data error!", e); + throw new RequestException("MetaServer Exchanger request data error!", request, e); + } + return response; + } + + @Override + public Client connectServer() { + return null; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/RaftExchanger.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/RaftExchanger.java new file mode 100644 index 000000000..6a35b4b7a --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/RaftExchanger.java @@ -0,0 +1,377 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting; + +import com.alipay.sofa.jraft.CliService; +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.jraft.conf.Configuration; +import com.alipay.sofa.jraft.core.CliServiceImpl; +import com.alipay.sofa.jraft.core.NodeImpl; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.jraft.option.CliOptions; +import com.alipay.sofa.jraft.rpc.impl.AbstractBoltClientService; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.jraft.bootstrap.RaftServer; +import com.alipay.sofa.registry.jraft.bootstrap.RaftServerConfig; +import com.alipay.sofa.registry.jraft.processor.FollowerProcessListener; +import com.alipay.sofa.registry.jraft.processor.LeaderProcessListener; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.executor.ExecutorManager; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: RaftExchanger.java, v 0.1 2018-05-22 15:13 shangyu.wh Exp $ + */ +public class RaftExchanger { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftExchanger.class); + + private static final Logger METRICS_LOGGER = LoggerFactory.getLogger("META-JRAFT-METRICS"); + + @Autowired + private MetaServerConfig metaServerConfig; + + @Autowired + private NodeConfig nodeConfig; + + @Autowired + private Registry metaServerRegistry; + + private RaftServer raftServer; + + private RaftClient raftClient; + + private CliService cliService; + + private AtomicBoolean clientStart = new AtomicBoolean(false); + private AtomicBoolean serverStart = new AtomicBoolean(false); + private AtomicBoolean clsStart = new AtomicBoolean(false); + + /** + * Start Raft server + * @param executorManager + */ + public void startRaftServer(final ExecutorManager executorManager) { + try { + if (serverStart.compareAndSet(false, true)) { + String serverId = NetUtil.genHost(NetUtil.getLocalAddress().getHostAddress(), + metaServerConfig.getRaftServerPort()); + String serverConf = getServerConfig(); + + raftServer = new RaftServer(metaServerConfig.getRaftDataPath(), getGroup(), + serverId, serverConf); + raftServer.setLeaderProcessListener(new LeaderProcessListener() { + @Override + public void startProcess() { + LOGGER.info("Start leader process..."); + executorManager.startScheduler(); + LOGGER.info("Initialize server scheduler success!"); + PeerId leader = new PeerId(NetUtil.getLocalAddress().getHostAddress(), + metaServerConfig.getRaftServerPort()); + raftServer.sendNotify(leader, "leader"); + registerCurrentNode(); + } + + @Override + public void stopProcess() { + LOGGER.info("Stop leader process..."); + executorManager.stopScheduler(); + LOGGER.info("Stop server scheduler success!"); + PeerId leader = new PeerId(NetUtil.getLocalAddress().getHostAddress(), + metaServerConfig.getRaftServerPort()); + raftServer.sendNotify(leader, "leader"); + } + }); + + raftServer.setFollowerProcessListener(new FollowerProcessListener() { + @Override + public void startProcess(PeerId leader) { + LOGGER.info("Start follower process leader {}...", leader); + raftServer.sendNotify(leader, "follower"); + registerCurrentNode(); + } + + @Override + public void stopProcess(PeerId leader) { + LOGGER.info("Stop follower process leader {}...", leader); + raftServer.sendNotify(leader, "follower"); + } + }); + + RaftServerConfig raftServerConfig = new RaftServerConfig(); + raftServerConfig.setMetricsLogger(METRICS_LOGGER); + raftServerConfig.setEnableMetrics(metaServerConfig.isEnableMetrics()); + + raftServer.start(raftServerConfig); + } + } catch (Exception e) { + serverStart.set(false); + LOGGER.error("Start raft server error!", e); + throw new RuntimeException("Start raft server error!", e); + } + } + + /** + * start raft client + */ + public void startRaftClient() { + try { + if (clientStart.compareAndSet(false, true)) { + String serverConf = getServerConfig(); + if (raftServer != null && raftServer.getNode() != null) { + //TODO this cannot be invoke,because RaftAnnotationBeanPostProcessor.getProxy will start first + raftClient = new RaftClient(getGroup(), serverConf, + (AbstractBoltClientService) (((NodeImpl) raftServer.getNode()) + .getRpcService())); + } else { + raftClient = new RaftClient(getGroup(), serverConf); + } + raftClient.start(); + } + } catch (Exception e) { + clientStart.set(false); + LOGGER.error("Start raft client error!", e); + throw new RuntimeException("Start raft client error!", e); + } + } + + /** + * start cli service + */ + public void startCliService() { + if (clsStart.compareAndSet(false, true)) { + try { + cliService = new CliServiceImpl(); + cliService.init(new CliOptions()); + } catch (Exception e) { + LOGGER.error("Start raft cliService error!", e); + throw new RuntimeException("Start raft cliService error!", e); + } + } + } + + private void registerCurrentNode() { + Map> metaMap = nodeConfig.getMetaNodeIP(); + //if current ip existed in config list,register it + if (metaMap != null && metaMap.size() > 0) { + Collection metas = metaMap.get(nodeConfig.getLocalDataCenter()); + String ip = NetUtil.getLocalAddress().getHostAddress(); + if (metas != null && metas.contains(ip)) { + metaServerRegistry.register(new MetaNode(new URL(ip, 0), nodeConfig + .getLocalDataCenter())); + } else { + LOGGER.error( + "Register CurrentNode fail!meta node list config not contains current ip {}", + ip); + throw new RuntimeException( + "Register CurrentNode fail!meta node list config not contains current ip!"); + } + } + } + + /** + * api for change meta node + */ + public void changePeer(List ipAddressList) { + try { + if (cliService != null) { + Configuration peersConf = new Configuration(); + for (String ipAddress : ipAddressList) { + PeerId peer = new PeerId(ipAddress, metaServerConfig.getRaftServerPort()); + peersConf.addPeer(peer); + } + + Status status = cliService.changePeers(getGroup(), getCurrentConfiguration(), + peersConf); + + if (!status.isOk()) { + LOGGER.error("CliService change peer fail!error message {}", + status.getErrorMsg()); + throw new RuntimeException("CliService change peer fail!error message " + + status.getErrorMsg()); + } + } else { + LOGGER.error("cliService can't be null,it must be init first!"); + throw new RuntimeException("cliService can't be null,it must be init first!"); + } + } catch (Exception e) { + LOGGER.error("CliService change peer error!", e); + throw new RuntimeException("CliService change peer error!", e); + } + } + + /** + * api for reset meta node + */ + public void resetPeer(List ipAddressList) { + try { + if (cliService != null) { + Configuration peersConf = new Configuration(); + for (String ipAddress : ipAddressList) { + PeerId peer = new PeerId(ipAddress, metaServerConfig.getRaftServerPort()); + peersConf.addPeer(peer); + } + String ip = NetUtil.getLocalAddress().getHostAddress(); + PeerId localPeer = new PeerId(ip, metaServerConfig.getRaftServerPort()); + Status status = cliService.resetPeer(getGroup(), localPeer, peersConf); + if (!status.isOk()) { + LOGGER.error("CliService reset peer fail!error message {}", + status.getErrorMsg()); + throw new RuntimeException("CliService reset peer fail!error message " + + status.getErrorMsg()); + } + } else { + LOGGER.error("cliService can't be null,it must be init first!"); + throw new RuntimeException("cliService can't be null,it must be init first!"); + } + } catch (Exception e) { + LOGGER.error("CliService reset peer error!", e); + throw new RuntimeException("CliService reset peer error!", e); + } + } + + /** + * api for remove meta node + * @param ipAddress + */ + public void removePeer(String ipAddress) { + try { + if (cliService != null) { + PeerId peer = new PeerId(ipAddress, metaServerConfig.getRaftServerPort()); + Status status = cliService.removePeer(getGroup(), getCurrentConfiguration(), peer); + if (!status.isOk()) { + LOGGER.error("CliService remove peer fail!error message {}", + status.getErrorMsg()); + throw new RuntimeException("CliService remove peer fail!error message " + + status.getErrorMsg()); + } + } else { + LOGGER.error("cliService can't be null,it must be init first!"); + throw new RuntimeException("cliService can't be null,it must be init first!"); + } + } catch (Exception e) { + LOGGER.error("CliService remove peer error!", e); + throw new RuntimeException("CliService remove peer error!", e); + } + } + + /** + * api for get all peers + */ + public List getPeers() { + try { + Configuration currentConf = getCurrentConfiguration(); + return currentConf.getPeers(); + } catch (Exception e) { + String msg = "Get peers error:" + e.getMessage(); + LOGGER.error(msg, e); + throw new RuntimeException(msg, e); + } + } + + private Configuration getCurrentConfiguration() { + return ((NodeImpl) raftServer.getNode()).getCurrentConf(); + } + + /** + * refresh configuration and refresh leader + */ + public void refreshRaftClient() { + raftClient.refreshLeader(); + } + + public void shutdown() { + if (raftServer != null) { + raftServer.shutdown(); + } + if (raftClient != null) { + raftClient.shutdown(); + } + if (cliService != null) { + cliService.shutdown(); + } + } + + private String getServerConfig() { + String ret = ""; + Set ips = nodeConfig.getDataCenterMetaServers(nodeConfig.getLocalDataCenter()); + if (ips != null && !ips.isEmpty()) { + ret = ips.stream().map(ip -> ip + ":" + metaServerConfig.getRaftServerPort()) + .collect(Collectors.joining(",")); + } + if (ret.isEmpty()) { + throw new IllegalArgumentException("Init raft server config error!"); + } + return ret; + } + + private String getGroup() { + return metaServerConfig.getRaftGroup() + "_" + nodeConfig.getLocalDataCenter(); + } + + /** + * Getter method for property raftClient. + * + * @return property value of raftClient + */ + public RaftClient getRaftClient() { + return raftClient; + } + + /** + * Getter method for property clientStart. + * + * @return property value of clientStart + */ + public AtomicBoolean getClientStart() { + return clientStart; + } + + /** + * Getter method for property serverStart. + * + * @return property value of serverStart + */ + public AtomicBoolean getServerStart() { + return serverStart; + } + + /** + * Getter method for property clsStart. + * + * @return property value of clsStart + */ + public AtomicBoolean getClsStart() { + return clsStart; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/SessionNodeExchanger.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/SessionNodeExchanger.java new file mode 100644 index 000000000..eeb677d8b --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/SessionNodeExchanger.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeExchanger.java, v 0.1 2018-01-15 21:21 shangyu.wh Exp $ + */ +public class SessionNodeExchanger implements NodeExchanger { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionNodeExchanger.class); + + @Autowired + private Exchange boltExchange; + + @Autowired + private MetaServerConfig metaServerConfig; + + @Override + public Response request(Request request) throws RequestException { + Response response = null; + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("SessionNodeExchanger request body:{} url:{}", request.getRequestBody(), + request.getRequestUrl()); + } + + Server sessionServer = boltExchange.getServer(metaServerConfig.getSessionServerPort()); + + if (sessionServer != null) { + + Channel channel = sessionServer.getChannel(request.getRequestUrl()); + if (channel != null && channel.isConnected()) { + final Object result = sessionServer.sendSync(channel, request.getRequestBody(), + metaServerConfig.getSessionNodeExchangeTimeout()); + response = () -> result; + } else { + String errorMsg = "SessionNode Exchanger get channel error! channel with url:" + + channel == null ? "" : channel.getRemoteAddress() + " can not be null or disconnected!"; + LOGGER.error(errorMsg); + throw new RequestException(errorMsg, request); + } + + } + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("SessionNodeExchanger response result:{} ", response.getResult()); + } + return response; + } + + @Override + public Client connectServer() { + return null; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/DataConnectionHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/DataConnectionHandler.java new file mode 100644 index 000000000..58f95bee7 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/DataConnectionHandler.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.connection; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Handle data node's connect request + * @author shangyu.wh + * @version $Id: DataConnectionHandler.java, v 0.1 2018-01-24 16:04 shangyu.wh Exp $ + */ +public class DataConnectionHandler extends AbstractServerHandler implements NodeConnectManager { + private Map connections = new ConcurrentHashMap<>(); + + @Override + public void connected(Channel channel) throws RemotingException { + super.connected(channel); + addConnection(channel); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + super.disconnected(channel); + removeConnection(channel); + } + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public void addConnection(Channel channel) { + InetSocketAddress remoteAddress = channel.getRemoteAddress(); + String connectId = NetUtil.toAddressString(remoteAddress); + connections.putIfAbsent(connectId, remoteAddress); + } + + @Override + public boolean removeConnection(Channel channel) { + InetSocketAddress remoteAddress = channel.getRemoteAddress(); + String connectId = NetUtil.toAddressString(remoteAddress); + + return connections.remove(connectId) != null; + } + + @Override + public Collection getConnections(String dataCenter) { + return connections.values(); + } + + @Override + public NodeType getNodeType() { + return NodeType.DATA; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/MetaConnectionHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/MetaConnectionHandler.java new file mode 100644 index 000000000..2e4699278 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/MetaConnectionHandler.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.connection; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Handle meta node's connect request + * @author shangyu.wh + * @version $Id: MetaConnectionHandler.java, v 0.1 2018-02-12 15:01 shangyu.wh Exp $ + */ +public class MetaConnectionHandler extends AbstractServerHandler implements NodeConnectManager { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaConnectionHandler.class); + + @Autowired + private NodeConfig nodeConfig; + + private Map> connections = new ConcurrentHashMap<>(); + + @Override + public void connected(Channel channel) throws RemotingException { + super.connected(channel); + addConnection(channel); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + super.disconnected(channel); + removeConnection(channel); + } + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public void addConnection(Channel channel) { + InetSocketAddress remoteAddress = channel.getRemoteAddress(); + String connectId = NetUtil.toAddressString(remoteAddress); + String ipAddress = remoteAddress.getAddress().getHostAddress(); + + String dataCenter = nodeConfig.getMetaDataCenter(ipAddress); + if (dataCenter != null) { + Map connectMap = connections.get(dataCenter); + if (connectMap == null) { + final Map newMap = new ConcurrentHashMap<>(); + connectMap = connections.putIfAbsent(dataCenter, newMap); + if (connectMap == null) { + connectMap = newMap; + } + } + connectMap.putIfAbsent(connectId, remoteAddress); + } + } + + @Override + public boolean removeConnection(Channel channel) { + InetSocketAddress remoteAddress = channel.getRemoteAddress(); + String connectId = NetUtil.toAddressString(remoteAddress); + String ipAddress = remoteAddress.getAddress().getHostAddress(); + + String dataCenter = nodeConfig.getMetaDataCenter(ipAddress); + if (dataCenter != null) { + Map connectMap = connections.get(dataCenter); + if (connectMap != null) { + connectMap.remove(connectId); + return true; + } + } + return false; + } + + @Override + public Collection getConnections(String dataCenter) { + Map connectMap = connections.get(dataCenter); + if (connectMap == null || connectMap.isEmpty()) { + LOGGER.error("Can not find connection of dataCenter {}", dataCenter); + throw new RuntimeException("Can not find connection of dataCenter:" + dataCenter); + } + return connectMap.values(); + } + + @Override + public NodeType getNodeType() { + return NodeType.META; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/NodeConnectManager.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/NodeConnectManager.java new file mode 100644 index 000000000..fc83092f3 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/NodeConnectManager.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.connection; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.remoting.Channel; + +import java.net.InetSocketAddress; +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: NodeConnectManager.java, v 0.1 2018-01-24 10:57 shangyu.wh Exp $ + */ +public interface NodeConnectManager { + + void addConnection(Channel channel); + + boolean removeConnection(Channel channel); + + Collection getConnections(String dataCenter); + + NodeType getNodeType(); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/SessionConnectionHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/SessionConnectionHandler.java new file mode 100644 index 000000000..49aa5e211 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/connection/SessionConnectionHandler.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.connection; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.meta.remoting.handler.AbstractServerHandler; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Handle session node's connect request + * @author shangyu.wh + * @version $Id: ServerConnectionHandler.java, v 0.1 2018-01-24 11:42 shangyu.wh Exp $ + */ +public class SessionConnectionHandler extends AbstractServerHandler implements NodeConnectManager { + + private Map connections = new ConcurrentHashMap<>(); + + @Override + public void connected(Channel channel) throws RemotingException { + super.connected(channel); + addConnection(channel); + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + super.disconnected(channel); + removeConnection(channel); + } + + @Override + public void addConnection(Channel channel) { + InetSocketAddress remoteAddress = channel.getRemoteAddress(); + String connectId = NetUtil.toAddressString(remoteAddress); + connections.putIfAbsent(connectId, remoteAddress); + } + + @Override + public boolean removeConnection(Channel channel) { + String connectId = NetUtil.toAddressString(channel.getRemoteAddress()); + return connections.remove(connectId) != null; + } + + @Override + public Collection getConnections(String dataCenter) { + return connections.values(); + } + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public NodeType getNodeType() { + return NodeType.SESSION; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/AbstractServerHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/AbstractServerHandler.java new file mode 100644 index 000000000..5bcb55119 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/AbstractServerHandler.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; + +/** + * + * @author shangyu.wh + * @version $Id: ServerHandler.java, v 0.1 2017-11-28 18:06 shangyu.wh Exp $ + */ +public abstract class AbstractServerHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("META-CONNECT"); + + @Override + public void connected(Channel channel) throws RemotingException { + if (channel != null && channel.isConnected()) { + LOGGER.info("Server connected,remote address:" + channel.getRemoteAddress() + + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + if (channel != null && !channel.isConnected()) { + LOGGER.info("Server disconnected,remote address:" + channel.getRemoteAddress() + + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void caught(Channel channel, T message, Throwable exception) { + + } + + @Override + public void received(Channel channel, T message) { + + } + + @Override + public Object reply(Channel channel, T message) { + return null; + } + + @Override + public Class interest() { + return null; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/DataNodeHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/DataNodeHandler.java new file mode 100644 index 000000000..06408669f --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/DataNodeHandler.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handle data node's register request + * @author shangyu.wh + * @version $Id: DataNodeHandler.java, v 0.1 2018-01-18 18:04 shangyu.wh Exp $ + */ +public class DataNodeHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeHandler.class); + + @Autowired + private Registry metaServerRegistry; + + @Override + public Object reply(Channel channel, DataNode dataNode) { + NodeChangeResult nodeChangeResult; + try { + nodeChangeResult = metaServerRegistry.register(dataNode); + LOGGER.info("Data node {} register success!result:{}", dataNode, nodeChangeResult); + } catch (Exception e) { + LOGGER.error("Data node register error!", e); + throw new RuntimeException("Data node register error!", e); + } + return nodeChangeResult; + } + + @Override + public Class interest() { + return DataNode.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/FetchProvideDataRequestHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/FetchProvideDataRequestHandler.java new file mode 100644 index 000000000..cef3777fd --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/FetchProvideDataRequestHandler.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.common.model.ServerDataBox; +import com.alipay.sofa.registry.common.model.console.PersistenceData; +import com.alipay.sofa.registry.common.model.metaserver.FetchProvideDataRequest; +import com.alipay.sofa.registry.common.model.metaserver.ProvideData; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.store.api.DBResponse; +import com.alipay.sofa.registry.store.api.DBService; +import com.alipay.sofa.registry.store.api.OperationStatus; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; + +/** + * Handle session node's query request, such as get ProvideData by dataInfoId + * @author shangyu.wh + * @version $Id: GetNodesRequestHandler.java, v 0.1 2018-03-02 15:12 shangyu.wh Exp $ + */ +public class FetchProvideDataRequestHandler extends AbstractServerHandler { + + private static final Logger DB_LOGGER = LoggerFactory.getLogger( + FetchProvideDataRequestHandler.class, "[DBService]"); + + @RaftReference + private DBService persistenceDataDBService; + + @Override + public Object reply(Channel channel, FetchProvideDataRequest fetchProvideDataRequest) { + try { + DBResponse ret = persistenceDataDBService.get(fetchProvideDataRequest.getDataInfoId()); + if (ret == null) { + DB_LOGGER.error("get null Data from db!"); + throw new RuntimeException("Get null Data from db!"); + } + + if (ret.getOperationStatus() == OperationStatus.SUCCESS) { + PersistenceData data = (PersistenceData) ret.getEntity(); + String dataInfoId = DataInfo.toDataInfoId(data.getDataId(), data.getInstanceId(), + data.getGroup()); + ProvideData provideData = new ProvideData(new ServerDataBox(data.getData()), + dataInfoId, data.getVersion()); + DB_LOGGER.info("get ProvideData {} from DB success!", provideData); + return provideData; + } else if (ret.getOperationStatus() == OperationStatus.NOTFOUND) { + ProvideData provideData = new ProvideData(null, + fetchProvideDataRequest.getDataInfoId(), null); + DB_LOGGER.warn("has not found data from DB dataInfoId:{}", + fetchProvideDataRequest.getDataInfoId()); + return provideData; + } else { + DB_LOGGER.error("get Data DB status error!"); + throw new RuntimeException("Get Data DB status error!"); + } + + } catch (Exception e) { + DB_LOGGER.error("get persistence Data dataInfoId {} from db error!", + fetchProvideDataRequest.getDataInfoId()); + throw new RuntimeException("Get persistence Data from db error!", e); + } + + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return FetchProvideDataRequest.class; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetChangeListRequestHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetChangeListRequestHandler.java new file mode 100644 index 000000000..e373f9fc7 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetChangeListRequestHandler.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.GetChangeListRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handle other datacenter's meta node's request for get the change node list + * @author shangyu.wh + * @version $Id: GetChangeListRequestHandler.java, v 0.1 2018-02-12 16:14 shangyu.wh Exp $ + */ +public class GetChangeListRequestHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("META-CONNECT"); + + @Autowired + private Registry metaServerRegistry; + + @Override + public Object reply(Channel channel, GetChangeListRequest getChangeListRequest) { + DataCenterNodes dataCenterNodes; + try { + dataCenterNodes = metaServerRegistry.getDataCenterNodes(getChangeListRequest + .getNodeType()); + LOGGER.info("Get change Node list {} success!from {}", dataCenterNodes, + channel.getRemoteAddress()); + } catch (Exception e) { + LOGGER.error("Get change Node list error!", e); + throw new RuntimeException("Get change Node list error!", e); + } + return dataCenterNodes; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return GetChangeListRequest.class; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetNodesRequestHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetNodesRequestHandler.java new file mode 100644 index 000000000..916d5c38e --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/GetNodesRequestHandler.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.common.model.metaserver.GetNodesRequest; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handle session/data node's query request, such as getAllNodes request + * and current this is no use for meta node, it's instead by RAFT + * @author shangyu.wh + * @version $Id: GetNodesRequestHandler.java, v 0.1 2018-03-02 15:12 shangyu.wh Exp $ + */ +public class GetNodesRequestHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("META-CONNECT"); + + @Autowired + private Registry metaServerRegistry; + + @Override + public Object reply(Channel channel, GetNodesRequest getNodesRequest) { + NodeChangeResult nodeChangeResult; + try { + nodeChangeResult = metaServerRegistry.getAllNodes(getNodesRequest.getNodeType()); + LOGGER.info("Get {} change node list {} success!from {}", + getNodesRequest.getNodeType(), nodeChangeResult, channel.getRemoteAddress()); + } catch (Exception e) { + LOGGER.error("Get node list error!", e); + throw new RuntimeException("Get node list error!", e); + } + return nodeChangeResult; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return GetNodesRequest.class; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/ReNewNodesRequestHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/ReNewNodesRequestHandler.java new file mode 100644 index 000000000..7425ce141 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/ReNewNodesRequestHandler.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.metaserver.ReNewNodesRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handle session/data node's heartbeat request + * @author shangyu.wh + * @version $Id: ReNewNodesRequestHandler.java, v 0.1 2018-03-30 19:58 shangyu.wh Exp $ + */ +public class ReNewNodesRequestHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(ReNewNodesRequestHandler.class); + + @Autowired + private Registry metaServerRegistry; + + @Override + public Object reply(Channel channel, ReNewNodesRequest reNewNodesRequest) { + Node reNewNode = null; + try { + reNewNode = reNewNodesRequest.getNode(); + metaServerRegistry.reNew(reNewNode, reNewNodesRequest.getDuration()); + } catch (Exception e) { + LOGGER.error("Node " + reNewNode + "reNew error!", e); + throw new RuntimeException("Node reNew error!", e); + } + return null; + } + + @Override + public Class interest() { + return ReNewNodesRequest.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/SessionNodeHandler.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/SessionNodeHandler.java new file mode 100644 index 000000000..f012d76d1 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/remoting/handler/SessionNodeHandler.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.remoting.handler; + +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Handle session node's register request + * @author shangyu.wh + * @version $Id: SessionNodeHandler.java, v 0.1 2018-01-11 17:03 shangyu.wh Exp $ + */ +public class SessionNodeHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionNodeHandler.class); + + @Autowired + private Registry metaServerRegistry; + + @Override + public Object reply(Channel channel, SessionNode sessionNode) { + NodeChangeResult nodeChangeResult; + try { + nodeChangeResult = metaServerRegistry.register(sessionNode); + LOGGER.info("Session node {} register success!", sessionNode); + } catch (Exception e) { + LOGGER.error("Session node register error!", e); + throw new RuntimeException("Session node register error!", e); + } + return nodeChangeResult; + } + + @Override + public Class interest() { + return SessionNode.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeConfirmStatusService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeConfirmStatusService.java new file mode 100644 index 000000000..93615dce1 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeConfirmStatusService.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.server.meta.node.NodeOperator; +import com.alipay.sofa.registry.store.api.annotation.ReadOnLeader; + +import java.util.Collection; +import java.util.Map; +import java.util.Queue; + +/** + * + * @author shangyu.wh + * @version $Id: NodeConfirmStatusService.java, v 0.1 2018-05-15 17:49 shangyu.wh Exp $ + */ +public interface NodeConfirmStatusService { + + void putConfirmNode(T node, DataOperator nodeOperate); + + @ReadOnLeader + NodeOperator peekConfirmNode(); + + NodeOperator pollConfirmNode() throws InterruptedException; + + @ReadOnLeader + Queue getAllConfirmNodes(); + + Map putExpectNodes(T confirmNode, Map addNodes); + + @ReadOnLeader + Map getExpectNodes(T confirmNode); + + Map removeExpectNodes(T confirmNode); + + Map removeExpectConfirmNodes(T confirmNode, Collection ips); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeRepository.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeRepository.java new file mode 100644 index 000000000..cdbde6fd9 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/NodeRepository.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.server.meta.store.RenewDecorate; + +import java.io.Serializable; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: NodeRepository.java, v 0.1 2018-07-20 14:49 shangyu.wh Exp $ + */ +public class NodeRepository implements Serializable { + + /** + * store node list existed dataCenter + */ + private String dataCenter; + + /** + * store node ip list,and it expired info + */ + private Map> nodeMap; + + /** + * store current dataCenter's node list version + */ + private Long version; + + /** + * constructor + * @param dataCenter + * @param nodeMap + * @param version + */ + public NodeRepository(String dataCenter, Map> nodeMap, Long version) { + this.dataCenter = dataCenter; + this.nodeMap = nodeMap; + this.version = version; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + /** + * Setter method for property dataCenter. + * + * @param dataCenter value to be assigned to property dataCenter + */ + public void setDataCenter(String dataCenter) { + this.dataCenter = dataCenter; + } + + /** + * Getter method for property nodeMap. + * + * @return property value of nodeMap + */ + public Map> getNodeMap() { + return nodeMap; + } + + /** + * Setter method for property nodeMap. + * + * @param nodeMap value to be assigned to property nodeMap + */ + public void setNodeMap(Map> nodeMap) { + this.nodeMap = nodeMap; + } + + /** + * Getter method for property version. + * + * @return property value of version + */ + public Long getVersion() { + return version; + } + + /** + * Setter method for property version. + * + * @param version value to be assigned to property version + */ + public void setVersion(Long version) { + this.version = version; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/RepositoryService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/RepositoryService.java new file mode 100644 index 000000000..414325dd6 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/RepositoryService.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository; + +import com.alipay.sofa.registry.store.api.annotation.ReadOnLeader; + +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: RepositoryService.java, v 0.1 2018-05-07 16:03 shangyu.wh Exp $ + */ +public interface RepositoryService { + + V put(K key, V value); + + V remove(Object key); + + V replace(K key, V value); + + @ReadOnLeader + V get(Object key); + + @ReadOnLeader + Map getAllData(); + + @ReadOnLeader + Map> getAllDataMap(); + + @ReadOnLeader + Map getNodeRepositories(); + + Map replaceAll(String dataCenter, Map map, Long version); + + @ReadOnLeader + boolean checkVersion(K key, Long version); + + @ReadOnLeader + Long getVersion(K key); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/VersionRepositoryService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/VersionRepositoryService.java new file mode 100644 index 000000000..f7a3fde8a --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/VersionRepositoryService.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository; + +import com.alipay.sofa.registry.store.api.annotation.ReadOnLeader; + +/** + * + * @author shangyu.wh + * @version $Id: VersionRepositoryService.java, v 0.1 2018-05-11 11:59 shangyu.wh Exp $ + */ +public interface VersionRepositoryService { + + /** + * check current meta server store node Info version change,and notify other meta update dataCenter node info + * @param key such as dataCenterId + * @param version + * @return + */ + boolean checkAndUpdateVersions(K key, Long version); + + @ReadOnLeader + Long getVersion(K key); +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/annotation/RaftAnnotationBeanPostProcessor.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/annotation/RaftAnnotationBeanPostProcessor.java new file mode 100644 index 000000000..4ee37ec1a --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/annotation/RaftAnnotationBeanPostProcessor.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.annotation; + +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.jraft.processor.Processor; +import com.alipay.sofa.registry.jraft.processor.ProxyHandler; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.remoting.RaftExchanger; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import com.alipay.sofa.registry.store.api.annotation.RaftService; +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; + +/** + * + * @author shangyu.wh + * @version $Id: AnnotationBeanPostProcessor.java, v 0.1 2018-05-22 22:44 shangyu.wh Exp $ + */ +public class RaftAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered { + + private static final Logger LOGGER = LoggerFactory + .getLogger(RaftAnnotationBeanPostProcessor.class); + + @Autowired + private RaftExchanger raftExchanger; + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + processRaftReference(bean); + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + processRaftService(bean, beanName); + return bean; + } + + private void processRaftReference(Object bean) { + final Class beanClass = bean.getClass(); + + ReflectionUtils.doWithFields(beanClass, field -> { + RaftReference referenceAnnotation = field.getAnnotation(RaftReference.class); + + if (referenceAnnotation == null) { + return; + } + + Class interfaceType = referenceAnnotation.interfaceType(); + + if (interfaceType.equals(void.class)) { + interfaceType = field.getType(); + } + String serviceId = getServiceId(interfaceType, referenceAnnotation.uniqueId()); + Object proxy = getProxy(interfaceType, serviceId); + ReflectionUtils.makeAccessible(field); + ReflectionUtils.setField(field, bean, proxy); + + }, field -> !Modifier.isStatic(field.getModifiers()) + && field.isAnnotationPresent(RaftReference.class)); + } + + private Object getProxy(Class interfaceType, String serviceId) { + RaftClient client = raftExchanger.getRaftClient(); + if (client == null) { + raftExchanger.startRaftClient(); + LOGGER.info("Raft client before started!"); + } + return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), + new Class[] { interfaceType }, new ProxyHandler(interfaceType, serviceId, + raftExchanger.getRaftClient())); + } + + private void processRaftService(Object bean, String beanName) { + + final Class beanClass = AopProxyUtils.ultimateTargetClass(bean); + + RaftService raftServiceAnnotation = beanClass.getAnnotation(RaftService.class); + + if (raftServiceAnnotation == null) { + return; + } + + Class interfaceType = raftServiceAnnotation.interfaceType(); + + if (interfaceType.equals(void.class)) { + Class[] interfaces = beanClass.getInterfaces(); + + if (interfaces == null || interfaces.length == 0 || interfaces.length > 1) { + throw new RuntimeException( + "Bean " + beanName + + " does not has any interface or has more than one interface."); + } + + interfaceType = interfaces[0]; + } + String serviceUniqueId = getServiceId(interfaceType, raftServiceAnnotation.uniqueId()); + Processor.getInstance().addWorker(serviceUniqueId, interfaceType, bean); + } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + private String getServiceId(Class interfaceType, String uniqueId) { + if (interfaceType == null) { + throw new IllegalArgumentException("Get serviceId error!interfaceType can not be null!"); + } + if (uniqueId != null && !uniqueId.isEmpty()) { + return interfaceType.getName() + ":" + uniqueId; + } else { + return interfaceType.getName(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataConfirmStatusService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataConfirmStatusService.java new file mode 100644 index 000000000..a290669d3 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataConfirmStatusService.java @@ -0,0 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.service; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.node.NodeOperator; +import com.alipay.sofa.registry.server.meta.repository.NodeConfirmStatusService; +import com.alipay.sofa.registry.store.api.annotation.RaftService; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: DataConfirmStatusService.java, v 0.1 2018-05-15 17:53 shangyu.wh Exp $ + */ +@RaftService(uniqueId = "dataServer") +public class DataConfirmStatusService extends AbstractSnapshotProcess + implements + NodeConfirmStatusService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataConfirmStatusService.class); + + /** + * store new data node status,The status can be removed after confirm by all registered other node + */ + private ConcurrentHashMap> expectNodes = new ConcurrentHashMap<>(); + private BlockingQueue expectNodesOrders = new LinkedBlockingQueue(); + + private Set snapShotFileNames = new HashSet<>(); + + private static final String NODE_EXTEND_NAME = "expectNodes"; + + private static final String NODE_ORDERS_EXTEND_NAME = "expectNodesOrders"; + + /** + * constructor + */ + public DataConfirmStatusService() { + } + + /** + * constructor + * @param expectNodes + * @param expectNodesOrders + */ + public DataConfirmStatusService(ConcurrentHashMap> expectNodes, + BlockingQueue expectNodesOrders) { + this.expectNodes = expectNodes; + this.expectNodesOrders = expectNodesOrders; + } + + @Override + public SnapshotProcess copy() { + return new DataConfirmStatusService(new ConcurrentHashMap<>(expectNodes), + new LinkedBlockingQueue<>(expectNodesOrders)); + } + + @Override + public void putConfirmNode(DataNode node, DataOperator nodeOperate) { + try { + expectNodesOrders.put(new NodeOperator(node, nodeOperate)); + LOGGER.info("Put operate:{} node:{} expect be confirm.", nodeOperate, node); + } catch (InterruptedException e) { + LOGGER.error("Put expect status list interrupt!", e); + } + } + + @Override + public NodeOperator peekConfirmNode() { + return expectNodesOrders.peek(); + } + + @Override + public NodeOperator pollConfirmNode() throws InterruptedException { + return expectNodesOrders.poll(1, TimeUnit.SECONDS); + } + + @Override + public Queue getAllConfirmNodes() { + return expectNodesOrders; + } + + @Override + public Map putExpectNodes(DataNode confirmNode, Map addNodes) { + expectNodes.put(confirmNode, addNodes); + LOGGER.info("Put ExpectNodes: expect be confirm {} expectNodes all {}", + confirmNode.getIp(), expectNodes); + return addNodes; + } + + @Override + public Map getExpectNodes(DataNode confirmNode) { + Map map = expectNodes.get(confirmNode); + LOGGER.info("Get ExpectNodes:{} node:{} expect be confirm. expectNodes all {}", map, + confirmNode.getIp(), expectNodes); + return map; + } + + @Override + public Map removeExpectConfirmNodes(DataNode confirmNode, Collection ips) { + Map map = expectNodes.get(confirmNode); + if (map != null) { + if (ips != null && !ips.isEmpty()) { + ips.forEach(ipAddress -> { + DataNode old = map.remove(ipAddress); + if (old == null) { + LOGGER.warn("Get Expect confirmNode ip {} not existed!", ipAddress); + } + }); + } + } else { + LOGGER.warn("Get Expect confirmNode {} not existed!", confirmNode); + } + LOGGER.info("Remove expect confirmNode:{} remove ips:{}. return all {}", confirmNode.getIp(), ips, map); + return map; + } + + @Override + public Map removeExpectNodes(DataNode confirmNode) { + return expectNodes.remove(confirmNode); + } + + @Override + public boolean save(String path) { + if (path == null) { + throw new IllegalArgumentException("Input path can't be null!"); + } + + if (path.endsWith(NODE_ORDERS_EXTEND_NAME)) { + return save(path, expectNodesOrders); + } else { + return save(path, expectNodes); + } + + } + + @Override + public synchronized boolean load(String path) { + try { + if (path == null) { + throw new IllegalArgumentException("Input path can't be null!"); + } + + if (path.endsWith(NODE_ORDERS_EXTEND_NAME)) { + BlockingQueue queue = load(path, expectNodesOrders.getClass()); + expectNodesOrders.clear(); + expectNodesOrders.addAll(queue); + + } else { + ConcurrentHashMap> map = load(path, + expectNodes.getClass()); + expectNodes.clear(); + expectNodes.putAll(map); + } + return true; + } catch (IOException e) { + LOGGER.error("Load confirm expect Nodes data error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(getExtPath(this.getClass().getSimpleName(), NODE_EXTEND_NAME)); + snapShotFileNames.add(getExtPath(this.getClass().getSimpleName(), NODE_ORDERS_EXTEND_NAME)); + return snapShotFileNames; + } + + private String getExtPath(String path, String extentName) { + return path + "_" + extentName; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataRepositoryService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataRepositoryService.java new file mode 100644 index 000000000..716359bb3 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/DataRepositoryService.java @@ -0,0 +1,366 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.service; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.repository.NodeRepository; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.store.RenewDecorate; +import com.alipay.sofa.registry.store.api.annotation.RaftService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: DataRepositoryServcie.java, v 0.1 2018-05-08 13:11 shangyu.wh Exp $ + */ +@RaftService(uniqueId = "dataServer") +public class DataRepositoryService extends AbstractSnapshotProcess + implements + RepositoryService> { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataRepositoryService.class); + + @Autowired + private NodeConfig nodeConfig; + + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock.readLock(); + private final Lock write = readWriteLock + .writeLock(); + + /** + * data node store and version + */ + private Map registry = new ConcurrentHashMap<>(); + + private Set snapShotFileNames = new HashSet<>(); + + /** + * constructor + */ + public DataRepositoryService() { + } + + /** + * constructor + * @param registry + */ + public DataRepositoryService(Map registry) { + this.registry = registry; + } + + @Override + public SnapshotProcess copy() { + return new DataRepositoryService(new ConcurrentHashMap<>(registry)); + } + + @Override + public RenewDecorate put(String ipAddress, RenewDecorate dataNode) { + + write.lock(); + try { + String dataCenter = dataNode.getRenewal().getDataCenter(); + + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository == null) { + NodeRepository nodeRepository = new NodeRepository<>(dataCenter, + new ConcurrentHashMap<>(), System.currentTimeMillis()); + dataNodeRepository = registry.put(dataCenter, nodeRepository); + if (dataNodeRepository == null) { + dataNodeRepository = nodeRepository; + } + } + + dataNodeRepository.setVersion(System.currentTimeMillis()); + + Map> dataNodes = dataNodeRepository + .getNodeMap(); + RenewDecorate oldRenewDecorate = dataNodes.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + LOGGER.info("Data node with ipAddress:" + ipAddress + " has already existed!"); + } + + dataNodes.put(ipAddress, dataNode); + + } catch (Exception e) { + LOGGER.error("Data node add error!", e); + throw new RuntimeException("Data node add error!", e); + } finally { + write.unlock(); + } + + return dataNode; + } + + @Override + public RenewDecorate remove(Object key) { + + write.lock(); + try { + String ipAddress = (String) key; + + String dataCenter = nodeConfig.getLocalDataCenter(); + + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + Map> dataNodes = dataNodeRepository + .getNodeMap(); + if (dataNodes != null) { + RenewDecorate oldRenewDecorate = dataNodes.remove(ipAddress); + if (oldRenewDecorate == null) { + LOGGER.warn("Data node with ipAddress:" + ipAddress + " has not exist!"); + return null; + } + + dataNodeRepository.setVersion(System.currentTimeMillis()); + return oldRenewDecorate; + } + } + return null; + } catch (Exception e) { + LOGGER.error("Data node remove error!", e); + throw new RuntimeException("Data node remove error!", e); + } finally { + write.unlock(); + } + } + + @Override + public RenewDecorate replace(String ipAddress, RenewDecorate dataNode) { + + write.lock(); + try { + String dataCenter = dataNode.getRenewal().getDataCenter(); + + NodeRepository dataNodeRepository = registry.get(dataCenter); + + if (dataNodeRepository != null) { + + Map> dataNodes = dataNodeRepository + .getNodeMap(); + RenewDecorate oldRenewDecorate = dataNodes.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + oldRenewDecorate.setRenewal(dataNode.getRenewal()); + oldRenewDecorate.reNew(); + } else { + LOGGER.error("Data node with ipAddress {} has not existed!", ipAddress); + throw new RuntimeException(String.format( + "Data node with ipAddress %s has not existed!", ipAddress)); + } + } else { + LOGGER.error("Data node in dataCenter: {} has not existed!", dataCenter); + throw new RuntimeException(String.format( + "Data node in dataCenter: %s has not existed!", dataCenter)); + } + + return dataNode; + } catch (Exception e) { + LOGGER.error("Data node replace error!", e); + throw new RuntimeException("Data node replace error!", e); + } finally { + write.unlock(); + } + } + + /** + * this function deal with dataCenter all data,according version and dataMap + * @param dataCenter + * @param map + * @return + */ + @Override + public Map> replaceAll(String dataCenter, + Map> map, + Long version) { + + Map> oldMap; + write.lock(); + try { + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + oldMap = dataNodeRepository.getNodeMap(); + if (oldMap == null) { + LOGGER.warn("Data node in dataCenter: {} has not existed!", dataCenter); + } + dataNodeRepository.setNodeMap(map); + dataNodeRepository.setVersion(version); + return oldMap; + } else { + registry.put(dataCenter, new NodeRepository(dataCenter, map, version)); + return map; + } + } finally { + write.unlock(); + } + } + + @Override + public RenewDecorate get(Object key) { + + read.lock(); + try { + String ipAddress = (String) key; + + String dataCenter = nodeConfig.getLocalDataCenter(); + + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + Map> dataNodes = dataNodeRepository + .getNodeMap(); + if (dataNodes != null) { + RenewDecorate oldRenewDecorate = dataNodes.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + return oldRenewDecorate; + } else { + LOGGER.warn( + "Data node with ipAddress {} has not existed!It not be registered!", + ipAddress); + return null; + } + } else { + LOGGER.warn("Data node map has not existed in dataCenter:{}!", dataCenter); + return null; + } + } else { + LOGGER.error("Data node in dataCenter: {} has not existed!", dataCenter); + throw new RuntimeException(String.format( + "Data node in dataCenter: %s has not existed!", dataCenter)); + } + } catch (Exception e) { + LOGGER.error("Get Data node error!", e); + throw new RuntimeException("Get Data node error!", e); + } finally { + read.unlock(); + } + + } + + @Override + public Map> getAllData() { + read.lock(); + try { + Map> nodes = new ConcurrentHashMap<>(); + registry.forEach((dataCenter, dataNodeRepository) -> nodes.putAll(dataNodeRepository.getNodeMap())); + return nodes; + } finally { + read.unlock(); + } + } + + @Override + public Map>> getAllDataMap() { + Map>> nodes = new ConcurrentHashMap<>(); + read.lock(); + try { + registry.forEach( + (dataCenter, dataNodeRepository) -> nodes.put(dataCenter, dataNodeRepository.getNodeMap())); + return nodes; + } finally { + read.unlock(); + } + } + + @Override + public Map getNodeRepositories() { + return registry; + } + + /** + * Setter method for property nodeConfig. + * + * @param nodeConfig value to be assigned to property nodeConfig + */ + public void setNodeConfig(NodeConfig nodeConfig) { + this.nodeConfig = nodeConfig; + } + + @Override + public boolean save(String path) { + return save(path, registry); + } + + @Override + public synchronized boolean load(String path) { + try { + Map map = load(path, registry.getClass()); + registry.clear(); + registry.putAll(map); + return true; + } catch (IOException e) { + LOGGER.error("Load registry data error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(this.getClass().getSimpleName()); + return snapShotFileNames; + } + + @Override + public boolean checkVersion(String dataCenter, Long version) { + read.lock(); + try { + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + Long oldValue = dataNodeRepository.getVersion(); + if (oldValue == null) { + return true; + } else { + return version > oldValue; + } + } else { + return true; + } + } finally { + read.unlock(); + } + } + + @Override + public Long getVersion(String dataCenter) { + read.lock(); + try { + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + return dataNodeRepository.getVersion(); + } + return null; + } finally { + read.unlock(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/MetaRepositoryService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/MetaRepositoryService.java new file mode 100644 index 000000000..06bb4a26d --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/MetaRepositoryService.java @@ -0,0 +1,350 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.service; + +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.repository.NodeRepository; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.store.RenewDecorate; +import com.alipay.sofa.registry.store.api.annotation.RaftService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: MetaRepositoryService.java, v 0.1 2018-07-30 16:51 shangyu.wh Exp $ + */ +@RaftService(uniqueId = "metaServer") +public class MetaRepositoryService extends AbstractSnapshotProcess + implements + RepositoryService> { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaRepositoryService.class); + + @Autowired + private NodeConfig nodeConfig; + + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock.readLock(); + private final Lock write = readWriteLock + .writeLock(); + + /** + * meta node store and version + */ + private Map registry = new ConcurrentHashMap<>(); + + private Set snapShotFileNames = new HashSet<>(); + + /** + * constructor + */ + public MetaRepositoryService() { + } + + /** + * constructor + * @param registry + */ + public MetaRepositoryService(Map registry) { + this.registry = registry; + } + + @Override + public SnapshotProcess copy() { + return new MetaRepositoryService(new ConcurrentHashMap<>(registry)); + } + + @Override + public RenewDecorate put(String ipAddress, RenewDecorate metaNode) { + write.lock(); + try { + String dataCenter = metaNode.getRenewal().getDataCenter(); + + NodeRepository metaNodeRepository = registry.get(dataCenter); + if (metaNodeRepository == null) { + NodeRepository nodeRepository = new NodeRepository<>(dataCenter, + new ConcurrentHashMap<>(), System.currentTimeMillis()); + metaNodeRepository = registry.put(dataCenter, nodeRepository); + if (metaNodeRepository == null) { + metaNodeRepository = nodeRepository; + } + } + + metaNodeRepository.setVersion(System.currentTimeMillis()); + + Map> metaNodes = metaNodeRepository + .getNodeMap(); + RenewDecorate oldRenewDecorate = metaNodes.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + LOGGER.info("Meta node with ipAddress:" + ipAddress + " has already existed!"); + } + + metaNodes.put(ipAddress, metaNode); + + } catch (Exception e) { + LOGGER.error("Meta node add error!", e); + throw new RuntimeException("Meta node add error!", e); + } finally { + write.unlock(); + } + + return metaNode; + } + + @Override + public RenewDecorate remove(Object key) { + write.lock(); + try { + String ipAddress = (String) key; + + String dataCenter = nodeConfig.getLocalDataCenter(); + + NodeRepository metaNodeRepository = registry.get(dataCenter); + if (metaNodeRepository != null) { + Map> metaNodes = metaNodeRepository + .getNodeMap(); + if (metaNodes != null) { + RenewDecorate oldRenewDecorate = metaNodes.remove(ipAddress); + if (oldRenewDecorate == null) { + LOGGER.warn("Meta node with ipAddress:" + ipAddress + " has not exist!"); + return null; + } + + metaNodeRepository.setVersion(System.currentTimeMillis()); + return oldRenewDecorate; + } + } + return null; + } catch (Exception e) { + LOGGER.error("Meta node remove error!", e); + throw new RuntimeException("Meta node remove error!", e); + } finally { + write.unlock(); + } + } + + @Override + public RenewDecorate replace(String ipAddress, RenewDecorate metaNode) { + write.lock(); + try { + String dataCenter = metaNode.getRenewal().getDataCenter(); + + NodeRepository metaNodeRepository = registry.get(dataCenter); + + if (metaNodeRepository != null) { + Map> dataNodes = metaNodeRepository + .getNodeMap(); + + if (dataNodes != null) { + RenewDecorate oldRenewDecorate = dataNodes.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + oldRenewDecorate.setRenewal(metaNode.getRenewal()); + oldRenewDecorate.reNew(); + + metaNodeRepository.setVersion(System.currentTimeMillis()); + } else { + LOGGER.error("Meta node with ipAddress {} has not existed!", ipAddress); + throw new RuntimeException(String.format( + "Meta node with ipAddress %s has not existed!", ipAddress)); + } + } else { + LOGGER.error("Meta node in dataCenter {} has not existed!", dataCenter); + throw new RuntimeException(String.format( + "Meta node in dataCenter %s has not existed!", dataCenter)); + } + } else { + LOGGER.error("Meta node in dataCenter: {} has not existed!", dataCenter); + throw new RuntimeException(String.format( + "Meta node in dataCenter: %s has not existed!", dataCenter)); + } + + return metaNode; + } catch (Exception e) { + LOGGER.error("Data node replace error!", e); + throw new RuntimeException("Data node replace error!", e); + } finally { + write.unlock(); + } + } + + @Override + public Map> replaceAll(String dataCenter, + Map> map, + Long version) { + Map> oldMap; + write.lock(); + try { + + NodeRepository metaNodeRepository = registry.get(dataCenter); + if (metaNodeRepository != null) { + oldMap = metaNodeRepository.getNodeMap(); + if (oldMap == null) { + LOGGER.warn("Meta node in dataCenter: {} has not existed!", dataCenter); + } + metaNodeRepository.setNodeMap(map); + metaNodeRepository.setVersion(version); + return oldMap; + } else { + registry.put(dataCenter, new NodeRepository(dataCenter, map, version)); + return map; + } + } finally { + write.unlock(); + } + } + + @Override + public RenewDecorate get(Object key) { + read.lock(); + try { + String ipAddress = (String) key; + + String dataCenter = nodeConfig.getLocalDataCenter(); + + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + Map> metaNodes = dataNodeRepository + .getNodeMap(); + if (metaNodes == null) { + LOGGER.error("Meta node in dataCenter: {} has not existed!", dataCenter); + throw new RuntimeException(String.format( + "Meta node in dataCenter: %s has not existed!", dataCenter)); + } + RenewDecorate oldRenewDecorate = metaNodes.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + return oldRenewDecorate; + } else { + LOGGER.warn( + "Meta node with ipAddress {} has not existed!It not be registered!", + ipAddress); + return null; + } + } else { + LOGGER.error("Meta node in dataCenter: {} has not existed!", dataCenter); + throw new RuntimeException(String.format( + "Meta node in dataCenter: %s has not existed!", dataCenter)); + } + } catch (Exception e) { + LOGGER.error("Get meta node error!", e); + throw new RuntimeException("Get meta node error!", e); + } finally { + read.unlock(); + } + } + + @Override + public Map> getAllData() { + read.lock(); + try { + Map> nodes = new ConcurrentHashMap<>(); + registry.forEach((dataCenter, metaNodeRepository) -> nodes.putAll(metaNodeRepository.getNodeMap())); + return nodes; + } finally { + read.unlock(); + } + } + + @Override + public Map>> getAllDataMap() { + Map>> nodes = new ConcurrentHashMap<>(); + read.lock(); + try { + registry.forEach( + (dataCenter, metaNodeRepository) -> nodes.put(dataCenter, metaNodeRepository.getNodeMap())); + return nodes; + } finally { + read.unlock(); + } + } + + @Override + public Map getNodeRepositories() { + return registry; + } + + @Override + public boolean checkVersion(String dataCenter, Long version) { + read.lock(); + try { + NodeRepository metaNodeRepository = registry.get(dataCenter); + if (metaNodeRepository != null) { + Long oldValue = metaNodeRepository.getVersion(); + return oldValue == null || version > oldValue; + } else { + return true; + } + } finally { + read.unlock(); + } + } + + @Override + public Long getVersion(String dataCenter) { + read.lock(); + try { + NodeRepository dataNodeRepository = registry.get(dataCenter); + if (dataNodeRepository != null) { + return dataNodeRepository.getVersion(); + } + return null; + } finally { + read.unlock(); + } + } + + @Override + public boolean save(String path) { + return save(path, registry); + } + + @Override + public synchronized boolean load(String path) { + try { + Map map = load(path, registry.getClass()); + registry.clear(); + registry.putAll(map); + return true; + } catch (IOException e) { + LOGGER.error("Load registry meta error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(this.getClass().getSimpleName()); + return snapShotFileNames; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionConfirmStatusService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionConfirmStatusService.java new file mode 100644 index 000000000..325c35482 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionConfirmStatusService.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.service; + +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.node.NodeOperator; +import com.alipay.sofa.registry.server.meta.repository.NodeConfirmStatusService; +import com.alipay.sofa.registry.store.api.annotation.RaftService; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: DataConfirmStatusService.java, v 0.1 2018-05-15 17:53 shangyu.wh Exp $ + */ +@RaftService(uniqueId = "sessionServer") +public class SessionConfirmStatusService extends AbstractSnapshotProcess + implements + NodeConfirmStatusService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionConfirmStatusService.class); + + /** + * store new data node status,The status can be removed after confirm by all registered other node + */ + private ConcurrentHashMap> expectNodes = new ConcurrentHashMap<>(); + private BlockingQueue expectNodesOrders = new LinkedBlockingQueue(); + + private Set snapShotFileNames = new HashSet<>(); + + private static final String NODE_EXTEND_NAME = "expectNodes"; + + private static final String NODE_ORDERS_EXTEND_NAME = "expectNodesOrders"; + + /** + * constructor + */ + public SessionConfirmStatusService() { + } + + /** + * constructor + * @param expectNodes + * @param expectNodesOrders + */ + public SessionConfirmStatusService(ConcurrentHashMap> expectNodes, + BlockingQueue expectNodesOrders) { + this.expectNodes = expectNodes; + this.expectNodesOrders = expectNodesOrders; + } + + @Override + public SnapshotProcess copy() { + return new SessionConfirmStatusService(new ConcurrentHashMap<>(expectNodes), + new LinkedBlockingQueue<>(expectNodesOrders)); + } + + @Override + public void putConfirmNode(SessionNode node, DataOperator nodeOperate) { + try { + expectNodesOrders.put(new NodeOperator(node, nodeOperate)); + LOGGER.info("Put operate:{} node:{} expect be confirm.", nodeOperate, node); + } catch (InterruptedException e) { + LOGGER.error("Put expect status list interrupt!", e); + } + } + + @Override + public NodeOperator peekConfirmNode() { + return expectNodesOrders.peek(); + } + + @Override + public NodeOperator pollConfirmNode() throws InterruptedException { + return expectNodesOrders.poll(1, TimeUnit.SECONDS); + } + + @Override + public Queue getAllConfirmNodes() { + return expectNodesOrders; + } + + @Override + public Map putExpectNodes(SessionNode confirmNode, + Map addNodes) { + expectNodes.put(confirmNode, addNodes); + LOGGER.info("Put ExpectNodes:{} node:{} expect be confirm.expectNodes all {}", addNodes, + confirmNode, expectNodes); + return addNodes; + } + + @Override + public Map getExpectNodes(SessionNode confirmNode) { + Map map = expectNodes.get(confirmNode); + LOGGER.info("Get ExpectNodes:{} node:{} expect be confirm. expectNodes all {}", map, + confirmNode, expectNodes); + return map; + } + + @Override + public Map removeExpectNodes(SessionNode confirmNode) { + return expectNodes.remove(confirmNode); + } + + @Override + public Map removeExpectConfirmNodes(SessionNode confirmNode, Collection ips) { + + Map map = expectNodes.get(confirmNode); + if (map != null) { + if (ips != null && !ips.isEmpty()) { + ips.forEach(ipAddress -> { + SessionNode old = map.remove(ipAddress); + if (old == null) { + LOGGER.warn("Get Expect confirmNode ip {} not existed!", ipAddress); + } + }); + } + } else { + LOGGER.warn("Get Expect confirmNode {} not existed!", confirmNode); + } + LOGGER.info("Remove expect confirmNode:{} ips:{}. return all {}", confirmNode, ips, map); + return map; + } + + @Override + public boolean save(String path) { + if (path == null) { + throw new IllegalArgumentException("Input path can't be null!"); + } + + if (path.endsWith(NODE_ORDERS_EXTEND_NAME)) { + return save(path, expectNodesOrders); + } else { + return save(path, expectNodes); + } + + } + + @Override + public synchronized boolean load(String path) { + try { + if (path == null) { + throw new IllegalArgumentException("Input path can't be null!"); + } + + if (path.endsWith(NODE_ORDERS_EXTEND_NAME)) { + BlockingQueue queue = load(path, expectNodesOrders.getClass()); + expectNodesOrders.clear(); + expectNodesOrders.addAll(queue); + + } else { + ConcurrentHashMap> map = load(path, + expectNodes.getClass()); + expectNodes.clear(); + expectNodes.putAll(map); + } + return true; + } catch (IOException e) { + LOGGER.error("Load confirm expect Nodes data error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(getExtPath(this.getClass().getSimpleName(), NODE_EXTEND_NAME)); + snapShotFileNames.add(getExtPath(this.getClass().getSimpleName(), NODE_ORDERS_EXTEND_NAME)); + return snapShotFileNames; + } + + private String getExtPath(String path, String extentName) { + return path + "_" + extentName; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionRepositoryService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionRepositoryService.java new file mode 100644 index 000000000..4a4f4d10f --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionRepositoryService.java @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.service; + +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.repository.NodeRepository; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.store.RenewDecorate; +import com.alipay.sofa.registry.store.api.annotation.RaftService; +import org.springframework.beans.factory.annotation.Autowired; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: SessionRepositoryService.java, v 0.1 2018-05-08 13:11 shangyu.wh Exp $ + */ +@RaftService(uniqueId = "sessionServer") +public class SessionRepositoryService extends AbstractSnapshotProcess + implements + RepositoryService> { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionRepositoryService.class); + + @Autowired + private NodeConfig nodeConfig; + + /** + * session node store + */ + private ConcurrentHashMap> registry = new ConcurrentHashMap<>(); + + private Set snapShotFileNames = new HashSet<>(); + + /** + * constructor + */ + public SessionRepositoryService() { + } + + /** + * constructor + * @param registry + */ + public SessionRepositoryService(ConcurrentHashMap> registry) { + this.registry = registry; + } + + @Override + public SnapshotProcess copy() { + return new SessionRepositoryService(new ConcurrentHashMap<>(registry)); + } + + @Override + public RenewDecorate put(String ipAddress, RenewDecorate sessionNode) { + try { + RenewDecorate oldRenewDecorate = registry.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + LOGGER.info("Session node with connectId:" + ipAddress + " has already existed!"); + } + registry.put(ipAddress, sessionNode); + LOGGER.info("Put session node {} ok", ipAddress); + } catch (Exception e) { + LOGGER.error("Session node add error!", e); + throw new RuntimeException("Session node add error!", e); + } + return sessionNode; + } + + @Override + public RenewDecorate remove(Object key) { + try { + String ipAddress = (String) key; + RenewDecorate oldRenewDecorate = registry.remove(ipAddress); + if (oldRenewDecorate == null) { + LOGGER + .info("Remove Session node with ipAddress:" + ipAddress + " has not existed!"); + return null; + } + return oldRenewDecorate; + } catch (Exception e) { + LOGGER.error("Data Session remove error!", e); + throw new RuntimeException("Session node remove error!", e); + } + } + + @Override + public RenewDecorate replace(String ipAddress, + RenewDecorate sessionNode) { + RenewDecorate oldRenewDecorate = registry.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + oldRenewDecorate.setRenewal(sessionNode.getRenewal()); + oldRenewDecorate.reNew(); + } else { + LOGGER.error("Session node with ipAddress {} has not existed!", ipAddress); + throw new RuntimeException(String.format( + "Session node with ipAddress %s has not existed!", ipAddress)); + } + return sessionNode; + } + + @Override + public RenewDecorate get(Object key) { + try { + String ipAddress = (String) key; + RenewDecorate oldRenewDecorate = registry.get(ipAddress); + if (oldRenewDecorate != null && oldRenewDecorate.getRenewal() != null) { + return oldRenewDecorate; + } else { + LOGGER.warn("Session node with ipAddress {} has not existed!It not be registered!", + ipAddress); + return null; + } + } catch (Exception e) { + LOGGER.error("Get Session node error!", e); + throw new RuntimeException("Get Session node error!", e); + } + } + + @Override + public Map> getAllData() { + return registry; + } + + @Override + public Map>> getAllDataMap() { + Map>> map = new ConcurrentHashMap<>(); + map.put(nodeConfig.getLocalDataCenter(), registry); + return map; + } + + @Override + public Map> replaceAll(String dataCenter, + Map> map, + Long version) { + return null; + } + + @Override + public Map getNodeRepositories() { + Map map = new ConcurrentHashMap<>(); + map.put(nodeConfig.getLocalDataCenter(), new NodeRepository( + nodeConfig.getLocalDataCenter(), registry, System.currentTimeMillis())); + return map; + } + + @Override + public boolean save(String path) { + return save(path, registry); + } + + @Override + public synchronized boolean load(String path) { + try { + ConcurrentHashMap> map = load(path, + registry.getClass()); + registry.clear(); + registry.putAll(map); + return true; + } catch (IOException e) { + LOGGER.error("Load registry data error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(this.getClass().getSimpleName()); + return snapShotFileNames; + } + + @Override + public boolean checkVersion(String key, Long version) { + return false; + } + + @Override + public Long getVersion(String key) { + return null; + } + + /** + * Setter method for property nodeConfig. + * + * @param nodeConfig value to be assigned to property nodeConfig + */ + public void setNodeConfig(NodeConfig nodeConfig) { + this.nodeConfig = nodeConfig; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionVersionRepositoryService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionVersionRepositoryService.java new file mode 100644 index 000000000..2c9db10c4 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/repository/service/SessionVersionRepositoryService.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.repository.service; + +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.repository.VersionRepositoryService; +import com.alipay.sofa.registry.store.api.annotation.RaftService; +import com.alipay.sofa.registry.util.VersionsMapUtils; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: DataVersionRepositoryService.java, v 0.1 2018-05-11 12:10 shangyu.wh Exp $ + */ +@RaftService(uniqueId = "sessionServer") +public class SessionVersionRepositoryService extends AbstractSnapshotProcess + implements + VersionRepositoryService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionVersionRepositoryService.class); + /** + * store dataCenter session list version,now just local dataCenter version + */ + private ConcurrentHashMap dataCenterListVersions = new ConcurrentHashMap(); + + private Set snapShotFileNames = new HashSet<>(); + + /** + * constructor + */ + public SessionVersionRepositoryService() { + } + + /** + * constructor + * @param dataCenterListVersions + */ + public SessionVersionRepositoryService(ConcurrentHashMap dataCenterListVersions) { + this.dataCenterListVersions = dataCenterListVersions; + } + + @Override + public SnapshotProcess copy() { + return new SessionVersionRepositoryService(new ConcurrentHashMap<>(dataCenterListVersions)); + } + + @Override + public boolean checkAndUpdateVersions(String dataCenterId, Long version) { + return VersionsMapUtils.checkAndUpdateVersions(dataCenterListVersions, dataCenterId, + version); + } + + @Override + public Long getVersion(String dataCenterId) { + return dataCenterListVersions.get(dataCenterId); + } + + @Override + public boolean save(String path) { + return save(path, dataCenterListVersions); + } + + @Override + public synchronized boolean load(String path) { + try { + ConcurrentHashMap map = load(path, dataCenterListVersions.getClass()); + dataCenterListVersions.clear(); + dataCenterListVersions.putAll(map); + return true; + } catch (IOException e) { + LOGGER.error("Load dataCenter versions data error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(this.getClass().getSimpleName()); + return snapShotFileNames; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/DecisionModeResource.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/DecisionModeResource.java new file mode 100644 index 000000000..b78f9ccaf --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/DecisionModeResource.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.resource; + +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig.DecisionMode; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfigBean; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author shangyu.wh + * @version $Id: DecisionModeResource.java, v 0.1 2018-02-01 16:50 shangyu.wh Exp $ + */ +@Path("decisionMode") +public class DecisionModeResource { + + @Autowired + private MetaServerConfig metaServerConfig; + + @POST + @Produces(MediaType.APPLICATION_JSON) + public Result changeDecisionMode(DecisionMode decisionMode) { + ((MetaServerConfigBean) metaServerConfig).setDecisionMode(decisionMode); + Result result = new Result(); + result.setSuccess(true); + return result; + } + +} diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/HealthResource.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/HealthResource.java new file mode 100644 index 000000000..8e6970390 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/HealthResource.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.resource; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.jraft.bootstrap.ServiceStateMachine; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerBootstrap; +import com.alipay.sofa.registry.server.meta.remoting.RaftExchanger; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author shangyu.wh + * @version $Id: PushSwitchResource.java, v 0.1 2018-10-29 16:51 shangyu.wh Exp $ + */ +@Path("health") +public class HealthResource { + + @Autowired + private MetaServerBootstrap metaServerBootstrap; + + @Autowired + private RaftExchanger raftExchanger; + + @GET + @Path("check") + @Produces(MediaType.APPLICATION_JSON) + public CommonResponse checkHealth() { + + CommonResponse response; + + StringBuilder sb = new StringBuilder("MetaServerBoot "); + + boolean start = metaServerBootstrap.getSessionStart().get(); + boolean ret = start; + sb.append("sessionRegisterServer:").append(start); + + start = metaServerBootstrap.getDataStart().get(); + ret = ret && start; + sb.append(", dataRegisterServerStart:").append(start); + + start = metaServerBootstrap.getMetaStart().get(); + ret = ret && start; + sb.append(", otherMetaRegisterServerStart:").append(start); + + start = metaServerBootstrap.getHttpStart().get(); + ret = ret && start; + sb.append(", httpServerStart:").append(start); + + start = raftExchanger.getServerStart().get(); + ret = ret && start; + sb.append(", raftServerStart:").append(start); + + start = raftExchanger.getClientStart().get(); + ret = ret && start; + sb.append(", raftClientStart:").append(start); + + start = raftExchanger.getClsStart().get(); + ret = ret && start; + sb.append(", raftManagerStart:").append(start); + + start = ServiceStateMachine.getInstance().isLeader() + || ServiceStateMachine.getInstance().isfollower(); + ret = ret && start; + + if (ServiceStateMachine.getInstance().isLeader()) { + + sb.append(", raftStatus:").append("Leader"); + } else if (ServiceStateMachine.getInstance().isfollower()) { + sb.append(", raftStatus:").append("Follower"); + } else { + sb.append(", raftStatus:").append(start); + } + + if (ret) { + response = CommonResponse.buildSuccessResponse(sb.toString()); + } else { + response = CommonResponse.buildFailedResponse(sb.toString()); + } + + return response; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaDigestResource.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaDigestResource.java new file mode 100644 index 000000000..538614f15 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaDigestResource.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.resource; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.console.PersistenceData; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import com.alipay.sofa.registry.store.api.DBResponse; +import com.alipay.sofa.registry.store.api.DBService; +import com.alipay.sofa.registry.store.api.OperationStatus; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: MetaDigestResource.java, v 0.1 2018-06-25 21:13 shangyu.wh Exp $ + */ +@Path("digest") +public class MetaDigestResource { + + private static final Logger TASK_LOGGER = LoggerFactory.getLogger(MetaDigestResource.class, + "[Resource]"); + + private static final Logger DB_LOGGER = LoggerFactory.getLogger(MetaDigestResource.class, + "[DBService]"); + + @Autowired + private Registry metaServerRegistry; + + @RaftReference + private DBService persistenceDataDBService; + + @GET + @Path("{type}/node/query") + @Produces(MediaType.APPLICATION_JSON) + public Map getRegisterNodeByType(@PathParam("type") String type) { + try { + NodeChangeResult nodeChangeResult = metaServerRegistry.getAllNodes(NodeType + .valueOf(type.toUpperCase())); + return nodeChangeResult.getNodes(); + } catch (Exception e) { + TASK_LOGGER.error("Fail get Register Node By Type {} !", type, e); + throw new RuntimeException("Fail get Register Node By Type" + type, e); + } + } + + /** + * return true mean push switch on + */ + @GET + @Path("pushSwitch") + @Produces(MediaType.APPLICATION_JSON) + public Map getPushSwitch() { + Map resultMap = new HashMap<>(1); + try { + DBResponse ret = persistenceDataDBService + .get(ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID); + + if (ret == null) { + //default push switch on + resultMap.put("pushSwitch", "open"); + resultMap.put("msg", "get null Data from db!"); + } else { + if (ret.getOperationStatus() == OperationStatus.SUCCESS) { + PersistenceData data = (PersistenceData) ret.getEntity(); + String result = data.getData(); + if (result != null && !result.isEmpty()) { + resultMap.put("pushSwitch", "false".equalsIgnoreCase(result) ? "open" + : "closed"); + } else { + resultMap.put("pushSwitch", "open"); + resultMap.put("msg", "data is empty"); + } + } else if (ret.getOperationStatus() == OperationStatus.NOTFOUND) { + resultMap.put("pushSwitch", "open"); + resultMap.put("msg", "OperationStatus is NOTFOUND"); + } else { + DB_LOGGER.error("get Data DB status error!"); + throw new RuntimeException("Get Data DB status error!"); + } + } + DB_LOGGER.info("getPushSwitch: {}", resultMap); + } catch (Exception e) { + DB_LOGGER.error("get persistence Data dataInfoId {} from db error!", + ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID, e); + throw new RuntimeException("Get persistence Data from db error!", e); + } + + return resultMap; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaStoreResource.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaStoreResource.java new file mode 100644 index 000000000..851b50e93 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/MetaStoreResource.java @@ -0,0 +1,216 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.resource; + +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.registry.Registry; +import com.alipay.sofa.registry.server.meta.remoting.RaftExchanger; +import com.google.common.collect.Lists; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.FormParam; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: MetaStoreResource.java, v 0.1 2018-07-30 18:55 shangyu.wh Exp $ + */ +@Path("manage") +public class MetaStoreResource { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaStoreResource.class); + + @Autowired + private Registry metaServerRegistry; + + @Autowired + private NodeConfig nodeConfig; + + @Autowired + private RaftExchanger raftExchanger; + + /** + * set node list in raft + */ + @POST + @Path("changePeer") + @Produces(MediaType.APPLICATION_JSON) + public Result changePeer(@FormParam("ipAddressList") String ipAddressList) { + Result result = new Result(); + result.setSuccess(false); + + List ipAddressList0 = null; + if (StringUtils.isNotBlank(ipAddressList)) { + String[] ipAddressArr = StringUtils.split(StringUtils.trim(ipAddressList), ','); + if (ipAddressArr != null) { + ipAddressList0 = Lists.newArrayList(ipAddressArr); + } + } + if (ipAddressList0 == null || ipAddressList0.size() <= 0) { + String msg = String.format("Empty ipAddressList from input: %s", ipAddressList); + LOGGER.error(msg); + result.setMessage(msg); + return result; + } + + //domain -> ip + ipAddressList0 = ipAddressList0.stream().map(NetUtil::getIPAddressFromDomain).collect(Collectors.toList()); + + try { + raftExchanger.changePeer(ipAddressList0); + + //sleep for a while after changePeer: if leader changed, 'metaServerRegistry.setNodes(metaNodes);' will throw error: + // java.lang.IllegalStateException: Server error:is not leader + // at com.alipay.sofa.registry.jraft.bootstrap.RaftClient.sendRequest(RaftClient.java:192) + Thread.sleep(3000L); + + List metaNodes = Lists.newArrayList(); + for (String ipAddress : ipAddressList0) { + MetaNode metaNode = new MetaNode(new URL(ipAddress, 0), nodeConfig.getLocalDataCenter()); + metaNodes.add(metaNode); + } + + metaServerRegistry.setNodes(metaNodes); + + result.setSuccess(true); + + LOGGER.info("Change peer ipAddressList {} to store!", ipAddressList0); + } catch (Exception e) { + String msg = String.format("Error when changePeer: %s", e.getMessage()); + result.setMessage(msg); + LOGGER.error(msg, e); + } + return result; + } + + /** + * force set node list in raft (no need leader alive), maybe lost data + */ + @POST + @Path("resetPeer") + @Produces(MediaType.APPLICATION_JSON) + public Result resetPeer(@FormParam("ipAddressList") String ipAddressList) { + Result result = new Result(); + result.setSuccess(false); + + List ipAddressList0 = null; + if (StringUtils.isNotBlank(ipAddressList)) { + String[] ipAddressArr = StringUtils.split(StringUtils.trim(ipAddressList), ','); + if (ipAddressArr != null) { + ipAddressList0 = Lists.newArrayList(ipAddressArr); + } + } + if (ipAddressList0 == null || ipAddressList0.size() <= 0) { + String msg = String.format("Empty ipAddressList from input: %s", ipAddressList); + LOGGER.error(msg); + result.setMessage(msg); + return result; + } + + //domain -> ip + ipAddressList0 = ipAddressList0.stream().map(NetUtil::getIPAddressFromDomain).collect(Collectors.toList()); + + try { + raftExchanger.resetPeer(ipAddressList0); + + List metaNodes = Lists.newArrayList(); + for (String ipAddress : ipAddressList0) { + MetaNode metaNode = new MetaNode(new URL(ipAddress, 0), nodeConfig.getLocalDataCenter()); + metaNodes.add(metaNode); + } + metaServerRegistry.setNodes(metaNodes); + + result.setSuccess(true); + + LOGGER.info("Reset peer ipAddressList {} to store!", ipAddressList0); + } catch (Exception e) { + String msg = String.format("Error when resetPeer: %s", e.getMessage()); + result.setMessage(msg); + LOGGER.error(msg, e); + } + return result; + } + + @POST + @Path("removePeer") + @Produces(MediaType.APPLICATION_JSON) + public Result remove(Map map) { + + Result result = new Result(); + if (map != null && !map.isEmpty()) { + + Map throwables = new HashMap<>(); + map.forEach((ipAddress, dataCenter) -> { + try { + if (!nodeConfig.getLocalDataCenter().equals(dataCenter)) { + LOGGER.error("Error input dataCenter {} ,current dataCenter {}!", dataCenter, + nodeConfig.getLocalDataCenter()); + throwables.put(ipAddress, "Error input dataCenter"); + return; + } + + //domain -> ip + ipAddress = NetUtil.getIPAddressFromDomain(ipAddress); + + raftExchanger.removePeer(ipAddress); + metaServerRegistry.cancel(ipAddress, NodeType.META); + LOGGER.info("Remove peer ipAddress {} to store!", ipAddress); + } catch (Exception e) { + LOGGER.error("Error remove peer ipAddress {} to store!", ipAddress, e); + throwables.put(ipAddress, e.getMessage()); + } + }); + + if (throwables.isEmpty()) { + result.setSuccess(true); + } else { + result.setSuccess(false); + result.setMessage(String.format("Nod remove all peer node,there are %s exception!", throwables.size())); + } + } else { + result.setSuccess(false); + result.setMessage("Input node map is empty!"); + } + return result; + } + + @GET + @Path("queryPeer") + @Produces(MediaType.APPLICATION_JSON) + public List getMetaList() { + List peerIds = raftExchanger.getPeers(); + return peerIds.stream().map(PeerId::getIp).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/PersistentDataResource.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/PersistentDataResource.java new file mode 100644 index 000000000..84b56fd5b --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/PersistentDataResource.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.resource; + +import com.alipay.sofa.registry.common.model.console.PersistenceData; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.store.api.DBService; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author shangyu.wh + * @version $Id: DecisionModeResource.java, v 0.1 2018-02-01 16:50 shangyu.wh Exp $ + */ +@Path("persistentData") +public class PersistentDataResource { + + private static final Logger DB_LOGGER = LoggerFactory.getLogger(PersistentDataResource.class, + "[DBService]"); + + private static final Logger taskLogger = LoggerFactory.getLogger(PersistentDataResource.class, + "[Task]"); + + @RaftReference + private DBService persistenceDataDBService; + + @Autowired + private TaskListenerManager taskListenerManager; + + @POST + @Path("put") + @Produces(MediaType.APPLICATION_JSON) + public Result put(PersistenceData data) { + + checkObj(data, "PersistenceData"); + checkString(data.getData()); + checkObj(data.getVersion(), "version"); + + String dataInfoId = DataInfo.toDataInfoId(data.getDataId(), data.getInstanceId(), + data.getGroup()); + + try { + boolean ret = persistenceDataDBService.put(dataInfoId, data); + DB_LOGGER.info("put Persistence Data {} to DB result {}!", data, ret); + } catch (Exception e) { + DB_LOGGER.error("error put Persistence Data {} to DB!", data); + throw new RuntimeException("Put Persistence Data " + data + " to DB error!"); + } + + fireDataChangeNotify(data.getVersion(), dataInfoId, DataOperator.ADD); + + Result result = new Result(); + result.setSuccess(true); + return result; + } + + @POST + @Path("remove") + @Produces(MediaType.APPLICATION_JSON) + public Result remove(PersistenceData data) { + + checkObj(data, "PersistenceData"); + checkObj(data.getVersion(), "version"); + + String dataInfoId = DataInfo.toDataInfoId(data.getDataId(), data.getInstanceId(), + data.getGroup()); + + try { + boolean ret = persistenceDataDBService.remove(dataInfoId); + DB_LOGGER.info("remove Persistence Data {} from DB result {}!", data, ret); + } catch (Exception e) { + DB_LOGGER.error("error remove Persistence Data {} from DB!", data); + throw new RuntimeException("Remove Persistence Data " + data + " from DB error!"); + } + + fireDataChangeNotify(data.getVersion(), dataInfoId, DataOperator.REMOVE); + + Result result = new Result(); + result.setSuccess(true); + return result; + } + + private void fireDataChangeNotify(Long version, String dataInfoId, DataOperator dataOperator) { + + NotifyProvideDataChange notifyProvideDataChange = new NotifyProvideDataChange(dataInfoId, + version, dataOperator); + + TaskEvent taskEvent = new TaskEvent(notifyProvideDataChange, + TaskType.PERSISTENCE_DATA_CHANGE_NOTIFY_TASK); + taskLogger.info("send PERSISTENCE_DATA_CHANGE_NOTIFY_TASK notifyProvideDataChange:" + + notifyProvideDataChange); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void checkString(String input) { + if (input == null || input.isEmpty()) { + throw new IllegalArgumentException("Error String data input:" + input); + } + } + + private void checkObj(Object input, String objName) { + if (input == null) { + throw new IllegalArgumentException("Error null Object " + objName + " data input!"); + } + } +} diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/StopPushDataResource.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/StopPushDataResource.java new file mode 100644 index 000000000..40df5eec1 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/resource/StopPushDataResource.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.resource; + +import com.alipay.sofa.registry.common.model.console.PersistenceData; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.store.api.DBService; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author shangyu.wh + * @version $Id: StopPushDataResource.java, v 0.1 2018-07-25 11:40 shangyu.wh Exp $ + */ +@Path("stopPushDataSwitch") +public class StopPushDataResource { + + private static final Logger DB_LOGGER = LoggerFactory.getLogger(StopPushDataResource.class, + "[DBService]"); + + private static final Logger TASK_LOGGER = LoggerFactory.getLogger(StopPushDataResource.class, + "[Task]"); + + @RaftReference + private DBService persistenceDataDBService; + + @Autowired + private TaskListenerManager taskListenerManager; + + /** + * close push + */ + @GET + @Path("open") + @Produces(MediaType.APPLICATION_JSON) + public Result closePush() { + PersistenceData persistenceData = createPushDataInfo(); + persistenceData.setData("true"); + + try { + boolean ret = persistenceDataDBService.put( + ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID, persistenceData); + DB_LOGGER.info("open stop push data switch to DB result {}!", ret); + } catch (Exception e) { + DB_LOGGER.error("error open stop push data switch to DB!"); + throw new RuntimeException("open stop push data switch to DB error!"); + } + + fireDataChangeNotify(persistenceData.getVersion(), + ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID, DataOperator.ADD); + + Result result = new Result(); + result.setSuccess(true); + return result; + } + + /** + * open push + */ + @GET + @Path("close") + @Produces(MediaType.APPLICATION_JSON) + public Result openPush() { + PersistenceData persistenceData = createPushDataInfo(); + persistenceData.setData("false"); + try { + boolean ret = persistenceDataDBService.update( + ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID, persistenceData); + DB_LOGGER.info("close stop push data switch to DB result {}!", ret); + } catch (Exception e) { + DB_LOGGER.error("error close stop push data switch from DB!"); + throw new RuntimeException("Close stop push data switch from DB error!"); + } + + fireDataChangeNotify(persistenceData.getVersion(), + ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID, DataOperator.UPDATE); + + Result result = new Result(); + result.setSuccess(true); + return result; + } + + private PersistenceData createPushDataInfo() { + DataInfo dataInfo = DataInfo.valueOf(ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID); + PersistenceData persistenceData = new PersistenceData(); + persistenceData.setDataId(dataInfo.getDataId()); + persistenceData.setGroup(dataInfo.getDataType()); + persistenceData.setInstanceId(dataInfo.getInstanceId()); + persistenceData.setVersion(System.currentTimeMillis()); + return persistenceData; + } + + private void fireDataChangeNotify(Long version, String dataInfoId, DataOperator dataOperator) { + + NotifyProvideDataChange notifyProvideDataChange = new NotifyProvideDataChange(dataInfoId, + version, dataOperator); + + TaskEvent taskEvent = new TaskEvent(notifyProvideDataChange, + TaskType.PERSISTENCE_DATA_CHANGE_NOTIFY_TASK); + TASK_LOGGER.info("send PERSISTENCE_DATA_CHANGE_NOTIFY_TASK notifyProvideDataChange:" + + notifyProvideDataChange); + taskListenerManager.sendTaskEvent(taskEvent); + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/DataStoreService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/DataStoreService.java new file mode 100644 index 000000000..ff324ff19 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/DataStoreService.java @@ -0,0 +1,598 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.store; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.common.model.metaserver.GetChangeListRequest; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.MetaNodeService; +import com.alipay.sofa.registry.server.meta.node.NodeOperator; +import com.alipay.sofa.registry.server.meta.repository.NodeConfirmStatusService; +import com.alipay.sofa.registry.server.meta.repository.NodeRepository; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.task.Constant; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: DataStoreService.java, v 0.1 2018-01-23 11:42 shangyu.wh Exp $ + */ +public class DataStoreService implements StoreService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataStoreService.class); + + private static final Logger TASK_LOGGER = LoggerFactory + .getLogger( + DataStoreService.class, + "[Task]"); + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock + .readLock(); + private final Lock write = readWriteLock + .writeLock(); + @Autowired + private NodeConfig nodeConfig; + + @Autowired + private TaskListenerManager taskListenerManager; + + @RaftReference(uniqueId = "dataServer") + private RepositoryService> dataRepositoryService; + + @RaftReference(uniqueId = "dataServer") + private NodeConfirmStatusService dataConfirmStatusService; + + private AtomicLong localDataCenterInitVersion = new AtomicLong( + -1L); + + private static final long COMPARE_TIME_COST = 1000L; + + @Override + public NodeType getNodeType() { + return NodeType.DATA; + } + + @Override + public NodeChangeResult setNodes(List nodes) { + throw new UnsupportedOperationException(); + } + + @Override + public NodeChangeResult addNode(DataNode dataNode) { + NodeChangeResult nodeChangeResult; + + String ipAddress = dataNode.getNodeUrl().getIpAddress(); + + long startAll = System.currentTimeMillis(); + write.lock(); + try { + + dataRepositoryService.put(ipAddress, new RenewDecorate(dataNode, + RenewDecorate.DEFAULT_DURATION_SECS)); + + reNew(dataNode, 30); + + nodeChangeResult = getNodeChangeResult(); + + dataConfirmStatusService.putConfirmNode(dataNode, DataOperator.ADD); + + } finally { + write.unlock(); + } + long cost = System.currentTimeMillis() - startAll; + if (cost >= COMPARE_TIME_COST) { + LOGGER.info("dataRepositoryService.addNode cost:{} ", cost); + } + return nodeChangeResult; + } + + @Override + public boolean removeNode(String ipAddress) { + + write.lock(); + try { + + RenewDecorate dataNode = dataRepositoryService.remove(ipAddress); + if (dataNode != null) { + + dataConfirmStatusService.putConfirmNode(dataNode.getRenewal(), DataOperator.REMOVE); + + LOGGER.info("Remove single node {} success!", dataNode.getRenewal()); + return true; + } + return false; + } finally { + write.unlock(); + } + } + + @Override + public void removeNodes(Collection nodes) { + write.lock(); + try { + if (nodes != null && !nodes.isEmpty()) { + for (DataNode dataNode : nodes) { + + String ipAddress = dataNode.getNodeUrl().getIpAddress(); + RenewDecorate dataNodeRemove = dataRepositoryService + .remove(ipAddress); + if (dataNodeRemove != null) { + + dataConfirmStatusService.putConfirmNode(dataNode, DataOperator.REMOVE); + + LOGGER.info("Remove node {} success!", dataNodeRemove.getRenewal()); + } + } + } + } finally { + write.unlock(); + } + } + + @Override + public void reNew(DataNode dataNode, int duration) { + + long startAll = System.currentTimeMillis(); + write.lock(); + try { + String ipAddress = dataNode.getNodeUrl().getIpAddress(); + RenewDecorate reNewer = dataRepositoryService.get(ipAddress); + + if (reNewer == null) { + LOGGER.warn("Renew Data node with ipAddress:" + ipAddress + + " has not existed!It will be registered again!"); + addNode(dataNode); + } else { + if (duration > 0) { + dataRepositoryService.replace(ipAddress, new RenewDecorate(dataNode, duration)); + } else { + dataRepositoryService.replace(ipAddress, new RenewDecorate(dataNode, + RenewDecorate.DEFAULT_DURATION_SECS)); + } + + } + long cost = System.currentTimeMillis() - startAll; + if (cost >= COMPARE_TIME_COST) { + LOGGER.info("dataRepositoryService.renew.all cost:{} ", cost); + } + } finally { + write.unlock(); + } + } + + /** + * only get local datacenter's dataNode, don't care other datacenter's dataNodes + * @return + */ + @Override + public Collection getExpired() { + Collection reNewerList = new ArrayList<>(); + read.lock(); + try { + Map> dataMap = dataRepositoryService.getAllData(); + + dataMap.forEach((ip, dataNode) -> { + + String dataCenter = dataNode.getRenewal().getDataCenter(); + if (dataCenter.equals(nodeConfig.getLocalDataCenter())) { + if (dataNode.isExpired()) { + reNewerList.add(dataNode.getRenewal()); + } + } + }); + + } finally { + read.unlock(); + } + return reNewerList; + } + + @Override + public Map getNodes() { + Map> map = getRunTime(); + Map ret = new HashMap<>(); + if (map != null && !map.isEmpty()) { + map.forEach((dataCenter, dataNodes) -> ret.putAll(dataNodes)); + } + return ret; + } + + @Override + public NodeChangeResult getNodeChangeResult() { + + NodeChangeResult nodeChangeResult = new NodeChangeResult(NodeType.DATA); + read.lock(); + try { + String localDataCenter = nodeConfig.getLocalDataCenter(); + + Map dataNodeRepositoryMap = dataRepositoryService + .getNodeRepositories(); + + ConcurrentHashMap> pushNodes = new ConcurrentHashMap<>(); + + Map versionMap = new ConcurrentHashMap<>(); + + dataNodeRepositoryMap.forEach((dataCenter, dataNodeRepository) -> { + + if (localDataCenter.equalsIgnoreCase(dataCenter)) { + + nodeChangeResult.setVersion(dataNodeRepository.getVersion()); + } + versionMap.put(dataCenter, dataNodeRepository.getVersion()); + + Map> dataMap = dataNodeRepository.getNodeMap(); + Map newMap = new ConcurrentHashMap<>(); + dataMap.forEach((ip, dataNode) -> newMap.put(ip, dataNode.getRenewal())); + pushNodes.put(dataCenter, newMap); + }); + + nodeChangeResult.setNodes(pushNodes); + + nodeChangeResult.setDataCenterListVersions(versionMap); + + nodeChangeResult.setLocalDataCenter(localDataCenter); + + } finally { + read.unlock(); + } + + return nodeChangeResult; + } + + @Override + public void pushNodeListChange() { + NodeOperator fireNode; + if ((fireNode = dataConfirmStatusService.peekConfirmNode()) != null) { + LOGGER.info("Now:type {},node {},Push queue:{}", fireNode.getNodeOperate(), fireNode + .getNode().getNodeUrl().getIpAddress(), + dataConfirmStatusService.getAllConfirmNodes()); + NodeChangeResult nodeChangeResult = getNodeChangeResult(); + Map> map = nodeChangeResult.getNodes(); + Map addNodes = map.get(nodeConfig.getLocalDataCenter()); + if (addNodes != null) { + LOGGER.info("addNodes:{}", addNodes.keySet()); + Map previousNodes = dataConfirmStatusService.putExpectNodes( + fireNode.getNode(), addNodes); + + if (!previousNodes.isEmpty()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("push Type:{},peek:{},list{}", fireNode.getNodeOperate(), + fireNode.getNode().getNodeUrl().getIpAddress(), previousNodes.keySet()); + } + firePushDataListTask(fireNode, nodeChangeResult, previousNodes, true); + + } + } + + firePushSessionListTask(nodeChangeResult, fireNode.getNodeOperate().toString()); + } + } + + @Override + public void confirmNodeStatus(String ipAddress, String confirmNodeIp) { + NodeOperator fireNode = dataConfirmStatusService.peekConfirmNode(); + if (fireNode != null) { + String fireNodeIp = fireNode.getNode().getIp(); + if (fireNodeIp != null && !fireNodeIp.equals(confirmNodeIp)) { + LOGGER + .info( + "Confirm node already be remove from queue!Receive ip:{},expect confirm ip:{},now peek ip:{}", + ipAddress, confirmNodeIp, fireNodeIp); + return; + } + Map waitNotifyNodes = dataConfirmStatusService + .getExpectNodes(fireNode.getNode()); + + if (waitNotifyNodes != null) { + LOGGER.info("Peek node:{} oper:{},waitNotifyNodes:{},confirm ip:{}", fireNode + .getNode().getNodeUrl().getIpAddress(), fireNode.getNodeOperate(), + waitNotifyNodes.keySet(), ipAddress); + + Set removeIp = getRemoveIp(waitNotifyNodes.keySet()); + removeIp.add(ipAddress); + + waitNotifyNodes = dataConfirmStatusService.removeExpectConfirmNodes( + fireNode.getNode(), removeIp); + + if (waitNotifyNodes.isEmpty()) { + //all node be notified,or some disconnect node be evict + try { + if (null != dataConfirmStatusService + .removeExpectNodes((dataConfirmStatusService.pollConfirmNode()) + .getNode())) { + //add init status must notify + if (fireNode.getNodeOperate() == DataOperator.ADD) { + notifyConfirm(fireNode.getNode()); + } + LOGGER.info("Data node {} operator {} be confirm,Dump queue:{}", + fireNode.getNode().getNodeUrl().getIpAddress(), + fireNode.getNodeOperate(), + dataConfirmStatusService.getAllConfirmNodes()); + } + } catch (InterruptedException e) { + LOGGER.error("Notify expect confirm status node {} interrupted!", + fireNode.getNode()); + } + } + } else { + try { + //wait node not exist, + dataConfirmStatusService.pollConfirmNode(); + LOGGER + .info( + "Data node {} operator {} poll!not other node need be notify!Confirm ip {},Dump queue:{}", + fireNode.getNode().getNodeUrl().getIpAddress(), + fireNode.getNodeOperate(), ipAddress, + dataConfirmStatusService.getAllConfirmNodes()); + } catch (InterruptedException e) { + LOGGER.error("Notify expect confirm status node " + fireNode.getNode() + + " interrupted!", e); + } + } + } + } + + private Set getRemoveIp(Set waitNotifyNodes) { + Map> map = getRunTime(); + Map addNodes = map.get(nodeConfig.getLocalDataCenter()); + if (addNodes != null && !addNodes.isEmpty()) { + return waitNotifyNodes.stream().filter(ip -> !addNodes.keySet().contains(ip)).collect(Collectors.toSet()); + } + return new HashSet<>(); + } + + private void firePushDataListTask(NodeOperator confirmNode, + NodeChangeResult nodeChangeResult, + Map targetNodes, boolean confirm) { + + //notify targetNodes change + String ip = ""; + String nodeOperate; + if (confirmNode != null) { + ip = confirmNode.getNode().getIp(); + nodeOperate = confirmNode.getNodeOperate().toString(); + } else { + nodeOperate = "OtherDataCenter update"; + } + TaskEvent taskEvent = new TaskEvent(nodeChangeResult, TaskType.DATA_NODE_CHANGE_PUSH_TASK); + taskEvent.setAttribute(Constant.PUSH_NEED_CONFIRM_KEY, confirm); + taskEvent.setAttribute(Constant.PUSH_TARGET_DATA_NODE, targetNodes); + taskEvent.setAttribute(Constant.PUSH_TARGET_TYPE, NodeType.DATA); + taskEvent.setAttribute(Constant.PUSH_TARGET_OPERATOR_TYPE, nodeOperate); + taskEvent.setAttribute(Constant.PUSH_TARGET_CONFIRM_NODE, ip); + + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " NodeType:" + NodeType.DATA + + " Operator:" + nodeOperate + " confirmNode:" + ip); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void firePushSessionListTask(NodeChangeResult nodeChangeResult, String nodeOperate) { + + //notify all session node + TaskEvent taskEvent = new TaskEvent(nodeChangeResult, TaskType.DATA_NODE_CHANGE_PUSH_TASK); + taskEvent.setAttribute(Constant.PUSH_TARGET_TYPE, NodeType.SESSION); + taskEvent.setAttribute(Constant.PUSH_TARGET_OPERATOR_TYPE, nodeOperate); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " NodeType:" + NodeType.SESSION + + " Operator:" + nodeOperate); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void notifyConfirm(DataNode node) { + TaskEvent taskEvent = new TaskEvent(node, TaskType.RECEIVE_STATUS_CONFIRM_NOTIFY_TASK); + + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " DataNode:" + node); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private Map> getRunTime() { + + read.lock(); + try { + ConcurrentHashMap> pushNodes = new ConcurrentHashMap<>(); + Map>> dataCenterMap = dataRepositoryService.getAllDataMap(); + + dataCenterMap.forEach((dataCenter, dataMap) -> { + + Map newMap = new ConcurrentHashMap<>(); + dataMap.forEach((ip, dataNode) -> newMap.put(ip, dataNode.getRenewal())); + pushNodes.put(dataCenter, newMap); + + }); + return pushNodes; + } finally { + read.unlock(); + } + } + + @Override + public void getOtherDataCenterNodeAndUpdate() { + + MetaNodeService metaNodeService = (MetaNodeService) ServiceFactory + .getNodeService(NodeType.META); + + Map> metaMap = nodeConfig.getMetaNodeIP(); + + if (metaMap != null && metaMap.size() > 0) { + for (String dataCenter : metaMap.keySet()) { + //get other dataCenter dataNodes + if (!nodeConfig.getLocalDataCenter().equals(dataCenter)) { + GetChangeListRequest getChangeListRequest = new GetChangeListRequest( + NodeType.DATA, dataCenter); + //trigger fetch dataCenter data list change + DataCenterNodes getDataCenterNodes = metaNodeService + .getDataCenterNodes(getChangeListRequest); + if (getDataCenterNodes != null) { + String dataCenterGet = getDataCenterNodes.getDataCenterId(); + Long version = getDataCenterNodes.getVersion(); + if (version == null) { + LOGGER.error("Request message version cant not be null!"); + return; + } + //check for scheduler get other dataCenter data node + boolean result = dataRepositoryService.checkVersion(dataCenterGet, version); + if (!result) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DataCenter {} data list version {} has not updated!", + dataCenter, version); + } + return; + } + updateOtherDataCenterNodes(getDataCenterNodes); + } else { + LOGGER.error("Get DataCenter data nodes change error!null"); + throw new RuntimeException("Get null DataCenter data nodes change!"); + } + } + } + } + } + + @Override + public void updateOtherDataCenterNodes(DataCenterNodes dataCenterNodes) { + write.lock(); + try { + String dataCenter = dataCenterNodes.getDataCenterId(); + Long version = dataCenterNodes.getVersion(); + + if (version == null) { + LOGGER.error("Request message version cant not be null!"); + return; + } + + Map dataCenterNodesMap = dataCenterNodes.getNodes(); + + LOGGER.info("update version {} Other DataCenter {} Nodes {}", version, dataCenter, dataCenterNodesMap); + + Map> dataCenterNodesMapTemp = new ConcurrentHashMap<>(); + dataCenterNodesMap.forEach((ipAddress, dataNode) -> dataCenterNodesMapTemp + .put(ipAddress, new RenewDecorate(dataNode, RenewDecorate.DEFAULT_DURATION_SECS))); + dataRepositoryService.replaceAll(dataCenter, dataCenterNodesMapTemp, version); + + if (version == localDataCenterInitVersion.get()) { + //first dataCenter has init version,need not notify local data node + LOGGER.info("DataCenter {} first start up,No data node change to notify!Init version {}", dataCenter, + version); + return; + } + + NodeChangeResult nodeChangeResult = getNodeChangeResult(); + + firePushDataListTask(null, nodeChangeResult, null, false); + + firePushSessionListTask(nodeChangeResult, "OtherDataCenterUpdate"); + } finally { + write.unlock(); + } + } + + @Override + public DataCenterNodes getDataCenterNodes() { + read.lock(); + try { + String localDataCenter = nodeConfig.getLocalDataCenter(); + + Map dataNodeRepositoryMap = dataRepositoryService + .getNodeRepositories(); + + NodeRepository dataNodeRepository = dataNodeRepositoryMap.get(localDataCenter); + + if (dataNodeRepository == null) { + //first just dataCenter exist but no data node register + DataCenterNodes dataCenterNodes = new DataCenterNodes(NodeType.DATA, localDataCenterInitVersion.get(), + localDataCenter); + dataCenterNodes.setNodes(new ConcurrentHashMap<>()); + return dataCenterNodes; + } + + DataCenterNodes dataCenterNodes = new DataCenterNodes(NodeType.DATA, dataNodeRepository.getVersion(), + localDataCenter); + + Map> dataMap = dataNodeRepository.getNodeMap(); + Map newMap = new ConcurrentHashMap<>(); + dataMap.forEach((ip, dataNode) -> newMap.put(ip, dataNode.getRenewal())); + + dataCenterNodes.setNodes(newMap); + + return dataCenterNodes; + } finally { + read.unlock(); + } + } + + /** + * Setter method for property nodeConfig. + * + * @param nodeConfig value to be assigned to property nodeConfig + */ + public void setNodeConfig(NodeConfig nodeConfig) { + this.nodeConfig = nodeConfig; + } + + /** + * Setter method for property taskListenerManager. + * + * @param taskListenerManager value to be assigned to property taskListenerManager + */ + public void setTaskListenerManager(TaskListenerManager taskListenerManager) { + this.taskListenerManager = taskListenerManager; + } + + /** + * Setter method for property dataRepositoryService. + * + * @param dataRepositoryService value to be assigned to property dataRepositoryService + */ + public void setDataRepositoryService(RepositoryService> dataRepositoryService) { + this.dataRepositoryService = dataRepositoryService; + } + + /** + * Setter method for property dataConfirmStatusService. + * + * @param dataConfirmStatusService value to be assigned to property dataConfirmStatusService + */ + public void setDataConfirmStatusService(NodeConfirmStatusService dataConfirmStatusService) { + this.dataConfirmStatusService = dataConfirmStatusService; + } + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/MetaStoreService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/MetaStoreService.java new file mode 100644 index 000000000..f50ce3b80 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/MetaStoreService.java @@ -0,0 +1,359 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.store; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.GetChangeListRequest; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.MetaNodeService; +import com.alipay.sofa.registry.server.meta.repository.NodeRepository; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.task.Constant; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.NotSupportedException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: MetaStoreService.java, v 0.1 2018-03-02 16:41 shangyu.wh Exp $ + */ +public class MetaStoreService implements StoreService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaStoreService.class); + + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock + .readLock(); + private final Lock write = readWriteLock + .writeLock(); + + @Autowired + private NodeConfig nodeConfig; + + private AtomicLong localDataCenterInitVersion = new AtomicLong( + -1L); + + @Autowired + private TaskListenerManager taskListenerManager; + + @RaftReference(uniqueId = "metaServer") + private RepositoryService> metaRepositoryService; + + @Override + public NodeType getNodeType() { + return NodeType.META; + } + + @Override + public NodeChangeResult setNodes(List metaNodes) { + NodeChangeResult nodeChangeResult; + + write.lock(); + try { + + //存放到repository(自动通过jraft同步给集群) + String dataCenter = nodeConfig.getLocalDataCenter(); + Map> dataCenterNodesMap = new ConcurrentHashMap<>(); + for (MetaNode metaNode : metaNodes) { + dataCenterNodesMap.put(metaNode.getIp(), new RenewDecorate(metaNode, + RenewDecorate.DEFAULT_DURATION_SECS)); + } + metaRepositoryService.replaceAll(dataCenter, dataCenterNodesMap, + System.currentTimeMillis()); + + //触发通知(需要通知data/session) + nodeChangeResult = getNodeChangeResult(); + firePushDataListTask(nodeChangeResult, "addMetaNode"); + firePushSessionListTask(nodeChangeResult, "addMetaNode"); + + LOGGER.info("Set meta node list {} success!", metaNodes); + + } finally { + write.unlock(); + } + + return nodeChangeResult; + } + + @Override + public NodeChangeResult addNode(MetaNode metaNode) { + NodeChangeResult nodeChangeResult; + + String ipAddress = metaNode.getNodeUrl().getIpAddress(); + + write.lock(); + try { + //存放到repository(自动通过jraft同步给集群) + metaRepositoryService.put(ipAddress, new RenewDecorate(metaNode, + RenewDecorate.DEFAULT_DURATION_SECS)); + + //触发通知(需要通知data/session) + nodeChangeResult = getNodeChangeResult(); + firePushDataListTask(nodeChangeResult, "addMetaNode"); + firePushSessionListTask(nodeChangeResult, "addMetaNode"); + + LOGGER.info("Add single meta node {} success!", metaNode); + + } finally { + write.unlock(); + } + + return nodeChangeResult; + } + + @Override + public boolean removeNode(String ipAddress) { + write.lock(); + try { + + //存放到repository(自动通过jraft同步给集群) + RenewDecorate dataNode = metaRepositoryService.remove(ipAddress); + + //触发通知(需要通知data/session) + if (dataNode != null) { + NodeChangeResult nodeChangeResult = getNodeChangeResult(); + firePushDataListTask(nodeChangeResult, "removeMetaNode"); + firePushSessionListTask(nodeChangeResult, "removeMetaNode"); + LOGGER.info("Remove single meta node {} success!", dataNode.getRenewal()); + return true; + } + return false; + } finally { + write.unlock(); + } + } + + @Override + public void removeNodes(Collection nodes) { + + } + + @Override + public void confirmNodeStatus(String connectId, String ip) { + throw new NotSupportedException("Node type META not support function"); + } + + @Override + public void reNew(MetaNode node, int duration) { + } + + @Override + public Collection getExpired() { + return null; + } + + @Override + public Map getNodes() { + return null; + } + + @Override + public NodeChangeResult getNodeChangeResult() { + + NodeChangeResult nodeChangeResult = new NodeChangeResult(NodeType.META); + + String localDataCenter = nodeConfig.getLocalDataCenter(); + + Map metaRepositoryMap = metaRepositoryService.getNodeRepositories(); + + ConcurrentHashMap> pushNodes = new ConcurrentHashMap<>(); + + Map versionMap = new ConcurrentHashMap<>(); + + metaRepositoryMap.forEach((dataCenter, metaNodeRepository) -> { + + if (localDataCenter.equalsIgnoreCase(dataCenter)) { + + nodeChangeResult.setVersion(metaNodeRepository.getVersion()); + } + versionMap.put(dataCenter, metaNodeRepository.getVersion()); + + Map> dataMap = metaNodeRepository.getNodeMap(); + Map newMap = new ConcurrentHashMap<>(); + dataMap.forEach((ip, dataNode) -> newMap.put(ip, dataNode.getRenewal())); + pushNodes.put(dataCenter, newMap); + }); + + nodeChangeResult.setLocalDataCenter(localDataCenter); + + nodeChangeResult.setNodes(pushNodes); + + nodeChangeResult.setDataCenterListVersions(versionMap); + + return nodeChangeResult; + } + + @Override + public void getOtherDataCenterNodeAndUpdate() { + + MetaNodeService metaNodeService = (MetaNodeService) ServiceFactory + .getNodeService(NodeType.META); + + Map> metaMap = nodeConfig.getMetaNodeIP(); + + if (metaMap != null && metaMap.size() > 0) { + for (String dataCenter : metaMap.keySet()) { + //get other dataCenter meta + if (!nodeConfig.getLocalDataCenter().equals(dataCenter)) { + GetChangeListRequest getChangeListRequest = new GetChangeListRequest( + NodeType.META, dataCenter); + //trigger fetch dataCenter meta list change + DataCenterNodes getDataCenterNodes = metaNodeService + .getDataCenterNodes(getChangeListRequest); + if (getDataCenterNodes != null) { + String dataCenterGet = getDataCenterNodes.getDataCenterId(); + Long version = getDataCenterNodes.getVersion(); + if (version == null) { + LOGGER.error("Request message meta version cant not be null!"); + return; + } + //check for scheduler get other dataCenter meta node + boolean result = metaRepositoryService.checkVersion(dataCenterGet, version); + if (!result) { + LOGGER.debug("DataCenter {} meta list version {} has not updated!", + dataCenter, version); + return; + } + updateOtherDataCenterNodes(getDataCenterNodes); + } else { + LOGGER.error("Get DataCenter meta nodes change error!null"); + throw new RuntimeException("Get null DataCenter meta nodes change!"); + } + } + } + } + } + + @Override + public void updateOtherDataCenterNodes(DataCenterNodes dataCenterNodes) { + write.lock(); + try { + String dataCenter = dataCenterNodes.getDataCenterId(); + Long version = dataCenterNodes.getVersion(); + + if (version == null) { + LOGGER.error("Request message version cant not be null!"); + return; + } + Map dataCenterNodesMap = dataCenterNodes.getNodes(); + + LOGGER.info("update version {} Other DataCenter {} meta Nodes {}", version, dataCenter, dataCenterNodesMap); + + Map> dataCenterNodesMapTemp = new ConcurrentHashMap<>(); + + dataCenterNodesMap.forEach((ipAddress, metaNode) -> dataCenterNodesMapTemp + .put(ipAddress, new RenewDecorate(metaNode, RenewDecorate.DEFAULT_DURATION_SECS))); + metaRepositoryService.replaceAll(dataCenter, dataCenterNodesMapTemp, version); + + if (version == localDataCenterInitVersion.get()) { + //first dataCenter has init version,need not notify local data node + LOGGER.info("DataCenter {} first start up,No meta node change to notify!Init version {}", dataCenter, + version); + return; + } + + NodeChangeResult nodeChangeResult = getNodeChangeResult(); + + firePushDataListTask(nodeChangeResult, "OtherDataCenterMetaUpdate"); + + firePushSessionListTask(nodeChangeResult, "OtherDataCenterMetaUpdate"); + } finally { + write.unlock(); + } + } + + @Override + public DataCenterNodes getDataCenterNodes() { + read.lock(); + try { + String localDataCenter = nodeConfig.getLocalDataCenter(); + + Map metaNodeRepositoryMap = metaRepositoryService + .getNodeRepositories(); + + NodeRepository metaNodeRepository = metaNodeRepositoryMap.get(localDataCenter); + + if (metaNodeRepository == null) { + DataCenterNodes dataCenterNodes = new DataCenterNodes(NodeType.META, localDataCenterInitVersion.get(), + localDataCenter); + dataCenterNodes.setNodes(new ConcurrentHashMap<>()); + + return dataCenterNodes; + } + + DataCenterNodes dataCenterNodes = new DataCenterNodes(NodeType.META, metaNodeRepository.getVersion(), + localDataCenter); + + Map> dataMap = metaNodeRepository.getNodeMap(); + Map newMap = new ConcurrentHashMap<>(); + dataMap.forEach((ip, metaNode) -> newMap.put(ip, metaNode.getRenewal())); + dataCenterNodes.setNodes(newMap); + + return dataCenterNodes; + } finally { + read.unlock(); + } + } + + private void firePushDataListTask(NodeChangeResult nodeChangeResult, String nodeOperate) { + + TaskEvent taskEvent = new TaskEvent(nodeChangeResult, TaskType.DATA_NODE_CHANGE_PUSH_TASK); + taskEvent.setAttribute(Constant.PUSH_NEED_CONFIRM_KEY, false); + taskEvent.setAttribute(Constant.PUSH_TARGET_TYPE, NodeType.DATA); + taskEvent.setAttribute(Constant.PUSH_TARGET_OPERATOR_TYPE, nodeOperate); + + LOGGER.info("send " + taskEvent.getTaskType() + " NodeType:" + NodeType.DATA + " Operator:" + + nodeOperate); + + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void firePushSessionListTask(NodeChangeResult nodeChangeResult, String nodeOperate) { + + //notify all session node + TaskEvent taskEvent = new TaskEvent(nodeChangeResult, TaskType.DATA_NODE_CHANGE_PUSH_TASK); + taskEvent.setAttribute(Constant.PUSH_TARGET_TYPE, NodeType.SESSION); + taskEvent.setAttribute(Constant.PUSH_TARGET_OPERATOR_TYPE, nodeOperate); + LOGGER.info("send " + taskEvent.getTaskType() + " NodeType:" + NodeType.SESSION + + " Operator:" + nodeOperate); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public void pushNodeListChange() { + + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/RenewDecorate.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/RenewDecorate.java new file mode 100644 index 000000000..e642ba557 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/RenewDecorate.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.store; + +import java.io.Serializable; + +/** + * heartbeat info for node + * @author shangyu.wh + * @version $Id: ReNewer.java, v 0.1 2018-01-16 17:10 shangyu.wh Exp $ + */ +public class RenewDecorate implements Serializable { + + public static final int DEFAULT_DURATION_SECS = 15; + + private T renewal; + + private long beginTimestamp; + + private volatile long lastUpdateTimestamp; + + private long duration; + + /** + * use for task parameter + * @param renewal + */ + public RenewDecorate(T renewal) { + this.renewal = renewal; + } + + /** + * constructor + * @param renewal + * @param durationSECS + */ + public RenewDecorate(T renewal, long durationSECS) { + this.renewal = renewal; + this.beginTimestamp = System.currentTimeMillis(); + this.lastUpdateTimestamp = beginTimestamp; + this.duration = durationSECS * 1000; + } + + /** + * verify expired or not + * @return + */ + public boolean isExpired() { + return System.currentTimeMillis() > lastUpdateTimestamp + duration; + } + + /** + * refresh lastUpdateTimestamp + */ + public void reNew() { + lastUpdateTimestamp = System.currentTimeMillis() + duration; + } + + /** + * refresh lastUpdateTimestamp by durationSECS + * @param durationSECS + */ + public void reNew(long durationSECS) { + lastUpdateTimestamp = System.currentTimeMillis() + durationSECS * 1000; + } + + /** + * Getter method for property renewal. + * + * @return property value of renewal + */ + public T getRenewal() { + return renewal; + } + + /** + * Setter method for property renewal. + * + * @param renewal value to be assigned to property renewal + */ + public void setRenewal(T renewal) { + this.renewal = renewal; + } + + /** + * Getter method for property beginTimestamp. + * + * @return property value of beginTimestamp + */ + public long getBeginTimestamp() { + return beginTimestamp; + } + + /** + * Getter method for property lastUpdateTimestamp. + * + * @return property value of lastUpdateTimestamp + */ + public long getLastUpdateTimestamp() { + return lastUpdateTimestamp; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/SessionStoreService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/SessionStoreService.java new file mode 100644 index 000000000..5123a9f43 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/SessionStoreService.java @@ -0,0 +1,450 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.store; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.node.NodeOperator; +import com.alipay.sofa.registry.server.meta.repository.NodeConfirmStatusService; +import com.alipay.sofa.registry.server.meta.repository.RepositoryService; +import com.alipay.sofa.registry.server.meta.repository.VersionRepositoryService; +import com.alipay.sofa.registry.server.meta.task.Constant; +import com.alipay.sofa.registry.store.api.annotation.RaftReference; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.NotSupportedException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: SessionStoreService.java, v 0.1 2018-01-12 14:14 shangyu.wh Exp $ + */ +public class SessionStoreService implements StoreService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionStoreService.class); + + private static final Logger TASK_LOGGER = LoggerFactory + .getLogger( + SessionStoreService.class, + "[Task]"); + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock + .readLock(); + private final Lock write = readWriteLock + .writeLock(); + @Autowired + private TaskListenerManager taskListenerManager; + @Autowired + private StoreService dataStoreService; + @Autowired + private NodeConfig nodeConfig; + + @RaftReference(uniqueId = "sessionServer") + private RepositoryService> sessionRepositoryService; + + @RaftReference(uniqueId = "sessionServer") + private VersionRepositoryService sessionVersionRepositoryService; + + @RaftReference(uniqueId = "sessionServer") + private NodeConfirmStatusService sessionConfirmStatusService; + + @Override + public NodeType getNodeType() { + return NodeType.SESSION; + } + + @Override + public NodeChangeResult setNodes(List nodes) { + throw new UnsupportedOperationException(); + } + + @Override + public NodeChangeResult addNode(SessionNode sessionNode) { + + write.lock(); + try { + String ipAddress = sessionNode.getNodeUrl().getIpAddress(); + + sessionRepositoryService.put(ipAddress, new RenewDecorate(sessionNode, + RenewDecorate.DEFAULT_DURATION_SECS)); + + sessionVersionRepositoryService.checkAndUpdateVersions(nodeConfig.getLocalDataCenter(), + System.currentTimeMillis()); + + reNew(sessionNode, 30); + + sessionConfirmStatusService.putConfirmNode(sessionNode, DataOperator.ADD); + + } finally { + write.unlock(); + } + + return dataStoreService.getNodeChangeResult(); + } + + @Override + public boolean removeNode(String ipAddress) { + + write.lock(); + try { + RenewDecorate oldRenewDecorate = sessionRepositoryService + .remove(ipAddress); + if (oldRenewDecorate == null) { + LOGGER + .info("Remove Session node with ipAddress:" + ipAddress + " has not existed!"); + return false; + } + + sessionVersionRepositoryService.checkAndUpdateVersions(nodeConfig.getLocalDataCenter(), + System.currentTimeMillis()); + + sessionConfirmStatusService.putConfirmNode(oldRenewDecorate.getRenewal(), + DataOperator.REMOVE); + } finally { + write.unlock(); + } + + return true; + } + + @Override + public void removeNodes(Collection nodes) { + + if (nodes != null && !nodes.isEmpty()) { + write.lock(); + try { + for (Node node : nodes) { + String ipAddress = node.getNodeUrl().getIpAddress(); + RenewDecorate oldRenewDecorate = sessionRepositoryService + .remove(ipAddress); + if (oldRenewDecorate == null) { + LOGGER.warn("Remove session nodes with ipAddress:" + ipAddress + + " has not existed!"); + continue; + } + + sessionVersionRepositoryService.checkAndUpdateVersions( + nodeConfig.getLocalDataCenter(), System.currentTimeMillis()); + + sessionConfirmStatusService.putConfirmNode(oldRenewDecorate.getRenewal(), + DataOperator.REMOVE); + + //confirmNodeStatus(ipAddress, DataOperator.REMOVE); + } + } finally { + write.unlock(); + } + } + } + + @Override + public void reNew(SessionNode sessionNode, int duration) { + + write.lock(); + try { + String ipAddress = sessionNode.getNodeUrl().getIpAddress(); + RenewDecorate reNewer = sessionRepositoryService.get(ipAddress); + + if (reNewer == null) { + LOGGER.warn("ReNew session node with ipAddress:" + ipAddress + + " has not existed!It will be registered again!"); + addNode(sessionNode); + } else { + if (duration > 0) { + sessionRepositoryService.replace(ipAddress, new RenewDecorate(sessionNode, + duration)); + } else { + sessionRepositoryService.replace(ipAddress, new RenewDecorate(sessionNode, + RenewDecorate.DEFAULT_DURATION_SECS)); + } + } + } finally { + write.unlock(); + } + } + + @Override + public Collection getExpired() { + Collection reNewerList = new ArrayList<>(); + read.lock(); + try { + Map> map = sessionRepositoryService.getAllData(); + map.forEach((key, value) -> { + if (value.isExpired()) { + reNewerList.add(value.getRenewal()); + } + }); + } finally { + read.unlock(); + } + return reNewerList; + } + + @Override + public Map getNodes() { + Map tmpMap = new HashMap<>(); + read.lock(); + try { + Map> map = sessionRepositoryService.getAllData(); + map.forEach((key, value) -> tmpMap.put(key, value.getRenewal())); + } finally { + read.unlock(); + } + + return tmpMap; + } + + @Override + public void pushNodeListChange() { + NodeOperator fireNode; + if ((fireNode = sessionConfirmStatusService.peekConfirmNode()) != null) { + //if (LOGGER.isDebugEnabled()) { + LOGGER.info("Now:type {},node {},Push queue:{}", fireNode.getNodeOperate(), fireNode + .getNode().getNodeUrl().getIpAddress(), + sessionConfirmStatusService.getAllConfirmNodes()); + //} + NodeChangeResult nodeChangeResult = getNodeChangeResult(); + Map> map = nodeChangeResult.getNodes(); + Map addNodes = map.get(nodeConfig.getLocalDataCenter()); + if (addNodes != null) { + LOGGER.info("addNodes:{}", addNodes.keySet()); + Map previousNodes = sessionConfirmStatusService + .putExpectNodes(fireNode.getNode(), addNodes); + + if (!previousNodes.isEmpty()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("push Type:{},peek:{},list{}", fireNode.getNodeOperate(), + fireNode.getNode().getNodeUrl().getIpAddress(), previousNodes.keySet()); + } + firePushSessionListTask(fireNode, previousNodes, nodeChangeResult); + } + } + } + } + + @Override + public void confirmNodeStatus(String ipAddress, String confirmNodeIp) { + NodeOperator fireNode = sessionConfirmStatusService.peekConfirmNode(); + if (fireNode != null) { + String fireNodeIp = fireNode.getNode().getNodeUrl().getIpAddress(); + if (fireNodeIp != null && !fireNodeIp.equals(confirmNodeIp)) { + LOGGER + .info( + "Confirm node already be remove from queue!Receive ip:{},expect confirm ip:{},now peek ip:{}", + ipAddress, confirmNodeIp, fireNodeIp); + return; + } + Map waitNotifyNodes = sessionConfirmStatusService + .getExpectNodes(fireNode.getNode()); + if (waitNotifyNodes != null) { + LOGGER.info("Peek node:{} oper:{},waitNotifyNodes:{},confirm ip:{}", fireNode + .getNode().getNodeUrl().getIpAddress(), fireNode.getNodeOperate(), + waitNotifyNodes.keySet(), ipAddress); + + Set removeIp = getRemoveIp(waitNotifyNodes.keySet()); + removeIp.add(ipAddress); + + waitNotifyNodes = sessionConfirmStatusService.removeExpectConfirmNodes( + fireNode.getNode(), removeIp); + + if (waitNotifyNodes.isEmpty()) { + //all node be notified,or some disconnect node be evict + try { + if (null != sessionConfirmStatusService + .removeExpectNodes(sessionConfirmStatusService.pollConfirmNode() + .getNode())) { + //add init status must notify + LOGGER.info("Session node {} operator {} confirm!", fireNode.getNode() + .getNodeUrl().getIpAddress(), fireNode.getNodeOperate()); + } + } catch (InterruptedException e) { + LOGGER.error("Notify expect confirm status node " + fireNode.getNode() + + " interrupted!", e); + } + } + } else { + try { + //wait node not exist, + sessionConfirmStatusService.pollConfirmNode(); + LOGGER + .info( + "Session node {} operator {} poll!not other node need be notify!Confirm ip {}", + fireNode.getNode().getNodeUrl().getIpAddress(), + fireNode.getNodeOperate(), ipAddress); + } catch (InterruptedException e) { + LOGGER.error("Notify expect confirm status node " + fireNode.getNode() + + " interrupted!", e); + } + } + } + + } + + private Set getRemoveIp(Set waitNotifyNodes) { + + NodeChangeResult nodeChangeResult = getNodeChangeResult(); + Map> map = nodeChangeResult.getNodes(); + Map addNodes = map.get(nodeConfig.getLocalDataCenter()); + if (addNodes != null && !addNodes.isEmpty()) { + return waitNotifyNodes.stream().filter(ip -> !addNodes.keySet().contains(ip)).collect(Collectors.toSet()); + } + return new HashSet<>(); + } + + private void firePushSessionListTask(NodeOperator fireNode, + Map sessionNodeMap, + NodeChangeResult nodeChangeResult) { + + //notify target session node registry + TaskEvent taskEvent = new TaskEvent(TaskType.SESSION_NODE_CHANGE_PUSH_TASK); + taskEvent.setAttribute(Constant.PUSH_TARGET_OPERATOR_TYPE, fireNode.getNodeOperate()); + taskEvent.setAttribute(Constant.PUSH_TARGET_SESSION_NODE, sessionNodeMap); + taskEvent.setAttribute(Constant.PUSH_TARGET_CONFIRM_NODE, fireNode.getNode().getNodeUrl() + .getIpAddress()); + taskEvent.setEventObj(nodeChangeResult); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " taskEvent:" + taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public NodeChangeResult getNodeChangeResult() { + + NodeChangeResult nodeChangeResult = new NodeChangeResult(NodeType.SESSION); + + //one session node cluster + String localDataCenter = nodeConfig.getLocalDataCenter(); + nodeChangeResult.setLocalDataCenter(localDataCenter); + + Map> nodes = new HashMap<>(); + read.lock(); + try { + Map tmpMap = new HashMap<>(); + Map> map = sessionRepositoryService.getAllData(); + map.forEach((key, value) -> tmpMap.put(key, value.getRenewal())); + nodes.put(localDataCenter, tmpMap); + + nodeChangeResult.setNodes(nodes); + nodeChangeResult.setVersion(sessionVersionRepositoryService.getVersion(nodeConfig.getLocalDataCenter())); + } finally { + read.unlock(); + } + return nodeChangeResult; + } + + @Override + public void getOtherDataCenterNodeAndUpdate() { + + } + + @Override + public DataCenterNodes getDataCenterNodes() { + Long version = sessionVersionRepositoryService.getVersion(nodeConfig.getLocalDataCenter()); + DataCenterNodes dataCenterNodes = new DataCenterNodes(NodeType.SESSION, version, + nodeConfig.getLocalDataCenter()); + dataCenterNodes.setNodes(getNodes()); + return dataCenterNodes; + } + + @Override + public void updateOtherDataCenterNodes(DataCenterNodes dataCenterNodes) { + throw new NotSupportedException("Node type SESSION not support function"); + } + + /** + * Setter method for property taskListenerManager. + * + * @param taskListenerManager value to be assigned to property taskListenerManager + */ + public void setTaskListenerManager(TaskListenerManager taskListenerManager) { + this.taskListenerManager = taskListenerManager; + } + + /** + * Setter method for property dataStoreService. + * + * @param dataStoreService value to be assigned to property dataStoreService + */ + public void setDataStoreService(StoreService dataStoreService) { + this.dataStoreService = dataStoreService; + } + + /** + * Setter method for property nodeConfig. + * + * @param nodeConfig value to be assigned to property nodeConfig + */ + public void setNodeConfig(NodeConfig nodeConfig) { + this.nodeConfig = nodeConfig; + } + + /** + * Setter method for property sessionRepositoryService. + * + * @param sessionRepositoryService value to be assigned to property sessionRepositoryService + */ + public void setSessionRepositoryService(RepositoryService> sessionRepositoryService) { + this.sessionRepositoryService = sessionRepositoryService; + } + + /** + * Setter method for property sessionVersionRepositoryService. + * + * @param sessionVersionRepositoryService value to be assigned to property sessionVersionRepositoryService + */ + public void setSessionVersionRepositoryService(VersionRepositoryService sessionVersionRepositoryService) { + this.sessionVersionRepositoryService = sessionVersionRepositoryService; + } + + /** + * Getter method for property sessionConfirmStatusService. + * + * @return property value of sessionConfirmStatusService + */ + public NodeConfirmStatusService getSessionConfirmStatusService() { + return sessionConfirmStatusService; + } + + /** + * Setter method for property sessionConfirmStatusService. + * + * @param sessionConfirmStatusService value to be assigned to property sessionConfirmStatusService + */ + public void setSessionConfirmStatusService(NodeConfirmStatusService sessionConfirmStatusService) { + this.sessionConfirmStatusService = sessionConfirmStatusService; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/StoreService.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/StoreService.java new file mode 100644 index 000000000..05d38de1b --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/store/StoreService.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.store; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataCenterNodes; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * interface for node store service + * @author shangyu.wh + * @version $Id: StoreService.java, v 0.1 2018-01-11 22:16 shangyu.wh Exp $ + */ +public interface StoreService { + + /** + * get node type + * @return + */ + NodeType getNodeType(); + + NodeChangeResult setNodes(List nodes); + + /** + * add new node,when renew request not found node will be add again + * @param node + * @return + */ + NodeChangeResult addNode(T node); + + /** + * node change info push must be confirm received, + * @param ipAddress received Node ipAddress + * @param confirmNodeIp will be confirmed node ip + */ + void confirmNodeStatus(String ipAddress, String confirmNodeIp); + + /** + * remove current dataCenter dataNode by ipAddress + * @param ipAddress + * @return + */ + boolean removeNode(String ipAddress); + + /** + * remove current dataCenter dataNodes + * @param nodes + */ + void removeNodes(Collection nodes); + + /** + * heartbeat update node expired time + * @param node + * @return + */ + void reNew(T node, int duration); + + /** + * get expired node list + * @return + */ + Collection getExpired(); + + /** + * get all Nodes from all dataCenter + * @return + */ + Map getNodes(); + + /** + * get node info request + * @return + */ + NodeChangeResult getNodeChangeResult(); + + /** + * schedule check other dataCenter node change and update + */ + void getOtherDataCenterNodeAndUpdate(); + + /** + * get other meta server node change update version and node info,and push current dataCenter node change info + * + * @param dataCenterNodes + */ + void updateOtherDataCenterNodes(DataCenterNodes dataCenterNodes); + + /** + * get DataCenter Nodes list contains version + * @return + */ + DataCenterNodes getDataCenterNodes(); + + /** + * push node change result + */ + void pushNodeListChange(); + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/AbstractMetaServerTask.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/AbstractMetaServerTask.java new file mode 100644 index 000000000..0bd945001 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/AbstractMetaServerTask.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.task.Retryable; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractMetaServerTask.java, v 0.1 2018-01-15 16:10 shangyu.wh Exp $ + */ +public abstract class AbstractMetaServerTask implements MetaServerTask, Retryable { + + private final static Logger LOGGER = LoggerFactory.getLogger(AbstractMetaServerTask.class, + "[Task]"); + + protected volatile String taskId; + + private AtomicInteger execCount = new AtomicInteger(1); + + @Override + public synchronized String getTaskId() { + if (taskId == null) { + taskId = UUID.randomUUID().toString(); + } + + return taskId; + } + + @Override + public long getExpiryTime() { + return -1; + } + + protected boolean checkRetryTimes(int configTimes) { + if (configTimes > 0) { + if (execCount.incrementAndGet() > configTimes) { + LOGGER.info("retry times more than {},info:{}", configTimes, this); + return false; + } else { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/Constant.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/Constant.java new file mode 100644 index 000000000..52278f3b2 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/Constant.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +/** + * + * @author shangyu.wh + * @version $Id: Constant.java, v 0.1 2018-03-28 14:10 shangyu.wh Exp $ + */ +public class Constant { + + public final static String PUSH_NEED_CONFIRM_KEY = "NEED_CONFIRM"; + + public final static String PUSH_TARGET_DATA_NODE = "PUSH_TARGET_DATA_NODE"; + + public final static String PUSH_TARGET_SESSION_NODE = "PUSH_TARGET_SESSION_NODE"; + + public final static String PUSH_TARGET_TYPE = "PUSH_TARGET_TYPE"; + + public final static String PUSH_TARGET_OPERATOR_TYPE = "PUSH_TARGET_OPERATOR_TYPE"; + + public final static String PUSH_TARGET_CONFIRM_NODE = "PUSH_TARGET_CONFIRM_NODE"; +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/DataNodeChangePushTask.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/DataNodeChangePushTask.java new file mode 100644 index 000000000..db0900c0e --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/DataNodeChangePushTask.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.DataNodeService; +import com.alipay.sofa.registry.server.meta.node.SessionNodeService; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.Map; + +/** + * node info change according local or other dataCenter,push change info to local dataCenter node + * + * @author shangyu.wh + * @version $Id: DataNodeChangePushTask.java, v 0.1 2018-01-23 19:05 shangyu.wh Exp $ + */ +public class DataNodeChangePushTask extends AbstractMetaServerTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeChangePushTask.class, + "[Task]"); + private final SessionNodeService sessionNodeService; + private final DataNodeService dataNodeService; + final private MetaServerConfig metaServerConfig; + final private NodeType nodeType; + private NodeChangeResult nodeChangeResult; + private Boolean confirm; + private String confirmNodeIp; + + private Map targetNodes; + + public DataNodeChangePushTask(NodeType nodeType, MetaServerConfig metaServerConfig) { + this.metaServerConfig = metaServerConfig; + this.nodeType = nodeType; + this.sessionNodeService = (SessionNodeService) ServiceFactory + .getNodeService(NodeType.SESSION); + this.dataNodeService = (DataNodeService) ServiceFactory.getNodeService(NodeType.DATA); + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + + confirm = (Boolean) taskEvent.getAttribute(Constant.PUSH_NEED_CONFIRM_KEY); + targetNodes = (Map) taskEvent + .getAttribute(Constant.PUSH_TARGET_DATA_NODE); + + confirmNodeIp = (String) taskEvent.getAttribute(Constant.PUSH_TARGET_CONFIRM_NODE); + + Object obj = taskEvent.getEventObj(); + if (obj instanceof NodeChangeResult) { + nodeChangeResult = (NodeChangeResult) obj; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + + @Override + public void execute() { + switch (nodeType) { + case SESSION: + sessionNodeService.pushDataNodes(nodeChangeResult); + LOGGER.info("push change to Session Nodes!"); + break; + case DATA: + dataNodeService + .pushDataNodes(nodeChangeResult, targetNodes, confirm, confirmNodeIp); + LOGGER.info("push change to Data Nodes!"); + break; + default: + break; + } + + } + + @Override + public String toString() { + return "DATA_NODE_CHANGE_PUSH_TASK {" + "taskId='" + taskId + '\'' + ", nodeType='" + + nodeType + '\'' + ", nodeChangeRequest=" + nodeChangeResult + '}'; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(metaServerConfig.getDataNodeChangePushTaskRetryTimes()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/MetaServerTask.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/MetaServerTask.java new file mode 100644 index 000000000..7713622f6 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/MetaServerTask.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +import com.alipay.sofa.registry.task.Task; + +/** + * + * @author shangyu.wh + * @version $Id: MataServerTask.java, v 0.1 2018-01-15 15:27 shangyu.wh Exp $ + */ +public interface MetaServerTask extends Task { + +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/PersistenceDataChangeNotifyTask.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/PersistenceDataChangeNotifyTask.java new file mode 100644 index 000000000..63d986fcc --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/PersistenceDataChangeNotifyTask.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.SessionNodeService; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeChangePushTask.java, v 0.1 2018-01-15 16:12 shangyu.wh Exp $ + */ +public class PersistenceDataChangeNotifyTask extends AbstractMetaServerTask { + + private final SessionNodeService sessionNodeService; + + final private MetaServerConfig metaServerConfig; + + private NotifyProvideDataChange notifyProvideDataChange; + + public PersistenceDataChangeNotifyTask(MetaServerConfig metaServerConfig) { + this.metaServerConfig = metaServerConfig; + this.sessionNodeService = (SessionNodeService) ServiceFactory + .getNodeService(NodeType.SESSION); + } + + @Override + public void execute() { + sessionNodeService.notifyProvideDataChange(notifyProvideDataChange); + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + if (obj instanceof NotifyProvideDataChange) { + this.notifyProvideDataChange = (NotifyProvideDataChange) obj; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + + @Override + public String toString() { + return "PERSISTENCE_DATA_CHANGE_NOTIFY_TASK{" + "taskId='" + taskId + '\'' + + ", notifyProvideDataChange=" + notifyProvideDataChange + '}'; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(metaServerConfig.getSessionNodeChangePushTaskRetryTimes()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/ReceiveStatusConfirmNotifyTask.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/ReceiveStatusConfirmNotifyTask.java new file mode 100644 index 000000000..1b2494953 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/ReceiveStatusConfirmNotifyTask.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.StatusConfirmRequest; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.node.DataNodeService; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +/** + * + * @author shangyu.wh + * @version $Id: ReceiveStatusConfirmNotifyTask.java, v 0.1 2018-03-24 17:08 shangyu.wh Exp $ + */ +public class ReceiveStatusConfirmNotifyTask extends AbstractMetaServerTask { + + private final DataNodeService dataNodeService; + final private MetaServerConfig metaServerConfig; + private DataNode dataNode; + + public ReceiveStatusConfirmNotifyTask(DataNodeService dataNodeService, + MetaServerConfig metaServerConfig) { + this.dataNodeService = dataNodeService; + this.metaServerConfig = metaServerConfig; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (obj instanceof DataNode) { + this.dataNode = (DataNode) obj; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + + @Override + public void execute() { + StatusConfirmRequest statusConfirmRequest = new StatusConfirmRequest(dataNode, + dataNode.getNodeStatus()); + dataNodeService.notifyStatusConfirm(statusConfirmRequest); + } + + @Override + public String toString() { + return "RECEIVE_STATUS_CONFIRM_NOTIFY_TASK{" + "taskId='" + taskId + '\'' + ", dataNode=" + + dataNode + '}'; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(metaServerConfig.getReceiveStatusConfirmNotifyTaskRetryTimes()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/SessionNodeChangePushTask.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/SessionNodeChangePushTask.java new file mode 100644 index 000000000..8bf195c4c --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/SessionNodeChangePushTask.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.ServiceFactory; +import com.alipay.sofa.registry.server.meta.node.SessionNodeService; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeChangePushTask.java, v 0.1 2018-01-15 16:12 shangyu.wh Exp $ + */ +public class SessionNodeChangePushTask extends AbstractMetaServerTask { + + private final SessionNodeService sessionNodeService; + final private MetaServerConfig metaServerConfig; + private NodeChangeResult nodeChangeResult; + private Map targetNodes; + private String confirmNodeIp; + + public SessionNodeChangePushTask(MetaServerConfig metaServerConfig) { + this.metaServerConfig = metaServerConfig; + this.sessionNodeService = (SessionNodeService) ServiceFactory + .getNodeService(NodeType.SESSION); + } + + @Override + public void execute() { + sessionNodeService.pushSessions(nodeChangeResult, targetNodes, confirmNodeIp); + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + targetNodes = (Map) taskEvent + .getAttribute(Constant.PUSH_TARGET_SESSION_NODE); + + confirmNodeIp = (String) taskEvent.getAttribute(Constant.PUSH_TARGET_CONFIRM_NODE); + Object obj = taskEvent.getEventObj(); + if (obj instanceof NodeChangeResult) { + this.nodeChangeResult = (NodeChangeResult) obj; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + + @Override + public String toString() { + return "SESSION_NODE_CHANGE_PUSH_TASK{" + "taskId='" + taskId + '\'' + + ", nodeChangeResult=" + nodeChangeResult + '}'; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(metaServerConfig.getSessionNodeChangePushTaskRetryTimes()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/DataNodeSingleTaskProcessor.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/DataNodeSingleTaskProcessor.java new file mode 100644 index 000000000..2715c0917 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/DataNodeSingleTaskProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.task.Retryable; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeSingleTaskProcessor.java, v 0.1 2017-12-11 19:35 shangyu.wh Exp $ + */ +public class DataNodeSingleTaskProcessor implements TaskProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeSingleTaskProcessor.class, + "[Task]"); + + @Override + public ProcessingResult process(MetaServerTask task) { + try { + LOGGER.info("execute " + task); + task.execute(); + LOGGER.info("end " + task); + return ProcessingResult.Success; + } catch (Throwable throwable) { + LOGGER.error("Data node SingleTask Process error!", throwable); + if (task instanceof Retryable) { + Retryable retryAbleTask = (Retryable) task; + if (retryAbleTask.checkRetryTimes()) { + return ProcessingResult.TransientError; + } + } + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/MetaNodeSingleTaskProcessor.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/MetaNodeSingleTaskProcessor.java new file mode 100644 index 000000000..8d6ec5d6c --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/MetaNodeSingleTaskProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.task.Retryable; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: ClientNodeSingleTaskProcessor.java, v 0.1 2017-12-11 19:47 shangyu.wh Exp $ + */ +public class MetaNodeSingleTaskProcessor implements TaskProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaNodeSingleTaskProcessor.class, + "[Task]"); + + @Override + public ProcessingResult process(MetaServerTask task) { + try { + LOGGER.info("execute " + task); + task.execute(); + LOGGER.info("end " + task); + return ProcessingResult.Success; + } catch (Throwable throwable) { + LOGGER.error("Meta node SingleTask Process error!", throwable); + if (task instanceof Retryable) { + Retryable retryAbleTask = (Retryable) task; + if (retryAbleTask.checkRetryTimes()) { + return ProcessingResult.TransientError; + } + } + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/SessionNodeSingleTaskProcessor.java b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/SessionNodeSingleTaskProcessor.java new file mode 100644 index 000000000..ec0e6f7c2 --- /dev/null +++ b/server/server/meta/src/main/java/com/alipay/sofa/registry/server/meta/task/processor/SessionNodeSingleTaskProcessor.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.task.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.task.MetaServerTask; +import com.alipay.sofa.registry.task.Retryable; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeSingleTaskProcessor.java, v 0.1 2018-01-15 16:42 shangyu.wh Exp $ + */ +public class SessionNodeSingleTaskProcessor implements TaskProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger( + SessionNodeSingleTaskProcessor.class, "[Task]"); + + @Override + public ProcessingResult process(MetaServerTask task) { + try { + LOGGER.info("execute " + task); + task.execute(); + LOGGER.info("end " + task); + return ProcessingResult.Success; + + } catch (Throwable throwable) { + LOGGER.error("Session node SingleTask Process error!", throwable); + if (task instanceof Retryable) { + Retryable retryAbleTask = (Retryable) task; + if (retryAbleTask.checkRetryTimes()) { + return ProcessingResult.TransientError; + } + } + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} \ No newline at end of file diff --git a/server/server/meta/src/main/resources/application.properties b/server/server/meta/src/main/resources/application.properties new file mode 100644 index 000000000..2449af5b3 --- /dev/null +++ b/server/server/meta/src/main/resources/application.properties @@ -0,0 +1,12 @@ +spring.main.banner-mode=LOG +#nodes.metaNode=: +#nodes.localDataCenter= + +#meta.server.logging.level=INFO +#meta.server.logging.home=/home/admin/logs/registry/meta +meta.server.sessionServerPort=9610 +meta.server.dataServerPort=9611 +meta.server.metaServerPort=9612 +meta.server.raftServerPort=9614 +meta.server.httpServerPort=9615 +meta.server.raftGroup=MetaServerRaftGroup diff --git a/server/server/meta/src/main/resources/banner.txt b/server/server/meta/src/main/resources/banner.txt new file mode 100644 index 000000000..500fe78d8 --- /dev/null +++ b/server/server/meta/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + + __ __ _ ____ + | \/ | ___| |_ __ _ / ___| ___ _ ____ _____ _ __ + | |\/| |/ _ \ __/ _` | \___ \ / _ \ '__\ \ / / _ \ '__| + | | | | __/ || (_| | ___) | __/ | \ V / __/ | + |_| |_|\___|\__\__,_| |____/ \___|_| \_/ \___|_| + \ No newline at end of file diff --git a/server/server/meta/src/main/resources/logback-spring.xml b/server/server/meta/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..9251cda98 --- /dev/null +++ b/server/server/meta/src/main/resources/logback-spring.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + + + + + true + + ERROR + + ${META_LOG_HOME}/common-error.log + + ${META_LOG_HOME}/common-error.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/common-default.log + + ${META_LOG_HOME}/common-default.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-raft.log + + ${META_LOG_HOME}/registry-raft.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-meta.log + + ${META_LOG_HOME}/registry-meta.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-startup.log + + ${META_LOG_HOME}/registry-startup.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-connect.log + + ${META_LOG_HOME}/registry-connect.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-raft-metrics.log + + ${META_LOG_HOME}/registry-raft-metrics.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${META_LOG_HOME}/registry-http.log + + ${META_LOG_HOME}/registry-http.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/BaseTest.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/BaseTest.java new file mode 100644 index 000000000..cd751ec3c --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/BaseTest.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test; + +import org.springframework.boot.SpringBootConfiguration; + +/** + * + * @author shangyu.wh + * @version $Id: BaseTest.java, v 0.1 2017-12-14 21:47 shangyu.wh Exp $ + */ +@SpringBootConfiguration +public class BaseTest { +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ConcurrentTestUtil.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ConcurrentTestUtil.java new file mode 100644 index 000000000..44bacff98 --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ConcurrentTestUtil.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; + +/** + * + * @author shangyu.wh + * @version $Id: ConcurrentTestUtil.java, v 0.1 2018-08-14 22:33 shangyu.wh Exp $ + */ +public class ConcurrentTestUtil { + public static void assertConcurrent(final String message, + final List runnables, + final int maxTimeoutSeconds) throws InterruptedException { + final int numThreads = runnables.size(); + final List exceptions = Collections.synchronizedList(new ArrayList()); + final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); + try { + final CountDownLatch allExecutorThreadsReady = new CountDownLatch(numThreads); + final CountDownLatch afterInitBlocker = new CountDownLatch(1); + final CountDownLatch allDone = new CountDownLatch(numThreads); + for (final Runnable submittedTestRunnable : runnables) { + threadPool.submit(() -> { + allExecutorThreadsReady.countDown(); + try { + afterInitBlocker.await(); + submittedTestRunnable.run(); + } catch (final Throwable e) { + exceptions.add(e); + } finally { + allDone.countDown(); + } + }); + } + // wait until all threads are ready + assertTrue( + "Timeout initializing threads! Perform long lasting initializations before passing runnables to assertConcurrent", + allExecutorThreadsReady.await(runnables.size() * 10, TimeUnit.MILLISECONDS)); + // start all test runners + afterInitBlocker.countDown(); + assertTrue(message + " timeout! More than" + maxTimeoutSeconds + "seconds", + allDone.await(maxTimeoutSeconds, TimeUnit.SECONDS)); + } finally { + threadPool.shutdownNow(); + } + assertTrue(message + "failed with exception(s)" + exceptions, exceptions.isEmpty()); + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/HttpTest.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/HttpTest.java new file mode 100644 index 000000000..22683950e --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/HttpTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.jersey.JerseyClient; +import com.alipay.sofa.registry.server.meta.MetaApplication; +import com.alipay.sofa.registry.server.meta.bootstrap.EnableMetaServer; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig.DecisionMode; +import org.apache.commons.io.FileUtils; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriBuilder; +import java.io.File; +import java.net.HttpURLConnection; +import java.net.URI; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * + * @author shangyu.wh + * @version $Id: HttpTest.java, v 0.1 2018-02-01 17:01 shangyu.wh Exp $ + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = MetaApplication.class) +@EnableMetaServer +public class HttpTest extends BaseTest { + + @BeforeClass + public static void beforeClass() throws Exception { + System.setProperty("nodes.metaNode", "registry-stable:" + + NetUtil.getLocalAddress().getHostAddress()); + System.setProperty("nodes.localDataCenter", "registry-stable"); + FileUtils.deleteDirectory(new File(System.getProperty("user.home") + File.separator + + "raftData")); + } + + @Test + public void testDecisionMode() { + URL url = new URL(NetUtil.getLocalAddress().getHostAddress(), 9615); + JerseyClient jerseyClient = JerseyClient.getInstance(); + Channel channel = jerseyClient.connect(url); + Result response = channel.getWebTarget().path("decisionMode").request() + .post(Entity.entity(DecisionMode.OFF, MediaType.APPLICATION_JSON), Result.class); + + assertTrue(response.isSuccess()); + } + + @Test + public void testConnect() throws Exception { + URL targetUrl = new URL(NetUtil.getLocalAddress().getHostAddress(), 9615); + java.net.URL urlnet = new java.net.URL("http", targetUrl.getIpAddress(), + targetUrl.getPort(), ""); + URI uri = urlnet.toURI(); + java.net.URL getUrl = UriBuilder.fromUri(uri).path("decisionMode").build().toURL(); + + HttpURLConnection connection = (HttpURLConnection) getUrl.openConnection(); + try { + connection.setDoOutput(true); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON); + + assertEquals(HttpURLConnection.HTTP_OK, connection.getResponseCode()); + } finally { + connection.disconnect(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ProcessResponseTest.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ProcessResponseTest.java new file mode 100644 index 000000000..f9c7b93ff --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/ProcessResponseTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test; + +import com.alipay.sofa.registry.jraft.command.ProcessResponse; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: ProcessResponseTest.java, v 0.1 2018-08-14 22:20 shangyu.wh Exp $ + */ +public class ProcessResponseTest { + + @Test + public void testProcessResponse() throws InterruptedException { + + int number = 500; + + AtomicInteger count = new AtomicInteger(); + List list = new ArrayList(); + for (int i = 0; i < number; i++) { + if (i % 2 == 0) { + list.add(() -> { + ProcessResponse response = ProcessResponse.fail("Can not find service %s from process!").build(); + if (response != null) { + if (!response.getSuccess()) { + count.incrementAndGet(); + } + } + }); + } else { + list.add(() -> { + ProcessResponse response = ProcessResponse.ok("Can not find service %s from process!").build(); + if (response != null) { + if (response.getSuccess()) { + count.incrementAndGet(); + } + } + }); + } + + } + ConcurrentTestUtil.assertConcurrent("多线程build序列化", list, 10); + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataNodeChangePushTaskListenerMock.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataNodeChangePushTaskListenerMock.java new file mode 100644 index 000000000..162df86cd --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataNodeChangePushTaskListenerMock.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test.confirm; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.server.meta.store.DataStoreService; +import com.alipay.sofa.registry.server.meta.task.Constant; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeChangePushTaskListenerMoke.java, v 0.1 2018-03-28 16:20 shangyu.wh Exp $ + */ +public class DataNodeChangePushTaskListenerMock implements TaskListener { + + private DataStoreService dataStoreService; + + private Collection removeNodes; + + public DataNodeChangePushTaskListenerMock(DataStoreService dataStoreService, + Collection removeNodes) { + this.dataStoreService = dataStoreService; + this.removeNodes = removeNodes; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.DATA_NODE_CHANGE_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + NodeType nodeType = (NodeType) event.getAttribute(Constant.PUSH_TARGET_TYPE); + String ip = (String) event.getAttribute(Constant.PUSH_TARGET_CONFIRM_NODE); + + Map targetNodes = (Map) event + .getAttribute(Constant.PUSH_TARGET_DATA_NODE); + switch (nodeType) { + case SESSION: + break; + case DATA: + final ExecutorService threadPool = Executors.newSingleThreadExecutor(); + try { + threadPool.submit(() -> targetNodes.forEach((address, dataNode) -> { + if (removeNodes == null || !removeNodes.contains(address)) { + dataStoreService.confirmNodeStatus(address, ip); + } + })); + break; + } finally { + threadPool.shutdown(); + } + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataServerConfirmTest.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataServerConfirmTest.java new file mode 100644 index 000000000..077c2a311 --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/DataServerConfirmTest.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test.confirm; + +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig; +import com.alipay.sofa.registry.server.meta.bootstrap.MetaServerConfig.DecisionMode; +import com.alipay.sofa.registry.server.meta.bootstrap.NodeConfig; +import com.alipay.sofa.registry.server.meta.repository.service.DataConfirmStatusService; +import com.alipay.sofa.registry.server.meta.repository.service.DataRepositoryService; +import com.alipay.sofa.registry.server.meta.store.DataStoreService; +import com.alipay.sofa.registry.task.listener.DefaultTaskListenerManager; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import com.alipay.sofa.registry.task.scheduler.TimedSupervisorTask; +import org.junit.Test; + +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * + * @author shangyu.wh + * @version $Id: DataServerConfirmTest.java, v 0.1 2018-03-27 17:13 shangyu.wh Exp $ + */ +public class DataServerConfirmTest { + + @Test + public void testDataServerRegisterConfirm() throws InterruptedException { + + DataStoreService dataStoreService = new DataStoreService(); + + DataConfirmStatusService dataConfirmStatusService = new DataConfirmStatusService(); + + NodeConfig nodeConfig = mock(NodeConfig.class); + MetaServerConfig metaServerConfig = mock(MetaServerConfig.class); + TaskListenerManager taskListenerManager = new DefaultTaskListenerManager(); + taskListenerManager + .addTaskListener(new DataNodeChangePushTaskListenerMock(dataStoreService, null)); + taskListenerManager.addTaskListener(new ReceiveStatusConfirmNotifyTaskMock()); + + dataStoreService.setNodeConfig(nodeConfig); + dataStoreService.setTaskListenerManager(taskListenerManager); + dataStoreService.setDataConfirmStatusService(dataConfirmStatusService); + + DataRepositoryService dataRepositoryService = new DataRepositoryService(); + dataRepositoryService.setNodeConfig(nodeConfig); + dataStoreService.setDataRepositoryService(dataRepositoryService); + + when(nodeConfig.getLocalDataCenter()).thenReturn("DefaultDataCenter"); + when(metaServerConfig.getDecisionMode()).thenReturn(DecisionMode.RUNTIME); + + //dataStoreService.pushDataNodeListChange(); + start(dataStoreService); + + int numThreads = 10; + final CountDownLatch allDone = new CountDownLatch(numThreads); + final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); + + for (int i = 0; i < numThreads; i++) { + final int n = i; + threadPool.execute(() -> dataStoreService.addNode(new NodeTest(new URL("192.168.0." + n, 0), allDone))); + } + + assertTrue(" timeout! More than" + 60 + "seconds,allDone:" + allDone.getCount(), + allDone.await(60, TimeUnit.SECONDS)); + } + + @Test + public void testDataServerRegisterConfirmWithRemove() throws InterruptedException { + + DataStoreService dataStoreService = new DataStoreService(); + DataConfirmStatusService dataConfirmStatusService = new DataConfirmStatusService(); + NodeConfig nodeConfig = mock(NodeConfig.class); + MetaServerConfig metaServerConfig = mock(MetaServerConfig.class); + TaskListenerManager taskListenerManager = new DefaultTaskListenerManager(); + + Collection removeNodes = new CopyOnWriteArrayList<>(); + + removeNodes.add("192.168.0.4"); + removeNodes.add("192.168.0.5"); + removeNodes.add("192.168.0.17"); + removeNodes.add("192.168.0.21"); + removeNodes.add("192.168.0.10"); + removeNodes.add("192.168.0.24"); + + taskListenerManager + .addTaskListener(new DataNodeChangePushTaskListenerMock(dataStoreService, removeNodes)); + taskListenerManager.addTaskListener(new ReceiveStatusConfirmNotifyTaskMock()); + + dataStoreService.setNodeConfig(nodeConfig); + dataStoreService.setTaskListenerManager(taskListenerManager); + dataStoreService.setDataConfirmStatusService(dataConfirmStatusService); + + DataRepositoryService dataRepositoryService = new DataRepositoryService(); + dataRepositoryService.setNodeConfig(nodeConfig); + dataStoreService.setDataRepositoryService(dataRepositoryService); + + when(nodeConfig.getLocalDataCenter()).thenReturn("DefaultDataCenter"); + when(metaServerConfig.getDecisionMode()).thenReturn(DecisionMode.RUNTIME); + + //dataStoreService.pushDataNodeListChange(); + start(dataStoreService); + int numThreads = 10; + //done number = node + final CountDownLatch allDone = new CountDownLatch(numThreads); + final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads); + try { + + for (int i = 0; i < numThreads; i++) { + final int n = i; + threadPool.execute(() -> dataStoreService.addNode(new NodeTest(new URL("192.168.0." + n, 0), allDone))); + } + TimeUnit.MILLISECONDS.sleep(2000); + removeNodes.forEach(dataStoreService::removeNode); + + assertTrue(" timeout! More than" + 60 + "seconds, allDone:" + allDone.getCount(), + allDone.await(60, TimeUnit.SECONDS)); + } finally { + threadPool.shutdown(); + } + } + + private void start(DataStoreService dataStoreService) { + + ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4); + ThreadPoolExecutor checkDataNodeListChangeExecutor = new ThreadPoolExecutor(1, 2, + 0, TimeUnit.SECONDS, new SynchronousQueue<>()); + + scheduler.schedule(new TimedSupervisorTask("CheckDataNodeListChange", scheduler, + checkDataNodeListChangeExecutor, 500, TimeUnit.MILLISECONDS, 3, + dataStoreService::pushNodeListChange), 1, TimeUnit.SECONDS); + } + + class NodeTest extends DataNode { + private final CountDownLatch allDone; + + public NodeTest(URL nodeUrl, CountDownLatch allDone) { + super(nodeUrl, "DefaultDataCenter"); + this.allDone = allDone; + } + + /** + * Getter method for property allDone. + * + * @return property value of allDone + */ + public CountDownLatch getAllDone() { + return allDone; + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/ReceiveStatusConfirmNotifyTaskMock.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/ReceiveStatusConfirmNotifyTaskMock.java new file mode 100644 index 000000000..bbdf33c62 --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/ReceiveStatusConfirmNotifyTaskMock.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test.confirm; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.meta.test.confirm.DataServerConfirmTest.NodeTest; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; + +/** + * + * @author shangyu.wh + * @version $Id: ReceiveStatusConfirmNotifyTaskMock.java, v 0.1 2018-03-28 16:38 shangyu.wh Exp $ + */ +public class ReceiveStatusConfirmNotifyTaskMock implements TaskListener { + + private static final Logger LOGGER = LoggerFactory.getLogger( + ReceiveStatusConfirmNotifyTaskMock.class, "[Task]"); + + @Override + public boolean support(TaskEvent event) { + return TaskType.RECEIVE_STATUS_CONFIRM_NOTIFY_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + Object obj = event.getEventObj(); + + if (obj instanceof NodeTest) { + ((NodeTest) obj).getAllDone().countDown(); + LOGGER.info("Notify:{}", ((NodeTest) obj)); + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/SessionNodeChangePushTaskMock.java b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/SessionNodeChangePushTaskMock.java new file mode 100644 index 000000000..8861c623a --- /dev/null +++ b/server/server/meta/src/test/java/com/alipay/sofa/registry/server/meta/test/confirm/SessionNodeChangePushTaskMock.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.meta.test.confirm; + +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.server.meta.store.SessionStoreService; +import com.alipay.sofa.registry.server.meta.task.Constant; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeChangePushTask.java, v 0.1 2018-01-15 16:12 shangyu.wh Exp $ + */ +public class SessionNodeChangePushTaskMock implements TaskListener { + + private SessionStoreService sessionStoreService; + + private Collection removeNodes; + + public SessionNodeChangePushTaskMock(SessionStoreService sessionStoreService, + Collection removeNodes) { + this.sessionStoreService = sessionStoreService; + this.removeNodes = removeNodes; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.SESSION_NODE_CHANGE_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + Map targetNodes = (Map) event + .getAttribute(Constant.PUSH_TARGET_SESSION_NODE); + + String ip = (String) event.getAttribute(Constant.PUSH_TARGET_CONFIRM_NODE); + final ExecutorService threadPool = Executors.newSingleThreadExecutor(); + try { + + threadPool.submit(() -> targetNodes.forEach((address, dataNode) -> { + + if (removeNodes == null || !removeNodes.contains(address)) { + sessionStoreService.confirmNodeStatus(address, ip); + } + })); + } finally { + threadPool.shutdown(); + } + } +} \ No newline at end of file diff --git a/server/server/meta/src/test/resources/application.properties b/server/server/meta/src/test/resources/application.properties new file mode 100644 index 000000000..386132e80 --- /dev/null +++ b/server/server/meta/src/test/resources/application.properties @@ -0,0 +1,9 @@ +spring.main.banner-mode=LOG +meta.server.logging.level=INFO +meta.server.sessionServerPort=9610 +meta.server.dataServerPort=9611 +meta.server.metaServerPort=9612 +meta.server.raftServerPort=9614 +meta.server.httpServerPort=9615 +meta.server.raftGroup=MetaServerRaftGroup +meta.server.decisionMode=RUNTIME \ No newline at end of file diff --git a/server/server/meta/src/test/resources/logback-test.xml b/server/server/meta/src/test/resources/logback-test.xml new file mode 100644 index 000000000..5598cba71 --- /dev/null +++ b/server/server/meta/src/test/resources/logback-test.xml @@ -0,0 +1,27 @@ + + + + + + \ No newline at end of file diff --git a/server/server/pom.xml b/server/server/pom.xml new file mode 100644 index 000000000..30a7de600 --- /dev/null +++ b/server/server/pom.xml @@ -0,0 +1,26 @@ + + + + com.alipay.sofa + registry-server-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-server + pom + + + ../../ + + + + session + data + meta + integration + + diff --git a/server/server/session/pom.xml b/server/server/session/pom.xml new file mode 100644 index 000000000..25d435d51 --- /dev/null +++ b/server/server/session/pom.xml @@ -0,0 +1,102 @@ + + + + com.alipay.sofa + registry-server + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-server-session + + + ../../../ + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + com.alipay.sofa + registry-remoting-api + + + com.google.guava + guava + + + com.alipay.sofa + registry-common-util + + + com.alipay.sofa + registry-remoting-bolt + + + com.alipay.sofa + registry-common-model + + + com.alipay.sofa + hessian + + + io.netty + netty-all + + + com.alipay.sofa + registry-remoting-http + + + org.hibernate + hibernate-validator + + + com.google.protobuf + protobuf-java + + + com.alipay.sofa + registry-store-jraft + + + commons-lang + commons-lang + + + + + registry-server-session + + + org.springframework.boot + spring-boot-maven-plugin + + ./target + executable + + + + + repackage + + + false + + + + + + + diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/SessionApplication.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/SessionApplication.java new file mode 100644 index 000000000..be15b48ed --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/SessionApplication.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SessionApplication.java, v 0.1 2017-11-13 20:19 zhuoyu.sjw Exp $$ + */ +@SpringBootApplication +@EnableScheduling +public class SessionApplication { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionApplication.class); + + public static void main(String[] args) { + // setup DefaultUncaughtExceptionHandler + Thread.setDefaultUncaughtExceptionHandler((t, e) -> { + LOGGER.error(String.format("UncaughtException in Thread(%s): %s", t.getName(), e.getMessage()), e); + }); + + SpringApplication.run(SessionApplication.class, args); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/CommonConfig.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/CommonConfig.java new file mode 100644 index 000000000..71e4f81a2 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/CommonConfig.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.bootstrap; + +import org.springframework.beans.factory.annotation.Value; + +import java.util.Collection; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: CommonConfig.java, v 0.1 2018-05-05 15:16 shangyu.wh Exp $ + */ +public class CommonConfig { + + /** + * server local data center, get from System Property + * example: nodes.localDataCenter=DefaultDataCenter + */ + @Value("${nodes.localDataCenter}") + private String localDataCenter; + + /** + * server local region, get from System Property + * example: nodes.localRegion=DEFAULT_ZONE + */ + @Value("${nodes.localRegion}") + private String localRegion; + + /** + * metaNodeInfo, get from System Property + * example: nodes.metaNode=DefaultDataCenter:192.168.xxx.xxx,192.168.xxx.xxx,192.168.xxx.xxx|AnotherDataCenter:192.168.xxx.xxx,192.168.xxx.xxx,192.168.xxx.xxx + */ + @Value("#{PropertySplitter.mapOfList('${nodes.metaNode}')}") + private Map> metaNode; + + /** + * Getter method for property metaNode. + * + * @return property value of metaNode + */ + public Map> getMetaNode() { + return metaNode; + } + + /** + * Setter method for property metaNode. + * + * @param metaNode value to be assigned to property metaNode + */ + public void setMetaNode(Map> metaNode) { + this.metaNode = metaNode; + } + + /** + * Getter method for property localDataCenter. + * + * @return property value of localDataCenter + */ + public String getLocalDataCenter() { + return localDataCenter; + } + + /** + * Getter method for property localRegion. + * + * @return property value of localRegion + */ + public String getLocalRegion() { + return localRegion; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerBootstrap.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerBootstrap.java new file mode 100644 index 000000000..87b01b6bb --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerBootstrap.java @@ -0,0 +1,431 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.bootstrap; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.metaserver.FetchProvideDataRequest; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.ProvideData; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManagerFactory; +import com.alipay.sofa.registry.server.session.node.RaftClientManager; +import com.alipay.sofa.registry.server.session.node.SessionProcessIdGenerator; +import com.alipay.sofa.registry.server.session.remoting.handler.AbstractClientHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import javax.ws.rs.Path; +import javax.ws.rs.ext.Provider; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * The type Session server bootstrap. + * @author shangyu.wh + * @version $Id : SessionServerBootstrap.java, v 0.1 2017-11-14 11:44 synex Exp $ + */ +public class SessionServerBootstrap { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionServerBootstrap.class); + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private Exchange jerseyExchange; + + @Autowired + private ExecutorManager executorManager; + + @Resource(name = "serverHandlers") + private Collection serverHandlers; + + @Resource(name = "dataClientHandlers") + private Collection dataClientHandlers; + + @Autowired + private NodeManager dataNodeManager; + + @Autowired + private NodeManager metaNodeManager; + + @Autowired + protected NodeExchanger metaNodeExchanger; + + @Autowired + private ResourceConfig jerseyResourceConfig; + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private RaftClientManager raftClientManager; + + private Server server; + + private Server httpServer; + + private Client dataClient; + + private Client metaClient; + + private AtomicBoolean metaStart = new AtomicBoolean(false); + + private AtomicBoolean schedulerStart = new AtomicBoolean(false); + + private AtomicBoolean httpStart = new AtomicBoolean(false); + + private AtomicBoolean serverStart = new AtomicBoolean(false); + + private AtomicBoolean dataStart = new AtomicBoolean(false); + + /** + * Do initialized. + */ + public void doInitialized() { + try { + initEnvironment(); + + startRaftClient(); + + connectMetaServer(); + + startScheduler(); + + openHttpServer(); + + openSessionServer(); + + connectDataServer(); + + LOGGER.info("Initialized Session Server..."); + + Runtime.getRuntime().addShutdownHook(new Thread(this::doStop)); + } catch (Throwable e) { + LOGGER.error("Cannot bootstrap session server :", e); + throw new RuntimeException("Cannot bootstrap session server :", e); + } + } + + /** + * Destroy. + */ + public void destroy() { + doStop(); + } + + private void doStop() { + try { + LOGGER.info("{} Shutting down Session Server..", new Date().toString()); + + executorManager.stopScheduler(); + TaskDispatchers.stopDefaultSingleTaskDispatcher(); + closeClients(); + stopHttpServer(); + stopServer(); + } catch (Throwable e) { + LOGGER.error("Shutting down Session Server error!", e); + } + LOGGER.info("{} Session server is now shutdown...", new Date().toString()); + } + + private void initEnvironment() { + LOGGER.info("Session server Environment: DataCenter {},Region {},ProcessId {}", + sessionServerConfig.getSessionServerDataCenter(), + sessionServerConfig.getSessionServerRegion(), + SessionProcessIdGenerator.getSessionProcessId()); + } + + private void startScheduler() { + + try { + if (schedulerStart.compareAndSet(false, true)) { + executorManager.startScheduler(); + LOGGER.info("Session Scheduler started!"); + } + } catch (Exception e) { + schedulerStart.set(false); + LOGGER.error("Session Scheduler start error!", e); + throw new RuntimeException("Session Scheduler start error!", e); + } + } + + private void openSessionServer() { + try { + if (serverStart.compareAndSet(false, true)) { + server = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(), + sessionServerConfig.getServerPort()), serverHandlers + .toArray(new ChannelHandler[serverHandlers.size()])); + + LOGGER.info("Session server started! port:{}", sessionServerConfig.getServerPort()); + } + } catch (Exception e) { + serverStart.set(false); + LOGGER.error("Session server start error! port:{}", + sessionServerConfig.getServerPort(), e); + throw new RuntimeException("Session server start error!", e); + } + } + + private void connectDataServer() { + try { + if (dataStart.compareAndSet(false, true)) { + Collection dataNodes = dataNodeManager.getDataCenterNodes(); + if (CollectionUtils.isEmpty(dataNodes)) { + dataNodeManager.getAllDataCenterNodes(); + dataNodes = dataNodeManager.getDataCenterNodes(); + } + if (!CollectionUtils.isEmpty(dataNodes)) { + for (Node dataNode : dataNodes) { + if (dataNode.getNodeUrl() == null + || dataNode.getNodeUrl().getIpAddress() == null) { + LOGGER + .error("get data node address error!url{}", dataNode.getNodeUrl()); + continue; + } + dataClient = boltExchange.connect( + Exchange.DATA_SERVER_TYPE, + new URL(dataNode.getNodeUrl().getIpAddress(), sessionServerConfig + .getDataServerPort()), dataClientHandlers + .toArray(new ChannelHandler[dataClientHandlers.size()])); + } + LOGGER.info("Data server connected {} server! port:{}", dataNodes.size(), + sessionServerConfig.getDataServerPort()); + } + } + } catch (Exception e) { + dataStart.set(false); + LOGGER.error("Data server connected server error! port:{}", + sessionServerConfig.getDataServerPort(), e); + throw new RuntimeException("Data server connected server error!", e); + } + } + + private void startRaftClient() { + raftClientManager.startRaftClient(); + LOGGER.info("Raft Client started! Leader:{}", raftClientManager.getLeader()); + } + + private void connectMetaServer() { + try { + if (metaStart.compareAndSet(false, true)) { + metaClient = metaNodeExchanger.connectServer(); + + int size = metaClient.getChannels().size(); + + URL leaderUrl = new URL(raftClientManager.getLeader().getIp(), + sessionServerConfig.getMetaServerPort()); + + registerSessionNode(leaderUrl); + + getAllDataCenter(); + + fetchStopPushSwitch(leaderUrl); + + LOGGER.info("MetaServer connected {} server! Port:{}", size, + sessionServerConfig.getMetaServerPort()); + } + } catch (Exception e) { + metaStart.set(false); + LOGGER.error("MetaServer connected server error! Port:{}", + sessionServerConfig.getMetaServerPort(), e); + throw new RuntimeException("MetaServer connected server error!", e); + } + } + + private void registerSessionNode(URL leaderUrl) { + URL clientUrl = new URL(NetUtil.getLocalAddress().getHostAddress(), 0); + SessionNode sessionNode = new SessionNode(clientUrl, + sessionServerConfig.getSessionServerRegion()); + Object ret = sendMetaRequest(sessionNode, leaderUrl); + if (ret instanceof NodeChangeResult) { + NodeChangeResult nodeChangeResult = (NodeChangeResult) ret; + NodeManager nodeManager = NodeManagerFactory.getNodeManager(nodeChangeResult + .getNodeType()); + //update data node info + nodeManager.updateNodes(nodeChangeResult); + LOGGER.info("Register MetaServer Session Node success!get data node list {}", + nodeChangeResult.getNodes()); + } + } + + private void fetchStopPushSwitch(URL leaderUrl) { + FetchProvideDataRequest fetchProvideDataRequest = new FetchProvideDataRequest( + ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID); + Object ret = sendMetaRequest(fetchProvideDataRequest, leaderUrl); + if (ret instanceof ProvideData) { + ProvideData provideData = (ProvideData) ret; + if (provideData.getProvideData() == null + || provideData.getProvideData().getObject() == null) { + LOGGER.info("Fetch session stop push switch no data existed,config not change!"); + return; + } + String data = (String) provideData.getProvideData().getObject(); + sessionServerConfig.setStopPushSwitch(Boolean.valueOf(data)); + if (data != null) { + if (!Boolean.valueOf(data)) { + //stop push init on,then begin fetch data schedule task + sessionServerConfig.setBeginDataFetchTask(true); + } + } + LOGGER.info("Fetch session stop push data switch {} success!", data); + } else { + LOGGER.info("Fetch session stop push switch data null,config not change!"); + } + } + + private Object sendMetaRequest(Object request, URL leaderUrl) { + Object ret; + try { + ret = metaClient.sendSync(metaClient.getChannel(leaderUrl), request, + sessionServerConfig.getMetaNodeExchangeTimeOut()); + } catch (Exception e) { + URL leaderUrlNew = new URL(raftClientManager.refreshLeader().getIp(), + sessionServerConfig.getMetaServerPort()); + LOGGER.warn("request send error!It will be retry once to new leader {}!", leaderUrlNew); + ret = metaClient.sendSync(metaClient.getChannel(leaderUrlNew), request, + sessionServerConfig.getMetaNodeExchangeTimeOut()); + } + return ret; + } + + private void getAllDataCenter() { + //get meta node info + metaNodeManager.getAllDataCenterNodes(); + LOGGER.info("Get all dataCenter from meta Server success!"); + } + + private void openHttpServer() { + try { + if (httpStart.compareAndSet(false, true)) { + bindResourceConfig(); + httpServer = jerseyExchange.open( + new URL(NetUtil.getLocalAddress().getHostAddress(), sessionServerConfig + .getHttpServerPort()), new ResourceConfig[] { jerseyResourceConfig }); + LOGGER.info("Open http server port {} success!", + sessionServerConfig.getHttpServerPort()); + } + } catch (Exception e) { + LOGGER.error("Open http server port {} error!", + sessionServerConfig.getHttpServerPort(), e); + httpStart.set(false); + throw new RuntimeException("Open http server error!", e); + } + } + + private void bindResourceConfig() { + registerInstances(Path.class); + registerInstances(Provider.class); + } + + private void registerInstances(Class annotationType) { + Map beans = applicationContext.getBeansWithAnnotation(annotationType); + if (beans != null && !beans.isEmpty()) { + beans.forEach((beanName, bean) -> { + jerseyResourceConfig.registerInstances(bean); + jerseyResourceConfig.register(bean.getClass()); + }); + } + } + + private void stopServer() { + if (server != null && server.isOpen()) { + server.close(); + } + } + + private void closeClients() { + if (dataClient != null && !dataClient.isClosed()) { + dataClient.close(); + } + } + + private void stopHttpServer() { + if (httpServer != null && httpServer.isOpen()) { + httpServer.close(); + } + } + + /** + * Getter method for property metaStart. + * + * @return property value of metaStart + */ + public AtomicBoolean getMetaStart() { + return metaStart; + } + + /** + * Getter method for property schedulerStart. + * + * @return property value of schedulerStart + */ + public AtomicBoolean getSchedulerStart() { + return schedulerStart; + } + + /** + * Getter method for property httpStart. + * + * @return property value of httpStart + */ + public AtomicBoolean getHttpStart() { + return httpStart; + } + + /** + * Getter method for property serverStart. + * + * @return property value of serverStart + */ + public AtomicBoolean getServerStart() { + return serverStart; + } + + /** + * Getter method for property dataStart. + * + * @return property value of dataStart + */ + public AtomicBoolean getDataStart() { + return dataStart; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfig.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfig.java new file mode 100644 index 000000000..98668f574 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfig.java @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.bootstrap; + +/** + * SessionServerConfig Interface + * @author shangyu.wh + * @version $Id: SessionServerConfig.java, v 0.1 2017-11-14 11:47 synex Exp $ + */ +public interface SessionServerConfig { + + int getServerPort(); + + int getMetaServerPort(); + + int getDataServerPort(); + + int getHttpServerPort(); + + int getSchedulerHeartbeatTimeout(); + + int getSchedulerHeartbeatFirstDelay(); + + int getSchedulerHeartbeatExpBackOffBound(); + + int getSchedulerGetSessionNodeTimeout(); + + int getSchedulerGetSessionNodeFirstDelay(); + + int getSchedulerGetSessionNodeExpBackOffBound(); + + int getSchedulerFetchDataTimeout(); + + int getSchedulerFetchDataFirstDelay(); + + int getSchedulerFetchDataExpBackOffBound(); + + int getClientNodeExchangeTimeOut(); + + int getDataNodeExchangeTimeOut(); + + int getMetaNodeExchangeTimeOut(); + + String getSessionServerRegion(); + + String getSessionServerDataCenter(); + + int getReceivedDataMultiPushTaskRetryTimes(); + + int getCancelDataTaskRetryTimes(); + + int getCancelDataTaskRetryFirstDelay(); + + long getCancelDataTaskRetryIncrementDelay(); + + int getDataChangeFetchTaskRetryTimes(); + + int getSubscriberRegisterFetchRetryTimes(); + + int getSessionRegisterDataServerTaskRetryTimes(); + + int getSchedulerConnectMetaTimeout(); + + int getSchedulerConnectMetaFirstDelay(); + + int getSchedulerConnectMetaExpBackOffBound(); + + int getSchedulerConnectDataTimeout(); + + int getSchedulerConnectDataFirstDelay(); + + int getSchedulerConnectDataExpBackOffBound(); + + int getAccessDataExecutorMinPoolSize(); + + int getAccessDataExecutorMaxPoolSize(); + + int getAccessDataExecutorQueueSize(); + + long getAccessDataExecutorKeepAliveTime(); + + int getDataChangeExecutorMinPoolSize(); + + int getDataChangeExecutorMaxPoolSize(); + + int getDataChangeExecutorQueueSize(); + + long getDataChangeExecutorKeepAliveTime(); + + int getPushTaskExecutorMinPoolSize(); + + int getPushTaskExecutorMaxPoolSize(); + + int getPushTaskExecutorQueueSize(); + + long getPushTaskExecutorKeepAliveTime(); + + int getDisconnectClientExecutorMinPoolSize(); + + int getDisconnectClientExecutorMaxPoolSize(); + + int getDisconnectClientExecutorQueueSize(); + + int getDataChangeFetchTaskMaxBufferSize(); + + int getDataChangeFetchTaskWorkerSize(); + + int getUserDataPushRetryWheelTicksSize(); + + int getUserDataPushRetryWheelTicksDuration(); + + int getPushDataTaskRetryFirstDelay(); + + long getPushDataTaskRetryIncrementDelay(); + + int getNumberOfReplicas(); + + boolean isStopPushSwitch(); + + void setStopPushSwitch(boolean stopPushSwitch); + + boolean isBeginDataFetchTask(); + + void setBeginDataFetchTask(boolean beginDataFetchTask); + + boolean isInvalidForeverZone(String zoneId); + + boolean isInvalidIgnored(String dataId); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfigBean.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfigBean.java new file mode 100644 index 000000000..916c5d641 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfigBean.java @@ -0,0 +1,1351 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.bootstrap; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * The type Session server config bean. + * @author shangyu.wh + * @version $Id : SessionServerConfigBean.java, v 0.1 2017-11-14 11:49 synex Exp $ + */ +@ConfigurationProperties(prefix = SessionServerConfigBean.PREFIX) +public class SessionServerConfigBean implements SessionServerConfig { + + /** + * The constant PREFIX. + */ + public static final String PREFIX = "session.server"; + + private int serverPort = 9600; + + private int metaServerPort = 9610; + + private int dataServerPort = 9620; + + private int httpServerPort; + + private int schedulerHeartbeatTimeout = 3; + + private int schedulerHeartbeatFirstDelay = 3; + + private int schedulerHeartbeatExpBackOffBound = 10; + + private int schedulerGetSessionNodeTimeout = 3; + + private int schedulerGetSessionNodeFirstDelay = 5; + + private int schedulerGetSessionNodeExpBackOffBound = 10; + + private int schedulerFetchDataTimeout = 1; //MINUTES + + private int schedulerFetchDataFirstDelay = 30; + + private int schedulerFetchDataExpBackOffBound = 10; + + private int schedulerConnectMetaTimeout = 5; + + private int schedulerConnectMetaFirstDelay = 5; + + private int schedulerConnectMetaExpBackOffBound = 10; + + private int schedulerConnectDataTimeout = 3; + + private int schedulerConnectDataFirstDelay = 3; + + private int schedulerConnectDataExpBackOffBound = 10; + + private int cancelDataTaskRetryTimes = 5; + + private int cancelDataTaskRetryFirstDelay = 100; + + private long cancelDataTaskRetryIncrementDelay = 200; + + private int dataChangeFetchTaskRetryTimes = 3; + + private int subscriberRegisterFetchRetryTimes = 3; + + private int receivedDataMultiPushTaskRetryTimes = 3; + + private int sessionRegisterDataServerTaskRetryTimes = 5; + + private int defaultSessionExecutorMinPoolSize = cpus(); + + private int defaultSessionExecutorMaxPoolSize = cpus() * 5; //5*CPUs by default + + private long defaultSessionExecutorKeepAliveTime = 60; + + private int accessDataExecutorMinPoolSize = 100; + + private int accessDataExecutorMaxPoolSize = 400; + + private int accessDataExecutorQueueSize = 10000; + + private long accessDataExecutorKeepAliveTime = 60; + + private int pushTaskExecutorMinPoolSize = 40; + + private int pushTaskExecutorMaxPoolSize = 400; + + private int pushTaskExecutorQueueSize = 100000; + + private long pushTaskExecutorKeepAliveTime = 60; + + private int dataChangeExecutorMinPoolSize = 40; + + private int dataChangeExecutorMaxPoolSize = 400; + + private int dataChangeExecutorQueueSize = 100000; + + private long dataChangeExecutorKeepAliveTime = 60; + + private int disconnectClientExecutorMinPoolSize = 40; + + private int disconnectClientExecutorMaxPoolSize = 200; + + private int disconnectClientExecutorQueueSize = 10000; + + private int dataChangeFetchTaskMaxBufferSize = 1000000; + + private int dataChangeFetchTaskWorkerSize = 100; + + private int clientNodeExchangeTimeOut = 1000; //time out cause netty HashedWheelTimer occupy a lot of mem + + private int dataNodeExchangeTimeOut = 3000; + + private int metaNodeExchangeTimeOut = 3000; + + private int numberOfReplicas = 1000; + + private int userDataPushRetryWheelTicksSize = 5120; + + private int userDataPushRetryWheelTicksDuration = 100; + + private int pushDataTaskRetryFirstDelay = 500; + + private long pushDataTaskRetryIncrementDelay = 500; + + private String sessionServerRegion; + + private String sessionServerDataCenter; + + private boolean stopPushSwitch = false; + + private boolean beginDataFetchTask = false; + + //begin config for enterprise version + + /** forever close push zone,such as:RZBETA */ + private String invalidForeverZones = ""; + /** config regex,exception to the rule of forever close push zone*/ + private String invalidIgnoreDataidRegex = ""; + + private Set invalidForeverZonesSet; + + private Pattern invalidIgnoreDataIdPattern = null; + + private String pushEmptyDataDataIdPrefixes = ""; + + private Set pushEmptyDataDataIdPrefixesSet; + + //end config for enterprise version + + private CommonConfig commonConfig; + + /** + * constructor + * @param commonConfig + */ + public SessionServerConfigBean(CommonConfig commonConfig) { + this.commonConfig = commonConfig; + } + + /** + * Getter method for property serverPort. + * + * @return property value of serverPort + */ + @Override + public int getServerPort() { + return serverPort; + } + + /** + * Setter method for property serverPort. + * + * @param serverPort value to be assigned to property serverPort + */ + public void setServerPort(int serverPort) { + this.serverPort = serverPort; + } + + /** + * Getter method for property schedulerHeartbeatTimeout. + * + * @return property value of schedulerHeartbeatTimeout + */ + @Override + public int getSchedulerHeartbeatTimeout() { + return schedulerHeartbeatTimeout; + } + + /** + * Setter method for property schedulerHeartbeatTimeout. + * + * @param schedulerHeartbeatTimeout value to be assigned to property schedulerHeartbeatTimeout + */ + public void setSchedulerHeartbeatTimeout(int schedulerHeartbeatTimeout) { + this.schedulerHeartbeatTimeout = schedulerHeartbeatTimeout; + } + + /** + * Getter method for property schedulerHeartbeatFirstDelay. + * + * @return property value of schedulerHeartbeatFirstDelay + */ + @Override + public int getSchedulerHeartbeatFirstDelay() { + return schedulerHeartbeatFirstDelay; + } + + /** + * Setter method for property schedulerHeartbeatFirstDelay. + * + * @param schedulerHeartbeatFirstDelay value to be assigned to property schedulerHeartbeatFirstDelay + */ + public void setSchedulerHeartbeatFirstDelay(int schedulerHeartbeatFirstDelay) { + this.schedulerHeartbeatFirstDelay = schedulerHeartbeatFirstDelay; + } + + /** + * Getter method for property schedulerHeartbeatExpBackOffBound. + * + * @return property value of schedulerHeartbeatExpBackOffBound + */ + @Override + public int getSchedulerHeartbeatExpBackOffBound() { + return schedulerHeartbeatExpBackOffBound; + } + + /** + * Setter method for property schedulerHeartbeatExpBackOffBound. + * + * @param schedulerHeartbeatExpBackOffBound value to be assigned to property schedulerHeartbeatExpBackOffBound + */ + public void setSchedulerHeartbeatExpBackOffBound(int schedulerHeartbeatExpBackOffBound) { + this.schedulerHeartbeatExpBackOffBound = schedulerHeartbeatExpBackOffBound; + } + + /** + * Getter method for property schedulerFetchDataTimeout. + * + * @return property value of schedulerFetchDataTimeout + */ + @Override + public int getSchedulerFetchDataTimeout() { + return schedulerFetchDataTimeout; + } + + /** + * Setter method for property schedulerFetchDataTimeout. + * + * @param schedulerFetchDataTimeout value to be assigned to property schedulerFetchDataTimeout + */ + public void setSchedulerFetchDataTimeout(int schedulerFetchDataTimeout) { + this.schedulerFetchDataTimeout = schedulerFetchDataTimeout; + } + + /** + * Getter method for property schedulerFetchDataFirstDelay. + * + * @return property value of schedulerFetchDataFirstDelay + */ + @Override + public int getSchedulerFetchDataFirstDelay() { + return schedulerFetchDataFirstDelay; + } + + /** + * Setter method for property schedulerFetchDataFirstDelay. + * + * @param schedulerFetchDataFirstDelay value to be assigned to property schedulerFetchDataFirstDelay + */ + public void setSchedulerFetchDataFirstDelay(int schedulerFetchDataFirstDelay) { + this.schedulerFetchDataFirstDelay = schedulerFetchDataFirstDelay; + } + + /** + * Getter method for property schedulerFetchDataExpBackOffBound. + * + * @return property value of schedulerFetchDataExpBackOffBound + */ + @Override + public int getSchedulerFetchDataExpBackOffBound() { + return schedulerFetchDataExpBackOffBound; + } + + /** + * Setter method for property schedulerFetchDataExpBackOffBound. + * + * @param schedulerFetchDataExpBackOffBound value to be assigned to property schedulerFetchDataExpBackOffBound + */ + public void setSchedulerFetchDataExpBackOffBound(int schedulerFetchDataExpBackOffBound) { + this.schedulerFetchDataExpBackOffBound = schedulerFetchDataExpBackOffBound; + } + + /** + * Getter method for property cancelDataTaskRetryTimes. + * + * @return property value of cancelDataTaskRetryTimes + */ + @Override + public int getCancelDataTaskRetryTimes() { + return cancelDataTaskRetryTimes; + } + + /** + * Setter method for property cancelDataTaskRetryTimes. + * + * @param cancelDataTaskRetryTimes value to be assigned to property cancelDataTaskRetryTimes + */ + public void setCancelDataTaskRetryTimes(int cancelDataTaskRetryTimes) { + this.cancelDataTaskRetryTimes = cancelDataTaskRetryTimes; + } + + /** + * Getter method for property cancelDataTaskRetryFirstDelay. + * + * @return property value of cancelDataTaskRetryFirstDelay + */ + @Override + public int getCancelDataTaskRetryFirstDelay() { + return cancelDataTaskRetryFirstDelay; + } + + /** + * Setter method for property cancelDataTaskRetryFirstDelay. + * + * @param cancelDataTaskRetryFirstDelay value to be assigned to property cancelDataTaskRetryFirstDelay + */ + public void setCancelDataTaskRetryFirstDelay(int cancelDataTaskRetryFirstDelay) { + this.cancelDataTaskRetryFirstDelay = cancelDataTaskRetryFirstDelay; + } + + /** + * Getter method for property cancelDataTaskRetryIncrementDelay. + * + * @return property value of cancelDataTaskRetryIncrementDelay + */ + @Override + public long getCancelDataTaskRetryIncrementDelay() { + return cancelDataTaskRetryIncrementDelay; + } + + /** + * Setter method for property cancelDataTaskRetryIncrementDelay. + * + * @param cancelDataTaskRetryIncrementDelay value to be assigned to property cancelDataTaskRetryIncrementDelay + */ + public void setCancelDataTaskRetryIncrementDelay(long cancelDataTaskRetryIncrementDelay) { + this.cancelDataTaskRetryIncrementDelay = cancelDataTaskRetryIncrementDelay; + } + + /** + * Getter method for property receivedDataMultiPushTaskRetryTimes. + * + * @return property value of receivedDataMultiPushTaskRetryTimes + */ + @Override + public int getReceivedDataMultiPushTaskRetryTimes() { + return receivedDataMultiPushTaskRetryTimes; + } + + /** + * Setter method for property receivedDataMultiPushTaskRetryTimes. + * + * @param receivedDataMultiPushTaskRetryTimes value to be assigned to property receivedDataMultiPushTaskRetryTimes + */ + public void setReceivedDataMultiPushTaskRetryTimes(int receivedDataMultiPushTaskRetryTimes) { + this.receivedDataMultiPushTaskRetryTimes = receivedDataMultiPushTaskRetryTimes; + } + + /** + * Getter method for property dataChangeFetchTaskRetryTimes. + * + * @return property value of dataChangeFetchTaskRetryTimes + */ + @Override + public int getDataChangeFetchTaskRetryTimes() { + return dataChangeFetchTaskRetryTimes; + } + + /** + * Setter method for property dataChangeFetchTaskRetryTimes. + * + * @param dataChangeFetchTaskRetryTimes value to be assigned to property dataChangeFetchTaskRetryTimes + */ + public void setDataChangeFetchTaskRetryTimes(int dataChangeFetchTaskRetryTimes) { + this.dataChangeFetchTaskRetryTimes = dataChangeFetchTaskRetryTimes; + } + + /** + * Getter method for property subscriberRegisterFetchRetryTimes. + * + * @return property value of subscriberRegisterFetchRetryTimes + */ + @Override + public int getSubscriberRegisterFetchRetryTimes() { + return subscriberRegisterFetchRetryTimes; + } + + /** + * Setter method for property subscriberRegisterFetchRetryTimes. + * + * @param subscriberRegisterFetchRetryTimes value to be assigned to property subscriberRegisterFetchRetryTimes + */ + public void setSubscriberRegisterFetchRetryTimes(int subscriberRegisterFetchRetryTimes) { + this.subscriberRegisterFetchRetryTimes = subscriberRegisterFetchRetryTimes; + } + + /** + * Getter method for property sessionRegisterDataServerTaskRetryTimes. + * + * @return property value of sessionRegisterDataServerTaskRetryTimes + */ + @Override + public int getSessionRegisterDataServerTaskRetryTimes() { + return sessionRegisterDataServerTaskRetryTimes; + } + + /** + * Setter method for property sessionRegisterDataServerTaskRetryTimes. + * + * @param sessionRegisterDataServerTaskRetryTimes value to be assigned to property sessionRegisterDataServerTaskRetryTimes + */ + public void setSessionRegisterDataServerTaskRetryTimes(int sessionRegisterDataServerTaskRetryTimes) { + this.sessionRegisterDataServerTaskRetryTimes = sessionRegisterDataServerTaskRetryTimes; + } + + /** + * Getter method for property clientNodeExchangeTimeOut. + * + * @return property value of clientNodeExchangeTimeOut + */ + @Override + public int getClientNodeExchangeTimeOut() { + return clientNodeExchangeTimeOut; + } + + /** + * Setter method for property clientNodeExchangeTimeOut. + * + * @param clientNodeExchangeTimeOut value to be assigned to property clientNodeExchangeTimeOut + */ + public void setClientNodeExchangeTimeOut(int clientNodeExchangeTimeOut) { + this.clientNodeExchangeTimeOut = clientNodeExchangeTimeOut; + } + + /** + * Getter method for property dataNodeExchangeTimeOut. + * + * @return property value of dataNodeExchangeTimeOut + */ + @Override + public int getDataNodeExchangeTimeOut() { + return dataNodeExchangeTimeOut; + } + + /** + * Setter method for property dataNodeExchangeTimeOut. + * + * @param dataNodeExchangeTimeOut value to be assigned to property dataNodeExchangeTimeOut + */ + public void setDataNodeExchangeTimeOut(int dataNodeExchangeTimeOut) { + this.dataNodeExchangeTimeOut = dataNodeExchangeTimeOut; + } + + /** + * Getter method for property metaServerPort. + * + * @return property value of metaServerPort + */ + @Override + public int getMetaServerPort() { + return metaServerPort; + } + + /** + * Setter method for property metaServerPort. + * + * @param metaServerPort value to be assigned to property metaServerPort + */ + public void setMetaServerPort(int metaServerPort) { + this.metaServerPort = metaServerPort; + } + + @Override + public String getSessionServerRegion() { + if (commonConfig != null) { + String region = commonConfig.getLocalRegion(); + if (region != null && !region.isEmpty()) { + return commonConfig.getLocalRegion().toUpperCase(); + } + } + + if (sessionServerRegion != null) { + sessionServerRegion = sessionServerRegion.toUpperCase(); + } + return sessionServerRegion; + } + + /** + * Setter method for property sessionServerRegion. + * + * @param sessionServerRegion value to be assigned to property sessionServerRegion + */ + public void setSessionServerRegion(String sessionServerRegion) { + if (sessionServerRegion != null) { + sessionServerRegion = sessionServerRegion.toUpperCase(); + } + this.sessionServerRegion = sessionServerRegion; + } + + @Override + public String getSessionServerDataCenter() { + if (commonConfig != null) { + String dataCenter = commonConfig.getLocalDataCenter(); + if (dataCenter != null && !dataCenter.isEmpty()) { + return commonConfig.getLocalDataCenter(); + } + } + + return sessionServerDataCenter; + } + + /** + * Setter method for property sessionServerDataCenter. + * + * @param sessionServerDataCenter value to be assigned to property sessionServerDataCenter + */ + public void setSessionServerDataCenter(String sessionServerDataCenter) { + this.sessionServerDataCenter = sessionServerDataCenter; + } + + /** + * Getter method for property metaNodeExchangeTimeOut. + * + * @return property value of metaNodeExchangeTimeOut + */ + @Override + public int getMetaNodeExchangeTimeOut() { + return metaNodeExchangeTimeOut; + } + + /** + * Setter method for property metaNodeExchangeTimeOut. + * + * @param metaNodeExchangeTimeOut value to be assigned to property metaNodeExchangeTimeOut + */ + public void setMetaNodeExchangeTimeOut(int metaNodeExchangeTimeOut) { + this.metaNodeExchangeTimeOut = metaNodeExchangeTimeOut; + } + + /** + * Getter method for property dataServerPort. + * + * @return property value of dataServerPort + */ + @Override + public int getDataServerPort() { + return dataServerPort; + } + + /** + * Setter method for property dataServerPort. + * + * @param dataServerPort value to be assigned to property dataServerPort + */ + public void setDataServerPort(int dataServerPort) { + this.dataServerPort = dataServerPort; + } + + /** + * Getter method for property httpServerPort. + * + * @return property value of httpServerPort + */ + @Override + public int getHttpServerPort() { + return httpServerPort; + } + + /** + * Setter method for property httpServerPort. + * + * @param httpServerPort value to be assigned to property httpServerPort + */ + public void setHttpServerPort(int httpServerPort) { + this.httpServerPort = httpServerPort; + } + + /** + * Getter method for property numberOfReplicas. + * + * @return property value of numberOfReplicas + */ + @Override + public int getNumberOfReplicas() { + return numberOfReplicas; + } + + /** + * Setter method for property numberOfReplicas. + * + * @param numberOfReplicas value to be assigned to property numberOfReplicas + */ + public void setNumberOfReplicas(int numberOfReplicas) { + this.numberOfReplicas = numberOfReplicas; + } + + /** + * Getter method for property schedulerGetSessionNodeTimeout. + * + * @return property value of schedulerGetSessionNodeTimeout + */ + @Override + public int getSchedulerGetSessionNodeTimeout() { + return schedulerGetSessionNodeTimeout; + } + + /** + * Setter method for property schedulerGetSessionNodeTimeout. + * + * @param schedulerGetSessionNodeTimeout value to be assigned to property schedulerGetSessionNodeTimeout + */ + public void setSchedulerGetSessionNodeTimeout(int schedulerGetSessionNodeTimeout) { + this.schedulerGetSessionNodeTimeout = schedulerGetSessionNodeTimeout; + } + + /** + * Getter method for property schedulerGetSessionNodeFirstDelay. + * + * @return property value of schedulerGetSessionNodeFirstDelay + */ + @Override + public int getSchedulerGetSessionNodeFirstDelay() { + return schedulerGetSessionNodeFirstDelay; + } + + /** + * Setter method for property schedulerGetSessionNodeFirstDelay. + * + * @param schedulerGetSessionNodeFirstDelay value to be assigned to property schedulerGetSessionNodeFirstDelay + */ + public void setSchedulerGetSessionNodeFirstDelay(int schedulerGetSessionNodeFirstDelay) { + this.schedulerGetSessionNodeFirstDelay = schedulerGetSessionNodeFirstDelay; + } + + /** + * Getter method for property schedulerGetSessionNodeExpBackOffBound. + * + * @return property value of schedulerGetSessionNodeExpBackOffBound + */ + @Override + public int getSchedulerGetSessionNodeExpBackOffBound() { + return schedulerGetSessionNodeExpBackOffBound; + } + + /** + * Setter method for property schedulerGetSessionNodeExpBackOffBound. + * + * @param schedulerGetSessionNodeExpBackOffBound value to be assigned to property schedulerGetSessionNodeExpBackOffBound + */ + public void setSchedulerGetSessionNodeExpBackOffBound(int schedulerGetSessionNodeExpBackOffBound) { + this.schedulerGetSessionNodeExpBackOffBound = schedulerGetSessionNodeExpBackOffBound; + } + + /** + * Getter method for property schedulerConnectMetaTimeout. + * + * @return property value of schedulerConnectMetaTimeout + */ + @Override + public int getSchedulerConnectMetaTimeout() { + return schedulerConnectMetaTimeout; + } + + /** + * Getter method for property schedulerConnectMetaFirstDelay. + * + * @return property value of schedulerConnectMetaFirstDelay + */ + @Override + public int getSchedulerConnectMetaFirstDelay() { + return schedulerConnectMetaFirstDelay; + } + + /** + * Getter method for property schedulerConnectMetaExpBackOffBound. + * + * @return property value of schedulerConnectMetaExpBackOffBound + */ + @Override + public int getSchedulerConnectMetaExpBackOffBound() { + return schedulerConnectMetaExpBackOffBound; + } + + /** + * Setter method for property schedulerConnectMetaTimeout. + * + * @param schedulerConnectMetaTimeout value to be assigned to property schedulerConnectMetaTimeout + */ + public void setSchedulerConnectMetaTimeout(int schedulerConnectMetaTimeout) { + this.schedulerConnectMetaTimeout = schedulerConnectMetaTimeout; + } + + /** + * Setter method for property schedulerConnectMetaFirstDelay. + * + * @param schedulerConnectMetaFirstDelay value to be assigned to property schedulerConnectMetaFirstDelay + */ + public void setSchedulerConnectMetaFirstDelay(int schedulerConnectMetaFirstDelay) { + this.schedulerConnectMetaFirstDelay = schedulerConnectMetaFirstDelay; + } + + /** + * Setter method for property schedulerConnectMetaExpBackOffBound. + * + * @param schedulerConnectMetaExpBackOffBound value to be assigned to property schedulerConnectMetaExpBackOffBound + */ + public void setSchedulerConnectMetaExpBackOffBound(int schedulerConnectMetaExpBackOffBound) { + this.schedulerConnectMetaExpBackOffBound = schedulerConnectMetaExpBackOffBound; + } + + @Override + public int getSchedulerConnectDataTimeout() { + return schedulerConnectDataTimeout; + } + + /** + * Setter method for property schedulerConnectDataTimeout. + * + * @param schedulerConnectDataTimeout value to be assigned to property schedulerConnectDataTimeout + */ + public void setSchedulerConnectDataTimeout(int schedulerConnectDataTimeout) { + this.schedulerConnectDataTimeout = schedulerConnectDataTimeout; + } + + @Override + public int getSchedulerConnectDataFirstDelay() { + return schedulerConnectDataFirstDelay; + } + + /** + * Setter method for property schedulerConnectDataFirstDelay. + * + * @param schedulerConnectDataFirstDelay value to be assigned to property schedulerConnectDataFirstDelay + */ + public void setSchedulerConnectDataFirstDelay(int schedulerConnectDataFirstDelay) { + this.schedulerConnectDataFirstDelay = schedulerConnectDataFirstDelay; + } + + @Override + public int getSchedulerConnectDataExpBackOffBound() { + return schedulerConnectDataExpBackOffBound; + } + + /** + * Setter method for property schedulerConnectDataExpBackOffBound. + * + * @param schedulerConnectDataExpBackOffBound value to be assigned to property schedulerConnectDataExpBackOffBound + */ + public void setSchedulerConnectDataExpBackOffBound(int schedulerConnectDataExpBackOffBound) { + this.schedulerConnectDataExpBackOffBound = schedulerConnectDataExpBackOffBound; + } + + /** + * Getter method for property stopPushSwitch. + * + * @return property value of stopPushSwitch + */ + @Override + public boolean isStopPushSwitch() { + return stopPushSwitch; + } + + /** + * Setter method for property stopPushSwitch. + * + * @param stopPushSwitch value to be assigned to property stopPushSwitch + */ + @Override + public void setStopPushSwitch(boolean stopPushSwitch) { + this.stopPushSwitch = stopPushSwitch; + } + + /** + * Getter method for property beginDataFetchTask. + * + * @return property value of beginDataFetchTask + */ + @Override + public boolean isBeginDataFetchTask() { + return beginDataFetchTask; + } + + /** + * Setter method for property beginDataFetchTask. + * + * @param beginDataFetchTask value to be assigned to property beginDataFetchTask + */ + @Override + public void setBeginDataFetchTask(boolean beginDataFetchTask) { + this.beginDataFetchTask = beginDataFetchTask; + } + + public String getInvalidForeverZones() { + return invalidForeverZones; + } + + /** + * Setter method for property invalidForeverZones. + * + * @param invalidForeverZones value to be assigned to property invalidForeverZones + */ + public void setInvalidForeverZones(String invalidForeverZones) { + this.invalidForeverZones = invalidForeverZones; + } + + public String getInvalidIgnoreDataidRegex() { + return invalidIgnoreDataidRegex; + } + + /** + * Setter method for property invalidIgnoreDataidRegex. + * + * @param invalidIgnoreDataidRegex value to be assigned to property invalidIgnoreDataidRegex + */ + public void setInvalidIgnoreDataidRegex(String invalidIgnoreDataidRegex) { + this.invalidIgnoreDataidRegex = invalidIgnoreDataidRegex; + } + + @Override + public int getAccessDataExecutorMinPoolSize() { + return accessDataExecutorMinPoolSize; + } + + /** + * Setter method for property accessDataExecutorMinPoolSize. + * + * @param accessDataExecutorMinPoolSize value to be assigned to property accessDataExecutorMinPoolSize + */ + public void setAccessDataExecutorMinPoolSize(int accessDataExecutorMinPoolSize) { + this.accessDataExecutorMinPoolSize = accessDataExecutorMinPoolSize; + } + + @Override + public int getAccessDataExecutorMaxPoolSize() { + return accessDataExecutorMaxPoolSize; + } + + /** + * Setter method for property accessDataExecutorMaxPoolSize. + * + * @param accessDataExecutorMaxPoolSize value to be assigned to property accessDataExecutorMaxPoolSize + */ + public void setAccessDataExecutorMaxPoolSize(int accessDataExecutorMaxPoolSize) { + this.accessDataExecutorMaxPoolSize = accessDataExecutorMaxPoolSize; + } + + @Override + public int getAccessDataExecutorQueueSize() { + return accessDataExecutorQueueSize; + } + + /** + * Setter method for property accessDataExecutorQueueSize. + * + * @param accessDataExecutorQueueSize value to be assigned to property accessDataExecutorQueueSize + */ + public void setAccessDataExecutorQueueSize(int accessDataExecutorQueueSize) { + this.accessDataExecutorQueueSize = accessDataExecutorQueueSize; + } + + @Override + public long getAccessDataExecutorKeepAliveTime() { + return accessDataExecutorKeepAliveTime; + } + + /** + * Setter method for property accessDataExecutorKeepAliveTime. + * + * @param accessDataExecutorKeepAliveTime value to be assigned to property accessDataExecutorKeepAliveTime + */ + public void setAccessDataExecutorKeepAliveTime(long accessDataExecutorKeepAliveTime) { + this.accessDataExecutorKeepAliveTime = accessDataExecutorKeepAliveTime; + } + + public String getPushEmptyDataDataIdPrefixes() { + return pushEmptyDataDataIdPrefixes; + } + + /** + * Getter method for property dataChangeExecutorMinPoolSize. + * + * @return property value of dataChangeExecutorMinPoolSize + */ + @Override + public int getDataChangeExecutorMinPoolSize() { + return dataChangeExecutorMinPoolSize; + } + + /** + * Getter method for property dataChangeExecutorMaxPoolSize. + * + * @return property value of dataChangeExecutorMaxPoolSize + */ + @Override + public int getDataChangeExecutorMaxPoolSize() { + return dataChangeExecutorMaxPoolSize; + } + + /** + * Getter method for property dataChangeExecutorQueueSize. + * + * @return property value of dataChangeExecutorQueueSize + */ + @Override + public int getDataChangeExecutorQueueSize() { + return dataChangeExecutorQueueSize; + } + + /** + * Getter method for property dataChangeExecutorKeepAliveTime. + * + * @return property value of dataChangeExecutorKeepAliveTime + */ + @Override + public long getDataChangeExecutorKeepAliveTime() { + return dataChangeExecutorKeepAliveTime; + } + + /** + * Setter method for property dataChangeExecutorMinPoolSize. + * + * @param dataChangeExecutorMinPoolSize value to be assigned to property dataChangeExecutorMinPoolSize + */ + public void setDataChangeExecutorMinPoolSize(int dataChangeExecutorMinPoolSize) { + this.dataChangeExecutorMinPoolSize = dataChangeExecutorMinPoolSize; + } + + /** + * Setter method for property dataChangeExecutorMaxPoolSize. + * + * @param dataChangeExecutorMaxPoolSize value to be assigned to property dataChangeExecutorMaxPoolSize + */ + public void setDataChangeExecutorMaxPoolSize(int dataChangeExecutorMaxPoolSize) { + this.dataChangeExecutorMaxPoolSize = dataChangeExecutorMaxPoolSize; + } + + /** + * Setter method for property dataChangeExecutorQueueSize. + * + * @param dataChangeExecutorQueueSize value to be assigned to property dataChangeExecutorQueueSize + */ + public void setDataChangeExecutorQueueSize(int dataChangeExecutorQueueSize) { + this.dataChangeExecutorQueueSize = dataChangeExecutorQueueSize; + } + + /** + * Setter method for property dataChangeExecutorKeepAliveTime. + * + * @param dataChangeExecutorKeepAliveTime value to be assigned to property dataChangeExecutorKeepAliveTime + */ + public void setDataChangeExecutorKeepAliveTime(long dataChangeExecutorKeepAliveTime) { + this.dataChangeExecutorKeepAliveTime = dataChangeExecutorKeepAliveTime; + } + + /** + * Setter method for property pushEmptyDataDataIdPrefixes. + * + * @param pushEmptyDataDataIdPrefixes value to be assigned to property pushEmptyDataDataIdPrefixes + */ + public void setPushEmptyDataDataIdPrefixes(String pushEmptyDataDataIdPrefixes) { + this.pushEmptyDataDataIdPrefixes = pushEmptyDataDataIdPrefixes; + } + + /** + * Getter method for property pushTaskExecutorMinPoolSize. + * + * @return property value of pushTaskExecutorMinPoolSize + */ + @Override + public int getPushTaskExecutorMinPoolSize() { + return pushTaskExecutorMinPoolSize; + } + + /** + * Getter method for property pushTaskExecutorMaxPoolSize. + * + * @return property value of pushTaskExecutorMaxPoolSize + */ + @Override + public int getPushTaskExecutorMaxPoolSize() { + return pushTaskExecutorMaxPoolSize; + } + + /** + * Getter method for property pushTaskExecutorQueueSize. + * + * @return property value of pushTaskExecutorQueueSize + */ + @Override + public int getPushTaskExecutorQueueSize() { + return pushTaskExecutorQueueSize; + } + + /** + * Getter method for property pushTaskExecutorKeepAliveTime. + * + * @return property value of pushTaskExecutorKeepAliveTime + */ + @Override + public long getPushTaskExecutorKeepAliveTime() { + return pushTaskExecutorKeepAliveTime; + } + + /** + * Setter method for property pushTaskExecutorMinPoolSize. + * + * @param pushTaskExecutorMinPoolSize value to be assigned to property pushTaskExecutorMinPoolSize + */ + public void setPushTaskExecutorMinPoolSize(int pushTaskExecutorMinPoolSize) { + this.pushTaskExecutorMinPoolSize = pushTaskExecutorMinPoolSize; + } + + /** + * Setter method for property pushTaskExecutorMaxPoolSize. + * + * @param pushTaskExecutorMaxPoolSize value to be assigned to property pushTaskExecutorMaxPoolSize + */ + public void setPushTaskExecutorMaxPoolSize(int pushTaskExecutorMaxPoolSize) { + this.pushTaskExecutorMaxPoolSize = pushTaskExecutorMaxPoolSize; + } + + /** + * Setter method for property pushTaskExecutorQueueSize. + * + * @param pushTaskExecutorQueueSize value to be assigned to property pushTaskExecutorQueueSize + */ + public void setPushTaskExecutorQueueSize(int pushTaskExecutorQueueSize) { + this.pushTaskExecutorQueueSize = pushTaskExecutorQueueSize; + } + + /** + * Setter method for property pushTaskExecutorKeepAliveTime. + * + * @param pushTaskExecutorKeepAliveTime value to be assigned to property pushTaskExecutorKeepAliveTime + */ + public void setPushTaskExecutorKeepAliveTime(long pushTaskExecutorKeepAliveTime) { + this.pushTaskExecutorKeepAliveTime = pushTaskExecutorKeepAliveTime; + } + + public Set getPushEmptyDataDataIdPrefixesSet() { + if (pushEmptyDataDataIdPrefixesSet == null || pushEmptyDataDataIdPrefixesSet.isEmpty()) { + Set s = new HashSet<>(); + String[] arr = pushEmptyDataDataIdPrefixes.split(";"); + for (String str : arr) { + if (str.trim().length() > 0) { + s.add(str); + } + } + pushEmptyDataDataIdPrefixesSet = Collections.unmodifiableSet(s); + } + return pushEmptyDataDataIdPrefixesSet; + } + + /** + * Setter method for property pushEmptyDataDataIdPrefixesSet. + * + * @param pushEmptyDataDataIdPrefixesSet value to be assigned to property pushEmptyDataDataIdPrefixesSet + */ + public void setPushEmptyDataDataIdPrefixesSet(Set pushEmptyDataDataIdPrefixesSet) { + this.pushEmptyDataDataIdPrefixesSet = pushEmptyDataDataIdPrefixesSet; + } + + /** + * Getter method for property defaultSessionExecutorMinPoolSize. + * + * @return property value of defaultSessionExecutorMinPoolSize + */ + public int getDefaultSessionExecutorMinPoolSize() { + return defaultSessionExecutorMinPoolSize; + } + + /** + * Getter method for property defaultSessionExecutorMaxPoolSize. + * + * @return property value of defaultSessionExecutorMaxPoolSize + */ + public int getDefaultSessionExecutorMaxPoolSize() { + return defaultSessionExecutorMaxPoolSize; + } + + /** + * Getter method for property defaultSessionExecutorKeepAliveTime. + * + * @return property value of defaultSessionExecutorKeepAliveTime + */ + public long getDefaultSessionExecutorKeepAliveTime() { + return defaultSessionExecutorKeepAliveTime; + } + + /** + * Setter method for property defaultSessionExecutorMinPoolSize. + * + * @param defaultSessionExecutorMinPoolSize value to be assigned to property defaultSessionExecutorMinPoolSize + */ + public void setDefaultSessionExecutorMinPoolSize(int defaultSessionExecutorMinPoolSize) { + this.defaultSessionExecutorMinPoolSize = defaultSessionExecutorMinPoolSize; + } + + /** + * Setter method for property defaultSessionExecutorMaxPoolSize. + * + * @param defaultSessionExecutorMaxPoolSize value to be assigned to property defaultSessionExecutorMaxPoolSize + */ + public void setDefaultSessionExecutorMaxPoolSize(int defaultSessionExecutorMaxPoolSize) { + this.defaultSessionExecutorMaxPoolSize = defaultSessionExecutorMaxPoolSize; + } + + /** + * Setter method for property defaultSessionExecutorKeepAliveTime. + * + * @param defaultSessionExecutorKeepAliveTime value to be assigned to property defaultSessionExecutorKeepAliveTime + */ + public void setDefaultSessionExecutorKeepAliveTime(long defaultSessionExecutorKeepAliveTime) { + this.defaultSessionExecutorKeepAliveTime = defaultSessionExecutorKeepAliveTime; + } + + /** + * Getter method for property disconnectClientExecutorMinPoolSize. + * + * @return property value of disconnectClientExecutorMinPoolSize + */ + @Override + public int getDisconnectClientExecutorMinPoolSize() { + return disconnectClientExecutorMinPoolSize; + } + + /** + * Setter method for property disconnectClientExecutorMinPoolSize. + * + * @param disconnectClientExecutorMinPoolSize value to be assigned to property disconnectClientExecutorMinPoolSize + */ + public void setDisconnectClientExecutorMinPoolSize(int disconnectClientExecutorMinPoolSize) { + this.disconnectClientExecutorMinPoolSize = disconnectClientExecutorMinPoolSize; + } + + /** + * Getter method for property disconnectClientExecutorMaxPoolSize. + * + * @return property value of disconnectClientExecutorMaxPoolSize + */ + @Override + public int getDisconnectClientExecutorMaxPoolSize() { + return disconnectClientExecutorMaxPoolSize; + } + + /** + * Setter method for property disconnectClientExecutorMaxPoolSize. + * + * @param disconnectClientExecutorMaxPoolSize value to be assigned to property disconnectClientExecutorMaxPoolSize + */ + public void setDisconnectClientExecutorMaxPoolSize(int disconnectClientExecutorMaxPoolSize) { + this.disconnectClientExecutorMaxPoolSize = disconnectClientExecutorMaxPoolSize; + } + + /** + * Getter method for property disconnectClientExecutorQueueSize. + * + * @return property value of disconnectClientExecutorQueueSize + */ + @Override + public int getDisconnectClientExecutorQueueSize() { + return disconnectClientExecutorQueueSize; + } + + /** + * Setter method for property disconnectClientExecutorQueueSize. + * + * @param disconnectClientExecutorQueueSize value to be assigned to property disconnectClientExecutorQueueSize + */ + public void setDisconnectClientExecutorQueueSize(int disconnectClientExecutorQueueSize) { + this.disconnectClientExecutorQueueSize = disconnectClientExecutorQueueSize; + } + + /** + * Getter method for property dataChangeFetchTaskMaxBufferSize. + * + * @return property value of dataChangeFetchTaskMaxBufferSize + */ + @Override + public int getDataChangeFetchTaskMaxBufferSize() { + return dataChangeFetchTaskMaxBufferSize; + } + + /** + * Setter method for property dataChangeFetchTaskMaxBufferSize. + * + * @param dataChangeFetchTaskMaxBufferSize value to be assigned to property dataChangeFetchTaskMaxBufferSize + */ + public void setDataChangeFetchTaskMaxBufferSize(int dataChangeFetchTaskMaxBufferSize) { + this.dataChangeFetchTaskMaxBufferSize = dataChangeFetchTaskMaxBufferSize; + } + + /** + * Getter method for property dataChangeFetchTaskWorkerSize. + * + * @return property value of dataChangeFetchTaskWorkerSize + */ + @Override + public int getDataChangeFetchTaskWorkerSize() { + return dataChangeFetchTaskWorkerSize; + } + + /** + * Setter method for property dataChangeFetchTaskWorkerSize. + * + * @param dataChangeFetchTaskWorkerSize value to be assigned to property dataChangeFetchTaskWorkerSize + */ + public void setDataChangeFetchTaskWorkerSize(int dataChangeFetchTaskWorkerSize) { + this.dataChangeFetchTaskWorkerSize = dataChangeFetchTaskWorkerSize; + } + + /** + * Getter method for property userDataPushRetryWheelTicksSize. + * + * @return property value of userDataPushRetryWheelTicksSize + */ + @Override + public int getUserDataPushRetryWheelTicksSize() { + return userDataPushRetryWheelTicksSize; + } + + /** + * Setter method for property userDataPushRetryWheelTicksSize. + * + * @param userDataPushRetryWheelTicksSize value to be assigned to property userDataPushRetryWheelTicksSize + */ + public void setUserDataPushRetryWheelTicksSize(int userDataPushRetryWheelTicksSize) { + this.userDataPushRetryWheelTicksSize = userDataPushRetryWheelTicksSize; + } + + /** + * Getter method for property userDataPushRetryWheelTicksDuration. + * + * @return property value of userDataPushRetryWheelTicksDuration + */ + @Override + public int getUserDataPushRetryWheelTicksDuration() { + return userDataPushRetryWheelTicksDuration; + } + + /** + * Setter method for property userDataPushRetryWheelTicksDuration. + * + * @param userDataPushRetryWheelTicksDuration value to be assigned to property userDataPushRetryWheelTicksDuration + */ + public void setUserDataPushRetryWheelTicksDuration(int userDataPushRetryWheelTicksDuration) { + this.userDataPushRetryWheelTicksDuration = userDataPushRetryWheelTicksDuration; + } + + /** + * Getter method for property pushDataTaskRetryFirstDelay. + * + * @return property value of pushDataTaskRetryFirstDelay + */ + @Override + public int getPushDataTaskRetryFirstDelay() { + return pushDataTaskRetryFirstDelay; + } + + /** + * Setter method for property pushDataTaskRetryFirstDelay. + * + * @param pushDataTaskRetryFirstDelay value to be assigned to property pushDataTaskRetryFirstDelay + */ + public void setPushDataTaskRetryFirstDelay(int pushDataTaskRetryFirstDelay) { + this.pushDataTaskRetryFirstDelay = pushDataTaskRetryFirstDelay; + } + + /** + * Getter method for property pushDataTaskRetryIncrementDelay. + * + * @return property value of pushDataTaskRetryIncrementDelay + */ + @Override + public long getPushDataTaskRetryIncrementDelay() { + return pushDataTaskRetryIncrementDelay; + } + + /** + * Setter method for property pushDataTaskRetryIncrementDelay. + * + * @param pushDataTaskRetryIncrementDelay value to be assigned to property pushDataTaskRetryIncrementDelay + */ + public void setPushDataTaskRetryIncrementDelay(long pushDataTaskRetryIncrementDelay) { + this.pushDataTaskRetryIncrementDelay = pushDataTaskRetryIncrementDelay; + } + + @Override + public boolean isInvalidForeverZone(String zoneId) { + + String[] zoneNameArr = getInvalidForeverZones().split(";"); + if (invalidForeverZonesSet == null) { + invalidForeverZonesSet = new HashSet<>(); + for (String str : zoneNameArr) { + if (str.trim().length() > 0) { + invalidForeverZonesSet.add(str); + } + } + } + + return invalidForeverZonesSet.contains(zoneId); + } + + @Override + public boolean isInvalidIgnored(String dataId) { + + String invalidIgnoreDataidRegex = getInvalidIgnoreDataidRegex(); + if (null != invalidIgnoreDataidRegex && !invalidIgnoreDataidRegex.isEmpty()) { + invalidIgnoreDataIdPattern = Pattern.compile(invalidIgnoreDataidRegex); + } + + return null != invalidIgnoreDataIdPattern + && invalidIgnoreDataIdPattern.matcher(dataId).find(); + } + + public static int cpus() { + return Runtime.getRuntime().availableProcessors(); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfiguration.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfiguration.java new file mode 100644 index 000000000..63dff75e1 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerConfiguration.java @@ -0,0 +1,605 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.bootstrap; + +import com.alipay.sofa.registry.remoting.bolt.exchange.BoltExchange; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.jersey.exchange.JerseyExchange; +import com.alipay.sofa.registry.server.session.cache.CacheGenerator; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.DatumCacheGenerator; +import com.alipay.sofa.registry.server.session.cache.SessionCacheService; +import com.alipay.sofa.registry.server.session.listener.CancelDataTaskListener; +import com.alipay.sofa.registry.server.session.listener.DataChangeFetchCloudTaskListener; +import com.alipay.sofa.registry.server.session.listener.DataChangeFetchTaskListener; +import com.alipay.sofa.registry.server.session.listener.DataPushTaskListener; +import com.alipay.sofa.registry.server.session.listener.ProvideDataChangeFetchTaskListener; +import com.alipay.sofa.registry.server.session.listener.ReceivedConfigDataPushTaskListener; +import com.alipay.sofa.registry.server.session.listener.ReceivedDataMultiPushTaskListener; +import com.alipay.sofa.registry.server.session.listener.SessionRegisterDataTaskListener; +import com.alipay.sofa.registry.server.session.listener.SubscriberMultiFetchTaskListener; +import com.alipay.sofa.registry.server.session.listener.SubscriberRegisterFetchTaskListener; +import com.alipay.sofa.registry.server.session.listener.WatcherRegisterFetchTaskListener; +import com.alipay.sofa.registry.server.session.node.DataNodeManager; +import com.alipay.sofa.registry.server.session.node.MetaNodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManagerFactory; +import com.alipay.sofa.registry.server.session.node.RaftClientManager; +import com.alipay.sofa.registry.server.session.node.SessionNodeManager; +import com.alipay.sofa.registry.server.session.node.processor.ClientNodeSingleTaskProcessor; +import com.alipay.sofa.registry.server.session.node.processor.ConsoleSyncSingleTaskProcessor; +import com.alipay.sofa.registry.server.session.node.processor.DataNodeSingleTaskProcessor; +import com.alipay.sofa.registry.server.session.node.processor.MetaNodeSingleTaskProcessor; +import com.alipay.sofa.registry.server.session.node.service.ClientNodeService; +import com.alipay.sofa.registry.server.session.node.service.ClientNodeServiceImpl; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.node.service.DataNodeServiceImpl; +import com.alipay.sofa.registry.server.session.node.service.MetaNodeService; +import com.alipay.sofa.registry.server.session.node.service.MetaNodeServiceImpl; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.registry.SessionRegistry; +import com.alipay.sofa.registry.server.session.remoting.ClientNodeExchanger; +import com.alipay.sofa.registry.server.session.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.session.remoting.MetaNodeExchanger; +import com.alipay.sofa.registry.server.session.remoting.handler.AbstractClientHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.CancelAddressRequestHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.ClientNodeConnectionHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.DataChangeRequestHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.DataNodeConnectionHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.DataPushRequestHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.MetaNodeConnectionHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.NodeChangeResultHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.NotifyProvideDataChangeHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.PublisherHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.SubscriberHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.SyncConfigHandler; +import com.alipay.sofa.registry.server.session.remoting.handler.WatcherHandler; +import com.alipay.sofa.registry.server.session.resource.ClientsOpenResource; +import com.alipay.sofa.registry.server.session.resource.HealthResource; +import com.alipay.sofa.registry.server.session.resource.SessionDigestResource; +import com.alipay.sofa.registry.server.session.resource.SessionOpenResource; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.scheduler.timertask.SyncClientsHeartbeatTask; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.SessionDataStore; +import com.alipay.sofa.registry.server.session.store.SessionInterests; +import com.alipay.sofa.registry.server.session.store.SessionWatchers; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.server.session.strategy.DataChangeRequestHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.PublisherHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.ReceivedConfigDataPushTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.ReceivedDataMultiPushTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.SessionRegistryStrategy; +import com.alipay.sofa.registry.server.session.strategy.SubscriberHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.SubscriberMultiFetchTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.SubscriberRegisterFetchTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.SyncConfigHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.TaskMergeProcessorStrategy; +import com.alipay.sofa.registry.server.session.strategy.WatcherHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultDataChangeRequestHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultPublisherHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultPushTaskMergeProcessor; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultReceivedConfigDataPushTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultReceivedDataMultiPushTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultSessionRegistryStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultSubscriberHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultSubscriberMultiFetchTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultSubscriberRegisterFetchTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultSyncConfigHandlerStrategy; +import com.alipay.sofa.registry.server.session.strategy.impl.DefaultWatcherHandlerStrategy; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.DefaultTaskListenerManager; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import com.alipay.sofa.registry.util.PropertySplitter; +import org.glassfish.jersey.jackson.JacksonFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: SessionServerConfiguration.java, v 0.1 2017-11-14 11:39 synex Exp $ + */ +@Configuration +@Import(SessionServerInitializer.class) +@EnableConfigurationProperties +public class SessionServerConfiguration { + + @Bean + @ConditionalOnMissingBean + public SessionServerBootstrap sessionServerBootstrap() { + return new SessionServerBootstrap(); + } + + @Configuration + public static class SessionServerConfigBeanConfiguration { + @Bean + public CommonConfig commonConfig() { + return new CommonConfig(); + } + + @Bean + @ConditionalOnMissingBean(name = "sessionServerConfig") + public SessionServerConfig sessionServerConfig(CommonConfig commonConfig) { + return new SessionServerConfigBean(commonConfig); + } + + @Bean(name = "PropertySplitter") + public PropertySplitter propertySplitter() { + return new PropertySplitter(); + } + + } + + @Configuration + public static class SessionRemotingConfiguration { + + @Bean + @ConditionalOnMissingBean(name = "boltExchange") + public Exchange boltExchange() { + return new BoltExchange(); + } + + @Bean + public Exchange jerseyExchange() { + return new JerseyExchange(); + } + + @Bean + public NodeExchanger clientNodeExchanger() { + return new ClientNodeExchanger(); + } + + @Bean + public NodeExchanger dataNodeExchanger() { + return new DataNodeExchanger(); + } + + @Bean + public NodeExchanger metaNodeExchanger() { + return new MetaNodeExchanger(); + } + + @Bean(name = "serverHandlers") + public Collection serverHandlers() { + Collection list = new ArrayList<>(); + list.add(publisherHandler()); + list.add(subscriberHandler()); + list.add(watcherHandler()); + list.add(clientNodeConnectionHandler()); + list.add(cancelAddressRequestHandler()); + list.add(syncConfigHandler()); + return list; + } + + @Bean + public AbstractServerHandler publisherHandler() { + return new PublisherHandler(); + } + + @Bean + public AbstractServerHandler syncConfigHandler() { + return new SyncConfigHandler(); + } + + @Bean + public AbstractServerHandler subscriberHandler() { + return new SubscriberHandler(); + } + + @Bean + public AbstractServerHandler watcherHandler() { + return new WatcherHandler(); + } + + @Bean + public AbstractServerHandler clientNodeConnectionHandler() { + return new ClientNodeConnectionHandler(); + } + + @Bean + public AbstractServerHandler cancelAddressRequestHandler() { + return new CancelAddressRequestHandler(); + } + + @Bean(name = "dataClientHandlers") + public Collection dataClientHandlers() { + Collection list = new ArrayList<>(); + list.add(dataNodeConnectionHandler()); + list.add(dataChangeRequestHandler()); + list.add(dataPushRequestHandler()); + return list; + } + + @Bean(name = "metaClientHandlers") + public Collection metaClientHandlers() { + Collection list = new ArrayList<>(); + list.add(metaNodeConnectionHandler()); + list.add(nodeChangeResultHandler()); + list.add(notifyProvideDataChangeHandler()); + return list; + } + + @Bean + public AbstractClientHandler metaNodeConnectionHandler() { + return new MetaNodeConnectionHandler(); + } + + @Bean + public AbstractClientHandler dataNodeConnectionHandler() { + return new DataNodeConnectionHandler(); + } + + @Bean + public AbstractClientHandler dataChangeRequestHandler() { + return new DataChangeRequestHandler(); + } + + @Bean + public AbstractClientHandler dataPushRequestHandler() { + return new DataPushRequestHandler(); + } + + @Bean + public AbstractClientHandler nodeChangeResultHandler() { + return new NodeChangeResultHandler(); + } + + @Bean + public AbstractClientHandler notifyProvideDataChangeHandler() { + return new NotifyProvideDataChangeHandler(); + } + } + + @Configuration + public static class ResourceConfiguration { + + @Bean + public ResourceConfig jerseyResourceConfig() { + ResourceConfig resourceConfig = new ResourceConfig(); + resourceConfig.register(JacksonFeature.class); + return resourceConfig; + } + + @Bean + @ConditionalOnMissingBean(name = "sessionOpenResource") + public SessionOpenResource sessionOpenResource() { + return new SessionOpenResource(); + } + + @Bean + public SessionDigestResource sessionDigestResource() { + return new SessionDigestResource(); + } + + @Bean + @ConditionalOnMissingBean(name = "healthResource") + public HealthResource healthResource() { + return new HealthResource(); + } + + @Bean + public ClientsOpenResource clientsOpenResource() { + return new ClientsOpenResource(); + } + } + + @Configuration + public static class SessionRegistryConfiguration { + @Bean + @ConditionalOnMissingBean(name = "sessionRegistry") + public Registry sessionRegistry() { + return new SessionRegistry(); + } + + @Bean + @ConditionalOnMissingBean + public Interests sessionInterests() { + return new SessionInterests(); + } + + @Bean + @ConditionalOnMissingBean + public Watchers sessionWatchers() { + return new SessionWatchers(); + } + + @Bean + @ConditionalOnMissingBean + public DataStore sessionDataStore() { + return new SessionDataStore(); + } + } + + @Configuration + public static class SessionNodeConfiguration { + + @Bean + @ConditionalOnMissingBean + public DataNodeService dataNodeService() { + return new DataNodeServiceImpl(); + } + + @Bean + public MetaNodeService mataNodeService() { + return new MetaNodeServiceImpl(); + } + + @Bean + @ConditionalOnMissingBean + public ClientNodeService clientNodeService() { + return new ClientNodeServiceImpl(); + } + + @Bean + public NodeManager dataNodeManager() { + return new DataNodeManager(); + } + + @Bean + public NodeManager sessionNodeManager() { + return new SessionNodeManager(); + } + + @Bean + public NodeManager metaNodeManager() { + return new MetaNodeManager(); + } + + @Bean + public RaftClientManager raftClientManager() { + return new RaftClientManager(); + } + + @Bean + public NodeManagerFactory nodeManagerFactory() { + return new NodeManagerFactory(); + } + } + + @Configuration + public static class SessionCacheConfiguration { + + @Bean + public CacheService sessionCacheService() { + return new SessionCacheService(); + } + + @Bean(name = "com.alipay.sofa.registry.server.session.cache.DatumKey") + public CacheGenerator datumCacheGenerator() { + return new DatumCacheGenerator(); + } + } + + @Configuration + public static class SessionTaskConfiguration { + + @Bean + public TaskProcessor dataNodeSingleTaskProcessor() { + return new DataNodeSingleTaskProcessor(); + } + + @Bean + public TaskProcessor metaNodeSingleTaskProcessor() { + return new MetaNodeSingleTaskProcessor(); + } + + @Bean + public TaskProcessor clientNodeSingleTaskProcessor() { + return new ClientNodeSingleTaskProcessor(); + } + + @Bean + public TaskProcessor consoleSyncSingleTaskProcessor() { + return new ConsoleSyncSingleTaskProcessor(); + } + + @Bean + public TaskListener subscriberRegisterFetchTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new SubscriberRegisterFetchTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener subscriberMultiFetchTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new SubscriberMultiFetchTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener watcherRegisterFetchTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new WatcherRegisterFetchTaskListener( + metaNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener provideDataChangeFetchTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new ProvideDataChangeFetchTaskListener( + metaNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener dataChangeFetchTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new DataChangeFetchTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener dataPushTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new DataPushTaskListener(dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener dataChangeFetchCloudTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new DataChangeFetchCloudTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener sessionRegisterDataTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new SessionRegisterDataTaskListener( + dataNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener receivedDataMultiPushTaskListener(TaskListenerManager taskListenerManager, + TaskMergeProcessorStrategy receiveDataTaskMergeProcessorStrategy, + SessionServerConfig sessionServerConfig) { + TaskListener taskListener = new ReceivedDataMultiPushTaskListener( + clientNodeSingleTaskProcessor(), receiveDataTaskMergeProcessorStrategy, + sessionServerConfig); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener receivedConfigDataPushTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new ReceivedConfigDataPushTaskListener( + clientNodeSingleTaskProcessor()); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListener cancelDataTaskListener(TaskListenerManager taskListenerManager) { + TaskListener taskListener = new CancelDataTaskListener(); + taskListenerManager.addTaskListener(taskListener); + return taskListener; + } + + @Bean + public TaskListenerManager taskListenerManager() { + return new DefaultTaskListenerManager(); + } + + } + + @Configuration + public static class ExecutorConfiguration { + + @Bean + public ExecutorManager executorManager(SessionServerConfig sessionServerConfig) { + return new ExecutorManager(sessionServerConfig); + } + + } + + @Configuration + public static class SessionTimerTaskConfiguration { + + @Bean + public SyncClientsHeartbeatTask syncClientsHeartbeatTask() { + return new SyncClientsHeartbeatTask(); + } + } + + @Configuration + public static class SessionStrategyConfiguration { + @Bean + @ConditionalOnMissingBean + public SessionRegistryStrategy sessionRegistryStrategy() { + return new DefaultSessionRegistryStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public DataChangeRequestHandlerStrategy dataChangeRequestHandlerStrategy() { + return new DefaultDataChangeRequestHandlerStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public SyncConfigHandlerStrategy syncConfigHandlerStrategy() { + return new DefaultSyncConfigHandlerStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public SubscriberRegisterFetchTaskStrategy subscriberRegisterFetchTaskStrategy() { + return new DefaultSubscriberRegisterFetchTaskStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public SubscriberMultiFetchTaskStrategy subscriberMultiFetchTaskStrategy() { + return new DefaultSubscriberMultiFetchTaskStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public PublisherHandlerStrategy publisherHandlerStrategy() { + return new DefaultPublisherHandlerStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public SubscriberHandlerStrategy subscriberHandlerStrategy() { + return new DefaultSubscriberHandlerStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public WatcherHandlerStrategy watcherHandlerStrategy() { + return new DefaultWatcherHandlerStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public TaskMergeProcessorStrategy receiveDataTaskMergeProcessorStrategy() { + return new DefaultPushTaskMergeProcessor(); + } + + @Bean + @ConditionalOnMissingBean + public ReceivedDataMultiPushTaskStrategy receivedDataMultiPushTaskStrategy() { + return new DefaultReceivedDataMultiPushTaskStrategy(); + } + + @Bean + @ConditionalOnMissingBean + public ReceivedConfigDataPushTaskStrategy receivedConfigDataPushTaskStrategy() { + return new DefaultReceivedConfigDataPushTaskStrategy(); + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerInitializer.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerInitializer.java new file mode 100644 index 000000000..163a152da --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/bootstrap/SessionServerInitializer.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.bootstrap; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.SmartLifecycle; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * SmartLifecycle for SessionServerBootstrap + * @author shangyu.wh + * @version $Id: SessionServerInitializerConfiguration.java, v 0.1 2017-11-14 11:41 synex Exp $ + */ +public class SessionServerInitializer implements SmartLifecycle { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionServerInitializer.class); + + @Autowired + private SessionServerBootstrap sessionServerBootstrap; + + private AtomicBoolean running = new AtomicBoolean(false); + + @Override + public boolean isAutoStartup() { + return true; + } + + @Override + public void start() { + try { + sessionServerBootstrap.doInitialized(); + LOGGER.info("Started SessionServer"); + + SessionServerInitializer.this.running.set(true); + } catch (Exception ex) { + SessionServerInitializer.this.running.set(false); + LOGGER.error("Could not initialize Session server!", ex); + } + } + + @Override + public void stop() { + this.running.set(false); + sessionServerBootstrap.destroy(); + } + + @Override + public boolean isRunning() { + return this.running.get(); + } + + @Override + public int getPhase() { + return 0; + } + + @Override + public void stop(Runnable callback) { + callback.run(); + this.running.set(false); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheGenerator.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheGenerator.java new file mode 100644 index 000000000..0d8cb9d9c --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheGenerator.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +/** + * + * @author shangyu.wh + * @version $Id: CacheGenerator.java, v 0.1 2017-12-06 17:29 shangyu.wh Exp $ + */ +public interface CacheGenerator { + + /** + * generator cache on write request + * + * @param key + * @return + */ + Value generatePayload(Key key); + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheService.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheService.java new file mode 100644 index 000000000..6b95977ab --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/CacheService.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: CacheService.java, v 0.1 2017-12-06 20:19 shangyu.wh Exp $ + */ +public interface CacheService { + + /** + * get cache by key + * @param key + * @return + */ + Value getValue(Key key); + + Map getValues(final Iterable keys); + + /** + * invalidate cache by keys + * @param keys + */ + void invalidate(Key... keys); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumCacheGenerator.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumCacheGenerator.java new file mode 100644 index 000000000..4af01f8ff --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumCacheGenerator.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DatumCacheGenerator.java, v 0.1 2018-11-19 16:15 shangyu.wh Exp $ + */ +public class DatumCacheGenerator implements CacheGenerator { + + private static final Logger LOGGER = LoggerFactory.getLogger(DatumCacheGenerator.class); + + /** + * DataNode service + */ + @Autowired + private DataNodeService dataNodeService; + + @Override + public Value generatePayload(Key key) { + + EntityType entityType = key.getEntityType(); + if (entityType instanceof DatumKey) { + DatumKey datumKey = (DatumKey) entityType; + + String dataCenter = datumKey.getDataCenter(); + String dataInfoId = datumKey.getDataInfoId(); + + if (isNotBlank(dataCenter) && isNotBlank(dataInfoId)) { + return new Value(dataNodeService.fetchDataCenter(dataInfoId, dataCenter)); + } else { + LOGGER.warn("Input key " + key + " invalid!"); + } + } else { + LOGGER.warn("Input key " + key + " invalid!"); + } + + return null; + } + + public boolean isNotBlank(String ss) { + return ss != null && !ss.isEmpty(); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumKey.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumKey.java new file mode 100644 index 000000000..40aae56c8 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/DatumKey.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +import com.alipay.sofa.registry.common.model.store.WordCache; + +/** + * + * @author shangyu.wh + * @version $Id: DatumKey.java, v 0.1 2018-11-19 16:08 shangyu.wh Exp $ + */ +public class DatumKey implements EntityType { + + private final String dataInfoId; + + private final String dataCenter; + + public DatumKey(String dataInfoId, String dataCenter) { + this.dataInfoId = WordCache.getInstance().getWordCache(dataInfoId); + this.dataCenter = WordCache.getInstance().getWordCache(dataCenter); + } + + @Override + public String getUniqueKey() { + StringBuilder sb = new StringBuilder(dataCenter); + sb.append(COMMA).append(dataInfoId); + return sb.toString(); + } + + @Override + public int hashCode() { + String hashKey = getUniqueKey(); + return hashKey.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof DatumKey) { + return getUniqueKey().equals(((DatumKey) other).getUniqueKey()); + } else { + return false; + } + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Getter method for property dataCenter. + * + * @return property value of dataCenter + */ + public String getDataCenter() { + return dataCenter; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DatumKey{"); + sb.append("dataInfoId='").append(dataInfoId).append('\''); + sb.append(", dataCenter='").append(dataCenter).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/EntityType.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/EntityType.java new file mode 100644 index 000000000..72912579e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/EntityType.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +/** + * + * @author shangyu.wh + * @version $Id: EntityType.java, v 0.1 2017-12-06 15:52 shangyu.wh Exp $ + */ +public interface EntityType { + + /** symbol : */ + char COMMA = ','; + + /** + * cache contents uniqueKey,use for make up Key' hash code + * @return + */ + String getUniqueKey(); + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Key.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Key.java new file mode 100644 index 000000000..c31f773e8 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Key.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +/** + * cache query condition key + * + * @author shangyu.wh + * @version $Id: Key.java, v 0.1 2017-12-06 15:52 shangyu.wh Exp $ + */ +public class Key { + + private String entityName; + private String hashKey; + private KeyType keyType; + private EntityType entityType; + + /** + * construct func + */ + public Key(KeyType keyType, String entityName, EntityType entityType) { + this.keyType = keyType; + this.entityName = entityName; + this.entityType = entityType; + this.hashKey = this.keyType + this.entityName + this.entityType.getUniqueKey(); + } + + /** + * Getter method for property entityName. + * + * @return property value of entityName + */ + public String getEntityName() { + return entityName; + } + + /** + * Getter method for property hashKey. + * + * @return property value of hashKey + */ + public String getHashKey() { + return hashKey; + } + + /** + * Getter method for property keyType. + * + * @return property value of keyType + */ + public KeyType getKeyType() { + return keyType; + } + + /** + * Getter method for property entityType. + * + * @return property value of entityType + */ + public EntityType getEntityType() { + return entityType; + } + + @Override + public int hashCode() { + String hashKey = getHashKey(); + return hashKey.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof Key) { + return getHashKey().equals(((Key) other).getHashKey()); + } else { + return false; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{name=").append(entityName).append(", type=").append(entityType) + .append(", format=").append(keyType); + sb.append('}'); + return sb.toString(); + } + + /** + * cache data type + */ + public enum KeyType { + JSON, XML, OBJ + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SessionCacheService.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SessionCacheService.java new file mode 100644 index 000000000..ba5c1aab3 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SessionCacheService.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: CacheService.java, v 0.1 2017-12-06 18:22 shangyu.wh Exp $ + */ +public class SessionCacheService implements CacheService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionCacheService.class); + + private final LoadingCache readWriteCacheMap; + /** + * injectQ + */ + private Map cacheGenerators; + + /** + * constructor + */ + public SessionCacheService() { + this.readWriteCacheMap = CacheBuilder.newBuilder().maximumSize(1000L) + .expireAfterWrite(31000, TimeUnit.MILLISECONDS).build(new CacheLoader() { + @Override + public Value load(Key key) { + return generatePayload(key); + } + }); + } + + private Value generatePayload(Key key) { + if (key == null || key.getEntityType() == null) { + throw new IllegalArgumentException("Generator key input error!"); + } + + Value value = null; + switch (key.getKeyType()) { + case OBJ: + EntityType entityType = key.getEntityType(); + CacheGenerator cacheGenerator = cacheGenerators + .get(entityType.getClass().getName()); + value = cacheGenerator.generatePayload(key); + break; + case JSON: + break; + case XML: + break; + default: + LOGGER.error("Unidentified data type: " + key.getKeyType() + + " found in the cache key."); + value = new Value(new HashMap()); + break; + } + return value; + } + + @Override + public Value getValue(final Key key) { + Value payload = null; + try { + payload = readWriteCacheMap.get(key); + } catch (Throwable t) { + LOGGER.error("Cannot get value for key :" + key, t); + } + return payload; + } + + @Override + public Map getValues(final Iterable keys) { + Map valueMap = null; + try { + valueMap = readWriteCacheMap.getAll(keys); + } catch (ExecutionException e) { + LOGGER.error("Cannot get value for keys :" + keys, e); + } + return valueMap; + } + + @Override + public void invalidate(Key... keys) { + for (Key key : keys) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Invalidating the response cache key : {} {} {}", key.getEntityType(), + key.getEntityName(), key.getKeyType()); + } + + readWriteCacheMap.invalidate(key); + } + } + + /** + * Setter method for property cacheGenerators. + * + * @param cacheGenerators value to be assigned to property cacheGenerators + */ + @Autowired + public void setCacheGenerators(Map cacheGenerators) { + this.cacheGenerators = cacheGenerators; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SubscriberResult.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SubscriberResult.java new file mode 100644 index 000000000..cdea4d663 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/SubscriberResult.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +import com.alipay.sofa.registry.core.model.ScopeEnum; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberResult.java, v 0.1 2017-12-06 17:16 shangyu.wh Exp $ + */ +public class SubscriberResult implements EntityType { + + private final String dataInfoId; + + private final ScopeEnum scope; + + public SubscriberResult(String dataInfoId, ScopeEnum scope) { + this.dataInfoId = dataInfoId; + this.scope = scope; + } + + @Override + public String getUniqueKey() { + StringBuilder sb = new StringBuilder(dataInfoId); + sb.append(COMMA).append(scope); + return sb.toString(); + } + + @Override + public int hashCode() { + String hashKey = getUniqueKey(); + return hashKey.hashCode(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof SubscriberResult) { + return getUniqueKey().equals(((SubscriberResult) other).getUniqueKey()); + } else { + return false; + } + } + + /** + * Getter method for property dataInfoId. + * + * @return property value of dataInfoId + */ + public String getDataInfoId() { + return dataInfoId; + } + + /** + * Getter method for property scope. + * + * @return property value of scope + */ + public ScopeEnum getScope() { + return scope; + } + + @Override + public String toString() { + return "SubscriberResult{" + "dataInfoId='" + dataInfoId + '\'' + ", scope=" + scope + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Value.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Value.java new file mode 100644 index 000000000..a867d24ae --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/cache/Value.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.cache; + +/** + * cache return result + * + * @author shangyu.wh + * @version $Id: Value.java, v 0.1 2017-12-06 15:52 shangyu.wh Exp $ + */ +public class Value { + + private final T payload; + + /** + * constructor + * @param payload + */ + public Value(T payload) { + this.payload = payload; + } + + /** + * Getter method for property payload. + * + * @return property value of payload + */ + public T getPayload() { + return payload; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/Converter.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/Converter.java new file mode 100644 index 000000000..698871dc6 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/Converter.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.converter; + +/** + * + * @author shangyu.wh + * @version $Id: Converter.java, v 0.1 2017-11-29 11:55 shangyu.wh Exp $ + * + * source type + * target type + */ +public interface Converter { + + T convert(S source); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/PublisherConverter.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/PublisherConverter.java new file mode 100644 index 000000000..472955b54 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/PublisherConverter.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.converter; + +import com.alipay.sofa.registry.common.model.ServerDataBox; +import com.alipay.sofa.registry.common.model.store.BaseInfo.ClientVersion; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.PublisherRegister; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: PublisherConvert.java, v 0.1 2017-11-30 17:54 shangyu.wh Exp $ + */ +public class PublisherConverter { + + /** + * PublisherRegister to Publisher + * + * @param publisherRegister + * @return + */ + public static Publisher convert(PublisherRegister publisherRegister) { + + Converter messageToData = source -> { + Publisher publisher = new Publisher(); + + publisher.setAppName(source.getAppName()); + //ZONE MUST BE CURRENT SESSION ZONE + publisher.setCell(source.getZone()); + publisher.setClientId(source.getClientId()); + publisher.setDataId(source.getDataId()); + publisher.setGroup(source.getGroup()); + publisher.setInstanceId(source.getInstanceId()); + publisher.setRegisterId(source.getRegistId()); + publisher.setProcessId(source.getProcessId()); + publisher.setVersion(source.getVersion()); + + //registerTimestamp must happen from server,client time maybe different cause pub and unPublisher fail + publisher.setRegisterTimestamp(System.currentTimeMillis()); + + publisher.setClientRegisterTimestamp(source.getTimestamp()); + publisher.setSourceAddress(new URL(source.getIp(), source.getPort())); + + publisher.setClientVersion(ClientVersion.StoreData); + + DataInfo dataInfo = new DataInfo(source.getInstanceId(), source.getDataId(), + source.getGroup()); + publisher.setDataInfoId(dataInfo.getDataInfoId()); + + publisher.setDataList(convert(source.getDataList())); + + return publisher; + }; + return messageToData.convert(publisherRegister); + } + + public static List convert(List boxList) { + List serverDataBoxes = new ArrayList<>(); + if (null != boxList) { + for (DataBox dataBox : boxList) { + ServerDataBox serverDataBox = new ServerDataBox(ServerDataBox.getBytes(dataBox + .getData())); + serverDataBoxes.add(serverDataBox); + } + } + return serverDataBoxes; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/ReceivedDataConverter.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/ReceivedDataConverter.java new file mode 100644 index 000000000..5280cc0a5 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/ReceivedDataConverter.java @@ -0,0 +1,265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.converter; + +import com.alipay.sofa.registry.common.model.ServerDataBox; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.core.model.DataBox; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Predicate; + +/** + * The type Received data converter. + * @author shangyu.wh + * @version $Id : ReceivedDataConverter.java, v 0.1 2017-12-13 13:42 shangyu.wh Exp $ + */ +public class ReceivedDataConverter { + private static final Logger LOGGER = LoggerFactory.getLogger(ReceivedDataConverter.class); + + /** + * convert for no datum from data node,just use for first get no datum + * if push empty data to subscriber must reset version,avoid client ignore this empty push + * @param dataId + * @param group + * @param instanceId + * @param dataCenter + * @param scope + * @param subscriberRegisterIdList + * @param regionLocal + * @return + */ + public static ReceivedData getReceivedDataMulti(String dataId, String group, String instanceId, + String dataCenter, ScopeEnum scope, + List subscriberRegisterIdList, + String regionLocal) { + ReceivedData receivedData = new ReceivedData(); + receivedData.setDataId(dataId); + receivedData.setGroup(group); + receivedData.setInstanceId(instanceId); + receivedData.setSubscriberRegistIds(subscriberRegisterIdList); + receivedData.setSegment(dataCenter); + receivedData.setScope(scope.name()); + //no datum set return version as mini as,avoid old client check + receivedData.setVersion(ValueConstants.DEFAULT_NO_DATUM_VERSION); + + receivedData.setLocalZone(regionLocal); + + Map> swizzMap = new HashMap<>(); + receivedData.setData(swizzMap); + return receivedData; + } + + /** + * Standard RunEnv + * @param datum the datum + * @param scope the scope + * @param subscriberRegisterIdList the subscriber register id list + * @param regionLocal the region local + * @return received data multi + */ + public static ReceivedData getReceivedDataMulti(Datum datum, ScopeEnum scope, + List subscriberRegisterIdList, + String regionLocal, + Predicate zonePredicate) { + + if (null == datum) { + return null; + } + + // todo judge server mode to decide local region + ReceivedData receivedData = new ReceivedData(); + receivedData.setDataId(datum.getDataId()); + receivedData.setGroup(datum.getGroup()); + receivedData.setInstanceId(datum.getInstanceId()); + receivedData.setSubscriberRegistIds(subscriberRegisterIdList); + receivedData.setSegment(datum.getDataCenter()); + receivedData.setScope(scope.name()); + + receivedData.setVersion(datum.getVersion()); + + receivedData.setLocalZone(regionLocal); + + Map> swizzMap = new HashMap<>(); + + Map publisherMap = datum.getPubMap(); + if (publisherMap == null || publisherMap.isEmpty()) { + receivedData.setData(swizzMap); + return receivedData; + } + for (Entry entry : publisherMap.entrySet()) { + Publisher publisher = entry.getValue(); + List datas = publisher.getDataList(); + + String region = publisher.getCell(); + + if (zonePredicate.test(region)) { + continue; + } + + if (null == datas) { + datas = new ArrayList<>(); + } + + List regionDatas = swizzMap.computeIfAbsent(region, k -> new ArrayList<>()); + fillRegionDatas(regionDatas, datas); + + } + + receivedData.setData(swizzMap); + + return receivedData; + } + + private static void fillRegionDatas(List regionDatas, List datas) { + for (ServerDataBox data : datas) { + DataBox box = new DataBox(); + try { + String dataString = (String) data.extract(); + box.setData(dataString); + regionDatas.add(box); + } catch (Exception e) { + LOGGER.error("ReceivedData convert error", e); + } + } + } + + /** + * Cloud RunEnv + * @param datums the datums + * @param scope the scope + * @param subscriberRegisterIdList the subscriber register id list + * @param subscriber decide common info + * @return received data multi + */ + public static ReceivedData getReceivedDataMulti(Map datums, ScopeEnum scope, + List subscriberRegisterIdList, + Subscriber subscriber) { + ReceivedData receivedData = new ReceivedData(); + receivedData.setDataId(subscriber.getDataId()); + receivedData.setGroup(subscriber.getGroup()); + receivedData.setInstanceId(subscriber.getInstanceId()); + receivedData.setSubscriberRegistIds(subscriberRegisterIdList); + receivedData.setSegment(ValueConstants.DEFAULT_DATA_CENTER); + receivedData.setScope(scope.name()); + + String regionLocal = subscriber.getCell(); + receivedData.setLocalZone(regionLocal); + + receivedData.setVersion(System.currentTimeMillis()); + + Map> swizzMap = new HashMap<>(); + + for (Entry entry : datums.entrySet()) { + Datum datum = entry.getValue(); + + Map publisherMap = datum.getPubMap(); + if (publisherMap == null || publisherMap.isEmpty()) { + continue; + } + + for (Entry publishers : publisherMap.entrySet()) { + Publisher publisher = publishers.getValue(); + List datas = publisher.getDataList(); + + String region = publisher.getCell(); + + if (ScopeEnum.zone == scope && !regionLocal.equals(region)) { + // zone scope subscribe only return zone list + continue; + } + + if (null == datas) { + datas = new ArrayList<>(); + } + + List regionDatas = swizzMap.computeIfAbsent(region, + k -> new ArrayList<>()); + fillRegionDatas(regionDatas, datas); + + } + } + + receivedData.setData(swizzMap); + return receivedData; + } + + /** + * Gets merge datum. + * + * @param datumMap the datum map + * @return the merge datum + */ + public static Datum getMergeDatum(Map datumMap) { + Datum merge = null; + Map mergePublisherMap = new HashMap<>(); + long version = 0; + for (Datum datum : datumMap.values()) { + if (datum.getDataId() == null) { + LOGGER.error("ReceivedData convert error,datum dataId is null,datum={}", datum); + continue; + } + if (null == merge) { + //new Datum avoid to change datumMap + merge = new Datum(datum.getDataInfoId(), datum.getDataCenter()); + merge.setDataId(datum.getDataId()); + merge.setGroup(datum.getGroup()); + merge.setInstanceId(datum.getInstanceId()); + } + mergePublisherMap.putAll(datum.getPubMap()); + version = Math.max(version, datum.getVersion()); + } + if (null == merge) { + return null; + } + merge.setVersion(version); + merge.setPubMap(mergePublisherMap); + merge.setDataCenter(ValueConstants.DEFAULT_DATA_CENTER); + return merge; + } + + public static ReceivedConfigData getReceivedConfigData(ServerDataBox dataBox, + DataInfo dataInfo, Long version) { + ReceivedConfigData receivedConfigData = new ReceivedConfigData(); + + if (dataBox != null) { + DataBox box = new DataBox(); + String dataString = (String) dataBox.getObject(); + box.setData(dataString); + receivedConfigData.setDataBox(box); + } + receivedConfigData.setDataId(dataInfo.getDataId()); + receivedConfigData.setGroup(dataInfo.getDataType()); + receivedConfigData.setInstanceId(dataInfo.getInstanceId()); + receivedConfigData.setVersion(version); + + return receivedConfigData; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/SubscriberConverter.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/SubscriberConverter.java new file mode 100644 index 000000000..5a8a4380f --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/converter/SubscriberConverter.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.converter; + +import com.alipay.sofa.registry.common.model.store.BaseInfo.ClientVersion; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.converter.ScopeEnumConverter; +import com.alipay.sofa.registry.core.model.ConfiguratorRegister; +import com.alipay.sofa.registry.core.model.SubscriberRegister; + +/** + * The type Subscriber converter. + * @author shangyu.wh + * @version $Id : SubscriberConverter.java, v 0.1 2017-12-05 11:00 shangyu.wh Exp $ + */ +public class SubscriberConverter { + + /** + * Convert subscriber. + * + * @param subscriberRegister the subscriber register + * @return the subscriber + */ + public static Subscriber convert(SubscriberRegister subscriberRegister) { + + Converter converter = source -> { + Subscriber subscriber = new Subscriber(); + + subscriber.setAppName(source.getAppName()); + subscriber.setCell(source.getZone()); + subscriber.setClientId(source.getClientId()); + subscriber.setDataId(source.getDataId()); + subscriber.setGroup(source.getGroup()); + subscriber.setInstanceId(source.getInstanceId()); + subscriber.setRegisterId(source.getRegistId()); + subscriber.setProcessId(source.getProcessId()); + subscriber.setVersion(source.getVersion()); + subscriber.setRegisterTimestamp(System.currentTimeMillis()); + subscriber.setClientRegisterTimestamp(source.getTimestamp()); + subscriber.setScope(ScopeEnumConverter.convertToScope(source.getScope())); + subscriber.setSourceAddress(new URL(source.getIp(), source.getPort())); + + subscriber.setClientVersion(ClientVersion.StoreData); + + DataInfo dataInfo = new DataInfo(source.getInstanceId(), source.getDataId(), + source.getGroup()); + + subscriber.setDataInfoId(dataInfo.getDataInfoId()); + + return subscriber; + }; + return converter.convert(subscriberRegister); + } + + /** + * Convert watcher. + * @param configuratorRegister + * @return + */ + public static Watcher convert(ConfiguratorRegister configuratorRegister) { + Converter converter = source -> { + Watcher watcher = new Watcher(); + + watcher.setAppName(source.getAppName()); + watcher.setCell(source.getZone()); + watcher.setClientId(source.getClientId()); + watcher.setDataId(source.getDataId()); + watcher.setGroup(source.getGroup()); + watcher.setInstanceId(source.getInstanceId()); + watcher.setRegisterId(source.getRegistId()); + watcher.setProcessId(source.getProcessId()); + watcher.setVersion(source.getVersion()); + watcher.setRegisterTimestamp(source.getTimestamp()); + watcher.setSourceAddress(new URL(source.getIp(), source.getPort())); + + watcher.setClientVersion(ClientVersion.StoreData); + + DataInfo dataInfo = new DataInfo(source.getInstanceId(), source.getDataId(), + source.getGroup()); + + watcher.setDataInfoId(dataInfo.getDataInfoId()); + + return watcher; + }; + return converter.convert(configuratorRegister); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/CancelDataTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/CancelDataTaskListener.java new file mode 100644 index 000000000..0bae12a2e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/CancelDataTaskListener.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.scheduler.task.CancelDataTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: CancelDataTaskListener.java, v 0.1 2017-12-27 12:02 shangyu.wh Exp $ + */ +public class CancelDataTaskListener implements TaskListener { + + /** + * store subscribers + */ + @Autowired + private Interests sessionInterests; + + /** + * store publishers + */ + @Autowired + private DataStore sessionDataStore; + + @Autowired + private Watchers sessionWatchers; + + /** + * transfer data to DataNode + */ + @Autowired + private DataNodeService dataNodeService; + + @Autowired + private SessionServerConfig sessionServerConfig; + + private TaskDispatcher singleTaskDispatcher; + + @Autowired + private TaskProcessor dataNodeSingleTaskProcessor; + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createSingleTaskDispatcher( + TaskDispatchers.getDispatcherName(TaskType.CANCEL_DATA_TASK.getName()), 10000, 80, + 1000, 100, dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.CANCEL_DATA_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + SessionTask cancelDataTask = new CancelDataTask(sessionInterests, sessionDataStore, + sessionWatchers, dataNodeService, sessionServerConfig); + + cancelDataTask.setTaskEvent(event); + getSingleTaskDispatcher().dispatch(cancelDataTask.getTaskId(), cancelDataTask, + cancelDataTask.getExpiryTime()); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchCloudTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchCloudTaskListener.java new file mode 100644 index 000000000..e558c98f5 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchCloudTaskListener.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.scheduler.task.DataChangeFetchCloudTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeFetchCloudTaskListener.java, v 0.1 2018-03-16 15:26 shangyu.wh Exp $ + */ +public class DataChangeFetchCloudTaskListener implements TaskListener { + + @Autowired + private Interests sessionInterests; + + @Autowired + private SessionServerConfig sessionServerConfig; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Autowired + private ExecutorManager executorManager; + + @Autowired + private CacheService sessionCacheService; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public DataChangeFetchCloudTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createSingleTaskDispatcher( + TaskDispatchers.getDispatcherName(TaskType.DATA_CHANGE_FETCH_CLOUD_TASK.getName()), + sessionServerConfig.getDataChangeFetchTaskMaxBufferSize(), + sessionServerConfig.getDataChangeFetchTaskWorkerSize(), 1000, 100, + dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.DATA_CHANGE_FETCH_CLOUD_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + SessionTask dataChangeFetchTask = new DataChangeFetchCloudTask(sessionServerConfig, + taskListenerManager, sessionInterests, executorManager, sessionCacheService); + dataChangeFetchTask.setTaskEvent(event); + getSingleTaskDispatcher().dispatch(dataChangeFetchTask.getTaskId(), dataChangeFetchTask, + dataChangeFetchTask.getExpiryTime()); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchTaskListener.java new file mode 100644 index 000000000..434e6a61c --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataChangeFetchTaskListener.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.scheduler.task.DataChangeFetchTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeFetchTaskListener.java, v 0.1 2017-12-13 11:58 shangyu.wh Exp $ + */ +public class DataChangeFetchTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private Interests sessionInterests; + + @Autowired + private ExecutorManager executorManager; + + @Autowired + private CacheService sessionCacheService; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public DataChangeFetchTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createSingleTaskDispatcher( + TaskDispatchers.getDispatcherName(TaskType.DATA_CHANGE_FETCH_TASK.getName()), + sessionServerConfig.getDataChangeFetchTaskMaxBufferSize(), + sessionServerConfig.getDataChangeFetchTaskWorkerSize(), 1000, 100, + dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.DATA_CHANGE_FETCH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + SessionTask dataChangeFetchTask = new DataChangeFetchTask(sessionServerConfig, + taskListenerManager, executorManager, sessionInterests, sessionCacheService); + dataChangeFetchTask.setTaskEvent(event); + getSingleTaskDispatcher().dispatch(dataChangeFetchTask.getTaskId(), dataChangeFetchTask, + dataChangeFetchTask.getExpiryTime()); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataPushTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataPushTaskListener.java new file mode 100644 index 000000000..c1afe3314 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/DataPushTaskListener.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.scheduler.task.DataPushTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeFetchTaskListener.java, v 0.1 2017-12-13 11:58 shangyu.wh Exp $ + */ +public class DataPushTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private Interests sessionInterests; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Autowired + private ExecutorManager executorManager; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public DataPushTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.DATA_PUSH_TASK.getName(), dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.DATA_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + SessionTask dataPushTask = new DataPushTask(sessionInterests, sessionServerConfig, + executorManager, taskListenerManager); + dataPushTask.setTaskEvent(event); + getSingleTaskDispatcher().dispatch(dataPushTask.getTaskId(), dataPushTask, + dataPushTask.getExpiryTime()); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ProvideDataChangeFetchTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ProvideDataChangeFetchTaskListener.java new file mode 100644 index 000000000..fe4b73208 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ProvideDataChangeFetchTaskListener.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.MetaNodeService; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.scheduler.task.ProvideDataChangeFetchTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTaskListener.java, v 0.1 2017-12-07 19:53 shangyu.wh Exp $ + */ +public class ProvideDataChangeFetchTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + /** + * trigger push client process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + /** + * MetaNode service + */ + @Autowired + private MetaNodeService metaNodeService; + + @Autowired + private Exchange boltExchange; + + @Autowired + private Interests sessionInterests; + + @Autowired + private Watchers sessionWatchers; + + @Autowired + private Registry sessionRegistry; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public ProvideDataChangeFetchTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.PROVIDE_DATA_CHANGE_FETCH_TASK.getName(), dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.PROVIDE_DATA_CHANGE_FETCH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + SessionTask provideDataChangeFetchTask = new ProvideDataChangeFetchTask( + sessionServerConfig, taskListenerManager, metaNodeService, sessionWatchers, + boltExchange, sessionInterests, sessionRegistry); + + provideDataChangeFetchTask.setTaskEvent(event); + + getSingleTaskDispatcher().dispatch(provideDataChangeFetchTask.getTaskId(), + provideDataChangeFetchTask, provideDataChangeFetchTask.getExpiryTime()); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/PushTaskSender.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/PushTaskSender.java new file mode 100644 index 000000000..29a6ebd5a --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/PushTaskSender.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +/** + * + * @author shangyu.wh + * @version $Id: PushTaskSender.java, v 0.1 2018-12-18 19:31 shangyu.wh Exp $ + */ + +import com.alipay.sofa.registry.task.listener.TaskEvent; + +/** + * + * @author shangyu.wh + * @version $Id: PushTask.java, v 0.1 2018-12-11 14:22 shangyu.wh Exp $ + */ +public interface PushTaskSender { + + enum PushDataType { + RECEIVE_DATA, USER_ELEMENT, USER_ELEMENT_MULTI + } + + void executePushAsync(TaskEvent event); + + PushDataType getPushDataType(); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedConfigDataPushTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedConfigDataPushTaskListener.java new file mode 100644 index 000000000..17cc54b5e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedConfigDataPushTaskListener.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.ClientNodeService; +import com.alipay.sofa.registry.server.session.scheduler.task.ReceivedConfigDataPushTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.strategy.ReceivedConfigDataPushTaskStrategy; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterPushTaskListener.java, v 0.1 2017-12-11 20:44 shangyu.wh Exp $ + */ +public class ReceivedConfigDataPushTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private ClientNodeService clientNodeService; + + @Autowired + private ReceivedConfigDataPushTaskStrategy receivedConfigDataPushTaskStrategy; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor clientNodeSingleTaskProcessor; + + public ReceivedConfigDataPushTaskListener(TaskProcessor clientNodeSingleTaskProcessor) { + + this.clientNodeSingleTaskProcessor = clientNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.RECEIVED_DATA_CONFIG_PUSH_TASK.getName(), clientNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.RECEIVED_DATA_CONFIG_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + SessionTask receivedConfigDataPushTask = new ReceivedConfigDataPushTask( + sessionServerConfig, clientNodeService, receivedConfigDataPushTaskStrategy); + receivedConfigDataPushTask.setTaskEvent(event); + getSingleTaskDispatcher().dispatch(receivedConfigDataPushTask.getTaskId(), + receivedConfigDataPushTask, receivedConfigDataPushTask.getExpiryTime()); + + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedDataMultiPushTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedDataMultiPushTaskListener.java new file mode 100644 index 000000000..e4c8b06b3 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/ReceivedDataMultiPushTaskListener.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.ClientNodeService; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.scheduler.task.ReceivedDataMultiPushTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.strategy.ReceivedDataMultiPushTaskStrategy; +import com.alipay.sofa.registry.server.session.strategy.TaskMergeProcessorStrategy; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer.TaskFailedCallback; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterPushTaskListener.java, v 0.1 2017-12-11 20:44 shangyu.wh Exp $ + */ +public class ReceivedDataMultiPushTaskListener implements TaskListener, PushTaskSender { + + private static final Logger LOGGER = LoggerFactory + .getLogger(ReceivedDataMultiPushTaskListener.class); + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private ClientNodeService clientNodeService; + + @Autowired + private ExecutorManager executorManager; + + @Autowired + private Exchange boltExchange; + + @Autowired + private ReceivedDataMultiPushTaskStrategy receivedDataMultiPushTaskStrategy; + + private TaskMergeProcessorStrategy receiveDataTaskMergeProcessorStrategy; + + private TaskProcessor clientNodeSingleTaskProcessor; + + private AsyncHashedWheelTimer asyncHashedWheelTimer; + + public ReceivedDataMultiPushTaskListener(TaskProcessor clientNodeSingleTaskProcessor, + TaskMergeProcessorStrategy receiveDataTaskMergeProcessorStrategy, + SessionServerConfig sessionServerConfig) { + this.clientNodeSingleTaskProcessor = clientNodeSingleTaskProcessor; + + ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder(); + threadFactoryBuilder.setDaemon(true); + asyncHashedWheelTimer = new AsyncHashedWheelTimer(threadFactoryBuilder.setNameFormat( + "Registry-ReceivedDataPushTask-WheelTimer").build(), + sessionServerConfig.getUserDataPushRetryWheelTicksDuration(), TimeUnit.MILLISECONDS, + sessionServerConfig.getUserDataPushRetryWheelTicksSize(), threadFactoryBuilder + .setNameFormat("Registry-ReceivedDataPushTask-WheelExecutor-%d").build(), + new TaskFailedCallback() { + @Override + public void executionRejected(Throwable e) { + LOGGER.error("executionRejected: " + e.getMessage(), e); + } + + @Override + public void executionFailed(Throwable e) { + LOGGER.error("executionFailed: " + e.getMessage(), e); + } + }); + + receiveDataTaskMergeProcessorStrategy.init(this); + this.receiveDataTaskMergeProcessorStrategy = receiveDataTaskMergeProcessorStrategy; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.RECEIVED_DATA_MULTI_PUSH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + receiveDataTaskMergeProcessorStrategy.handleEvent(event); + } + + @Override + public void executePushAsync(TaskEvent event) { + + SessionTask receivedDataMultiPushTask = new ReceivedDataMultiPushTask(sessionServerConfig, clientNodeService, + executorManager, boltExchange, receivedDataMultiPushTaskStrategy,asyncHashedWheelTimer); + receivedDataMultiPushTask.setTaskEvent(event); + + executorManager.getPushTaskExecutor() + .execute(() -> clientNodeSingleTaskProcessor.process(receivedDataMultiPushTask)); + } + + @Override + public PushDataType getPushDataType() { + return PushDataType.RECEIVE_DATA; + } + + /** + * Getter method for property taskMergeProcessorStrategy. + * + * @return property value of taskMergeProcessorStrategy + */ + public TaskMergeProcessorStrategy getTaskMergeProcessorStrategy() { + return receiveDataTaskMergeProcessorStrategy; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SessionRegisterDataTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SessionRegisterDataTaskListener.java new file mode 100644 index 000000000..38563b430 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SessionRegisterDataTaskListener.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionRegisterDataTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SessionRegisterDataTaskListener.java, v 0.1 2018-04-16 16:30 shangyu.wh Exp $ + */ +public class SessionRegisterDataTaskListener implements TaskListener { + + /** + * DataNode service + */ + @Autowired + private DataNodeService dataNodeService; + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionServerConfig sessionServerConfig; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public SessionRegisterDataTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createSingleTaskDispatcher( + TaskDispatchers.getDispatcherName(TaskType.SESSION_REGISTER_DATA_TASK.getName()), + 60, 5, 1000, 100, dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.SESSION_REGISTER_DATA_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + SessionTask sessionRegisterDataTask = new SessionRegisterDataTask(boltExchange, + dataNodeService, sessionServerConfig); + sessionRegisterDataTask.setTaskEvent(event); + getSingleTaskDispatcher().dispatch(sessionRegisterDataTask.getTaskId(), + sessionRegisterDataTask, sessionRegisterDataTask.getExpiryTime()); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberMultiFetchTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberMultiFetchTaskListener.java new file mode 100644 index 000000000..773e5e367 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberMultiFetchTaskListener.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SubscriberMultiFetchTask; +import com.alipay.sofa.registry.server.session.strategy.SubscriberMultiFetchTaskStrategy; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTaskListener.java, v 0.1 2017-12-07 19:53 shangyu.wh Exp $ + */ +public class SubscriberMultiFetchTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Autowired + private CacheService sessionCacheService; + + @Autowired + private SubscriberMultiFetchTaskStrategy subscriberMultiFetchTaskStrategy; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public SubscriberMultiFetchTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createSingleTaskDispatcher( + TaskDispatchers.getDispatcherName(TaskType.SUBSCRIBER_MULTI_FETCH_TASK.getName()), + 100000, 80, 0, 0, dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.SUBSCRIBER_MULTI_FETCH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + SessionTask subscriberMultiFetchTask = new SubscriberMultiFetchTask(sessionServerConfig, + taskListenerManager, sessionCacheService, subscriberMultiFetchTaskStrategy); + + subscriberMultiFetchTask.setTaskEvent(event); + + getSingleTaskDispatcher().dispatch(subscriberMultiFetchTask.getTaskId(), + subscriberMultiFetchTask, subscriberMultiFetchTask.getExpiryTime()); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberRegisterFetchTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberRegisterFetchTaskListener.java new file mode 100644 index 000000000..68b66cf63 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/SubscriberRegisterFetchTaskListener.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.scheduler.task.SubscriberRegisterFetchTask; +import com.alipay.sofa.registry.server.session.strategy.SubscriberRegisterFetchTaskStrategy; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTaskListener.java, v 0.1 2017-12-07 19:53 shangyu.wh Exp $ + */ +public class SubscriberRegisterFetchTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + /** + * DataNode service + */ + @Autowired + private DataNodeService dataNodeService; + + @Autowired + private CacheService sessionCacheService; + + @Autowired + private SubscriberRegisterFetchTaskStrategy subscriberRegisterFetchTaskStrategy; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public SubscriberRegisterFetchTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createSingleTaskDispatcher(TaskDispatchers + .getDispatcherName(TaskType.SUBSCRIBER_REGISTER_FETCH_TASK.getName()), 200000, 80, + 1000, 100, dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.SUBSCRIBER_REGISTER_FETCH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + SessionTask subscriberRegisterFetchTask = new SubscriberRegisterFetchTask( + sessionServerConfig, taskListenerManager, dataNodeService, sessionCacheService, + subscriberRegisterFetchTaskStrategy); + + subscriberRegisterFetchTask.setTaskEvent(event); + + getSingleTaskDispatcher().dispatch(subscriberRegisterFetchTask.getTaskId(), + subscriberRegisterFetchTask, subscriberRegisterFetchTask.getExpiryTime()); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/WatcherRegisterFetchTaskListener.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/WatcherRegisterFetchTaskListener.java new file mode 100644 index 000000000..68e4cd6f9 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/listener/WatcherRegisterFetchTaskListener.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.listener; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.MetaNodeService; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.server.session.scheduler.task.WatcherRegisterFetchTask; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTaskListener.java, v 0.1 2017-12-07 19:53 shangyu.wh Exp $ + */ +public class WatcherRegisterFetchTaskListener implements TaskListener { + + @Autowired + private SessionServerConfig sessionServerConfig; + + /** + * trigger push client process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + /** + * MetaNode service + */ + @Autowired + private MetaNodeService metaNodeService; + + private TaskDispatcher singleTaskDispatcher; + + private TaskProcessor dataNodeSingleTaskProcessor; + + public WatcherRegisterFetchTaskListener(TaskProcessor dataNodeSingleTaskProcessor) { + this.dataNodeSingleTaskProcessor = dataNodeSingleTaskProcessor; + } + + public TaskDispatcher getSingleTaskDispatcher() { + if (singleTaskDispatcher == null) { + singleTaskDispatcher = TaskDispatchers.createDefaultSingleTaskDispatcher( + TaskType.WATCHER_REGISTER_FETCH_TASK.getName(), dataNodeSingleTaskProcessor); + } + return singleTaskDispatcher; + } + + @Override + public boolean support(TaskEvent event) { + return TaskType.WATCHER_REGISTER_FETCH_TASK.equals(event.getTaskType()); + } + + @Override + public void handleEvent(TaskEvent event) { + + SessionTask watcherRegisterFetchTask = new WatcherRegisterFetchTask(sessionServerConfig, + taskListenerManager, metaNodeService); + + watcherRegisterFetchTask.setTaskEvent(event); + + getSingleTaskDispatcher().dispatch(watcherRegisterFetchTask.getTaskId(), + watcherRegisterFetchTask, watcherRegisterFetchTask.getExpiryTime()); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/AbstractNodeManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/AbstractNodeManager.java new file mode 100644 index 000000000..274aa4dc4 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/AbstractNodeManager.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.metaserver.GetNodesRequest; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.util.VersionsMapUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractNodeManager.java, v 0.1 2018-03-05 10:44 shangyu.wh Exp $ + */ +public abstract class AbstractNodeManager implements NodeManager { + + private static final Logger LOGGER = LoggerFactory + .getLogger(AbstractNodeManager.class); + + private static final Logger EXCHANGE_LOGGER = LoggerFactory + .getLogger("SESSION-EXCHANGE"); + protected final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + protected final Lock read = readWriteLock + .readLock(); + protected final Lock write = readWriteLock + .writeLock(); + protected Map> nodes = new ConcurrentHashMap<>(); + @Autowired + protected SessionServerConfig sessionServerConfig; + + @Autowired + protected NodeExchanger metaNodeExchanger; + + @Autowired + protected RaftClientManager raftClientManager; + /** + * store other dataCenter data list version + */ + private ConcurrentHashMap dataCenterNodesVersions = new ConcurrentHashMap<>(); + + @Override + public Collection getDataCenterNodes() { + read.lock(); + try { + + Map dataMap = nodes.get(sessionServerConfig + .getSessionServerDataCenter()); + if (dataMap != null) { + return dataMap.values(); + } + } finally { + read.unlock(); + } + return new ArrayList<>(); + } + + @Override + public Collection getDataCenters() { + read.lock(); + try { + return nodes.keySet(); + } finally { + read.unlock(); + } + } + + @Override + public void updateNodes(NodeChangeResult nodeChangeResult) { + write.lock(); + try { + nodes = nodeChangeResult.getNodes(); + dataCenterNodesVersions.putIfAbsent(nodeChangeResult.getLocalDataCenter(), + nodeChangeResult.getVersion()); + } finally { + write.unlock(); + } + } + + public boolean checkAndUpdateListVersions(String dataCenterId, Long version) { + return VersionsMapUtils.checkAndUpdateVersions(dataCenterNodesVersions, dataCenterId, + version); + } + + @Override + public NodeChangeResult getAllDataCenterNodes() { + NodeChangeResult nodeChangeResult; + try { + + Request getNodesRequestRequest = new Request() { + + @Override + public GetNodesRequest getRequestBody() { + return new GetNodesRequest(getNodeType()); + } + + @Override + public URL getRequestUrl() { + return new URL(raftClientManager.getLeader().getIp(), + sessionServerConfig.getMetaServerPort()); + } + }; + + Response response = metaNodeExchanger.request(getNodesRequestRequest); + + if (response != null && response.getResult() != null) { + + nodeChangeResult = response.getResult(); + updateNodes(nodeChangeResult); + + EXCHANGE_LOGGER.info("Update node type {} success!info:{}", getNodeType(), + nodeChangeResult.getNodes()); + } else { + LOGGER.error( + "NodeManager get all dataCenter nodes type {} error!No response receive!", + getNodeType()); + throw new RuntimeException( + "NodeManager get all dataCenter nodes error!No response receive!"); + } + + } catch (RequestException e) { + LOGGER.error("NodeManager get all dataCenter nodes error! " + e.getRequestMessage(), e); + throw new RuntimeException("NodeManager get all dataCenter nodes error! " + + e.getRequestMessage(), e); + } + + return nodeChangeResult; + } + + /** + * Getter method for property dataCenterNodesVersions. + * + * @return property value of dataCenterNodesVersions + */ + @Override + public ConcurrentHashMap getDataCenterNodesVersions() { + return dataCenterNodesVersions; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/DataNodeManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/DataNodeManager.java new file mode 100644 index 000000000..894346efa --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/DataNodeManager.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.DataNode; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.consistency.hash.ConsistentHash; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeManager.java, v 0.1 2017-12-08 19:34 shangyu.wh Exp $ + */ +public class DataNodeManager extends AbstractNodeManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeManager.class, + "[DataNodeManager]"); + + @Autowired + private SessionServerConfig sessionServerConfig; + + private ConsistentHash consistentHash; + + @Override + public DataNode getNode(String dataInfoId) { + DataNode dataNode = consistentHash.getNodeFor(dataInfoId); + if (dataNode == null) { + LOGGER.error("calculate data node error!,dataInfoId={}", dataInfoId); + throw new RuntimeException("DataNodeManager calculate data node error!,dataInfoId=" + + dataInfoId); + } + return dataNode; + } + + @Override + public void updateNodes(NodeChangeResult nodeChangeResult) { + write.lock(); + try { + super.updateNodes(nodeChangeResult); + consistentHash = new ConsistentHash(sessionServerConfig.getNumberOfReplicas(), + getDataCenterNodes()); + + } finally { + write.unlock(); + } + } + + @Override + public NodeType getNodeType() { + return NodeType.DATA; + } + + @Override + public void reNewNode() { + + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/MetaNodeManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/MetaNodeManager.java new file mode 100644 index 000000000..2a2095096 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/MetaNodeManager.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; + +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNodeManager.java, v 0.1 2018-03-05 10:58 shangyu.wh Exp $ + */ +public class MetaNodeManager extends AbstractNodeManager { + + @Override + public MetaNode getNode(String dataInfoId) { + return null; + } + + @Override + public NodeType getNodeType() { + return NodeType.META; + } + + @Override + public Collection getDataCenters() { + return nodes.keySet(); + } + + @Override + public void reNewNode() { + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManager.java new file mode 100644 index 000000000..59b47879a --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManager.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; + +import java.util.Collection; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: NodeManager.java, v 0.1 2017-11-28 11:56 shangyu.wh Exp $ + */ +public interface NodeManager { + + Collection getDataCenterNodes(); + + T getNode(String dataInfoId); + + NodeType getNodeType(); + + void updateNodes(NodeChangeResult nodeChangeResult); + + Collection getDataCenters(); + + void reNewNode(); + + NodeChangeResult getAllDataCenterNodes(); + + ConcurrentHashMap getDataCenterNodesVersions(); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManagerFactory.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManagerFactory.java new file mode 100644 index 000000000..d2f9467dd --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/NodeManagerFactory.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: StoreServiceFactory.java, v 0.1 2018-01-11 22:12 shangyu.wh Exp $ + */ +public class NodeManagerFactory implements ApplicationContextAware { + + private static Map nodeManagerMap = new HashMap<>(); + + public static NodeManager getNodeManager(NodeType nodeType) { + return nodeManagerMap.get(nodeType); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + + Map map = applicationContext.getBeansOfType(NodeManager.class); + + map.forEach((key, value) -> nodeManagerMap.put(value.getNodeType(), value)); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/RaftClientManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/RaftClientManager.java new file mode 100644 index 000000000..4eb4c370c --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/RaftClientManager.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.server.session.bootstrap.CommonConfig; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: RaftClientManager.java, v 0.1 2018-06-20 20:50 shangyu.wh Exp $ + */ +public class RaftClientManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftClientManager.class); + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private CommonConfig commonConfig; + + private RaftClient raftClient; + + private AtomicBoolean clientStart = new AtomicBoolean(false); + + private Set metaIps; + + public void startRaftClient() { + try { + if (clientStart.compareAndSet(false, true)) { + String serverConf = getServerConfig(); + raftClient = new RaftClient(getGroup(), serverConf); + raftClient.start(); + } + } catch (Exception e) { + clientStart.set(false); + LOGGER.error("Start raft client error!", e); + throw new RuntimeException("Start raft client error!", e); + } + } + + private String getServerConfig() { + String ret = ""; + Set ips = getMetaIp(); + if (ips != null && !ips.isEmpty()) { + ret = ips.stream().map(ip -> ip + ":" + ValueConstants.RAFT_SERVER_PORT).collect(Collectors.joining(",")); + } + if (ret.isEmpty()) { + throw new IllegalArgumentException("Init raft server config error!"); + } + return ret; + } + + public Set getMetaIp() { + if (metaIps != null && !metaIps.isEmpty()) { + return metaIps; + } + metaIps = new HashSet<>(); + Map> metaMap = commonConfig.getMetaNode(); + if (metaMap != null && !metaMap.isEmpty()) { + String localDataCenter = sessionServerConfig.getSessionServerDataCenter(); + if (localDataCenter != null && !localDataCenter.isEmpty()) { + Collection metas = metaMap.get(localDataCenter); + if (metas != null && !metas.isEmpty()) { + metas.forEach(domain -> { + String ip = NetUtil.getIPAddressFromDomain(domain); + if (ip == null) { + throw new RuntimeException("Node config convert domain {" + domain + "} error!"); + } + metaIps.add(ip); + }); + } + } + } + return metaIps; + } + + private String getGroup() { + return ValueConstants.RAFT_SERVER_GROUP + "_" + + sessionServerConfig.getSessionServerDataCenter(); + } + + public PeerId getLeader() { + if (raftClient == null) { + startRaftClient(); + } + PeerId leader = raftClient.getLeader(); + if (leader == null) { + LOGGER.error("[RaftClientManager] register MetaServer get no leader!"); + throw new RuntimeException("[RaftClientManager] register MetaServer get no leader!"); + } + return leader; + } + + public PeerId refreshLeader() { + if (raftClient == null) { + startRaftClient(); + } + PeerId leader = raftClient.refreshLeader(); + if (leader == null) { + LOGGER.error("[RaftClientManager] refresh MetaServer get no leader!"); + throw new RuntimeException("[RaftClientManager] refresh MetaServer get no leader!"); + } + return leader; + } + + /** + * Getter method for property clientStart. + * + * @return property value of clientStart + */ + public AtomicBoolean getClientStart() { + return clientStart; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionNodeManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionNodeManager.java new file mode 100644 index 000000000..4c50cfa2e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionNodeManager.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.common.model.metaserver.ReNewNodesRequest; +import com.alipay.sofa.registry.common.model.metaserver.SessionNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: SessionNodeManager.java, v 0.1 2018-03-05 10:42 shangyu.wh Exp $ + */ +public class SessionNodeManager extends AbstractNodeManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionNodeManager.class); + + @Override + public SessionNode getNode(String dataInfoId) { + return null; + } + + @Override + public NodeType getNodeType() { + return NodeType.SESSION; + } + + public List getZoneServerList(String zonename) { + List serverList = new ArrayList<>(); + Collection sessionNodes = getDataCenterNodes(); + if (sessionNodes != null && !sessionNodes.isEmpty()) { + if (zonename == null || zonename.isEmpty()) { + zonename = sessionServerConfig.getSessionServerRegion(); + } + for (SessionNode sessionNode : sessionNodes) { + if (zonename.equals(sessionNode.getRegionId())) { + URL url = sessionNode.getNodeUrl(); + if (url != null) { + serverList.add(url.getIpAddress()); + } + } + } + + } + return serverList; + } + + @Override + public void reNewNode() { + try { + + Request reNewNodesRequestRequest = new Request() { + + @Override + public ReNewNodesRequest getRequestBody() { + URL clientUrl = new URL(NetUtil.getLocalAddress().getHostAddress(), 0); + SessionNode sessionNode = new SessionNode(clientUrl, + sessionServerConfig.getSessionServerRegion()); + + return new ReNewNodesRequest(sessionNode); + } + + @Override + public URL getRequestUrl() { + return new URL(raftClientManager.getLeader().getIp(), + sessionServerConfig.getMetaServerPort()); + } + }; + + metaNodeExchanger.request(reNewNodesRequestRequest); + } catch (RequestException e) { + LOGGER.error("SessionNodeManager reNew node error! " + e.getRequestMessage(), e); + throw new RuntimeException("SessionNodeManager reNew node error! " + + e.getRequestMessage(), e); + } + } + + @Override + public void updateNodes(NodeChangeResult nodeChangeResult) { + write.lock(); + try { + Long receiveVersion = nodeChangeResult.getVersion(); + boolean versionChange = checkAndUpdateListVersions( + sessionServerConfig.getSessionServerDataCenter(), receiveVersion); + if (!versionChange) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Current data type {} list version has not updated!", + getNodeType()); + } + } + nodes = nodeChangeResult.getNodes(); + } finally { + write.unlock(); + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionProcessIdGenerator.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionProcessIdGenerator.java new file mode 100644 index 000000000..bec65516e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/SessionProcessIdGenerator.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node; + +import com.alipay.sofa.registry.net.NetUtil; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Session ProcessID Generator + * @author shangyu.wh + * @version $Id: SessionProcessId.java, v 0.1 2018-04-16 14:37 shangyu.wh Exp $ + */ +public class SessionProcessIdGenerator { + + private volatile static String processId; + + private final static String EMPTY_STRING = ""; + + private final static String PID = getPID(); + + private static AtomicInteger count = new AtomicInteger(1000); + + /** + * Get session processId. + */ + public static String getSessionProcessId() { + if (processId == null) { + synchronized (SessionProcessIdGenerator.class) { + if (processId == null) { + processId = generate(); + } + } + } + return processId; + } + + /** + * Generate session processId. + */ + public static String generate() { + String localIp = NetUtil.getLocalSocketAddress().getAddress().getHostAddress(); + if (localIp != null && !localIp.isEmpty()) { + return getId(getIPHex(localIp), System.currentTimeMillis(), getNextId()); + } + return EMPTY_STRING; + } + + private static String getId(String ip, long timestamp, int nextId) { + StringBuilder appender = new StringBuilder(30); + appender.append(ip).append(timestamp).append(nextId).append(PID); + return appender.toString(); + } + + private static String getIPHex(String ip) { + String[] ips = ip.split("\\."); + StringBuilder sb = new StringBuilder(); + for (String column : ips) { + String hex = Integer.toHexString(Integer.parseInt(column)); + if (hex.length() == 1) { + sb.append('0').append(hex); + } else { + sb.append(hex); + } + + } + return sb.toString(); + } + + /** + * Get process pid + */ + public static String getPID() { + String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName(); + + if (isBlank(processName)) { + return EMPTY_STRING; + } + + String[] processSplitName = processName.split("@"); + + if (processSplitName.length == 0) { + return EMPTY_STRING; + } + + String pid = processSplitName[0]; + + if (isBlank(pid)) { + return EMPTY_STRING; + } + + return pid; + } + + private static int getNextId() { + for (;;) { + int current = count.get(); + int next = (current > 9000) ? 1000 : current + 1; + if (count.compareAndSet(current, next)) { + return next; + } + } + } + + private static boolean isBlank(String str) { + return str == null || str.isEmpty(); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ClientNodeSingleTaskProcessor.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ClientNodeSingleTaskProcessor.java new file mode 100644 index 000000000..0dcc28a69 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ClientNodeSingleTaskProcessor.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: ClientNodeSingleTaskProcessor.java, v 0.1 2017-12-11 19:47 shangyu.wh Exp $ + */ +public class ClientNodeSingleTaskProcessor implements TaskProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger("SESSION-PUSH", "[Task]"); + + @Override + public ProcessingResult process(SessionTask task) { + try { + task.execute(); + return ProcessingResult.Success; + } catch (Throwable throwable) { + LOGGER.error("Client node SingleTask Process error! Task:" + task, throwable); + + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ConsoleSyncSingleTaskProcessor.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ConsoleSyncSingleTaskProcessor.java new file mode 100644 index 000000000..1273789d1 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/ConsoleSyncSingleTaskProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.task.Retryable; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author zhuoyu.sjw + * @version $Id: ConsoleSyncSingleTaskProcessor.java, v 0.1 2018-03-31 16:46 zhuoyu.sjw Exp $$ + */ +public class ConsoleSyncSingleTaskProcessor implements TaskProcessor { + private static final Logger CONSOLE_LOGGER = LoggerFactory.getLogger("SESSION-CONSOLE", + "[Sync]"); + + @Override + public ProcessingResult process(SessionTask task) { + try { + CONSOLE_LOGGER.info("execute {}", task); + task.execute(); + CONSOLE_LOGGER.info("end {}", task); + return ProcessingResult.Success; + } catch (Throwable throwable) { + CONSOLE_LOGGER.error("Sync to console SingleTask Process error! Task:" + task, + throwable); + if (task instanceof Retryable) { + Retryable retryAbleTask = (Retryable) task; + if (retryAbleTask.checkRetryTimes()) { + return ProcessingResult.TransientError; + } + } + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/DataNodeSingleTaskProcessor.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/DataNodeSingleTaskProcessor.java new file mode 100644 index 000000000..74d6c9c43 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/DataNodeSingleTaskProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.task.Retryable; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeSingleTaskProcessor.java, v 0.1 2017-12-11 19:35 shangyu.wh Exp $ + */ +public class DataNodeSingleTaskProcessor implements TaskProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeSingleTaskProcessor.class, + "[Task]"); + + @Override + public ProcessingResult process(SessionTask task) { + try { + LOGGER.info("execute " + task); + task.execute(); + LOGGER.info("end " + task); + return ProcessingResult.Success; + } catch (Throwable throwable) { + LOGGER.error("Data node SingleTask Process error! Task:" + task, throwable); + if (task instanceof Retryable) { + Retryable retryAbleTask = (Retryable) task; + if (retryAbleTask.checkRetryTimes()) { + return ProcessingResult.TransientError; + } + } + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/MetaNodeSingleTaskProcessor.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/MetaNodeSingleTaskProcessor.java new file mode 100644 index 000000000..927cc5ea2 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/processor/MetaNodeSingleTaskProcessor.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.processor; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.scheduler.task.SessionTask; +import com.alipay.sofa.registry.task.Retryable; +import com.alipay.sofa.registry.task.batcher.TaskProcessor; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: DataNodeSingleTaskProcessor.java, v 0.1 2017-12-11 19:35 shangyu.wh Exp $ + */ +public class MetaNodeSingleTaskProcessor implements TaskProcessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetaNodeSingleTaskProcessor.class, + "[Task]"); + + @Override + public ProcessingResult process(SessionTask task) { + try { + LOGGER.info("execute " + task); + task.execute(); + LOGGER.info("end " + task); + return ProcessingResult.Success; + } catch (Throwable throwable) { + LOGGER.error("Meta node SingleTask Process error! Task:" + task, throwable); + if (task instanceof Retryable) { + Retryable retryAbleTask = (Retryable) task; + if (retryAbleTask.checkRetryTimes()) { + return ProcessingResult.TransientError; + } + } + return ProcessingResult.PermanentError; + } + } + + @Override + public ProcessingResult process(List tasks) { + return null; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeService.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeService.java new file mode 100644 index 000000000..30ce420d3 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeService.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.service; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.CallbackHandler; + +/** + * + * @author shangyu.wh + * @version $Id: ClientNodeService.java, v 0.1 2017-12-01 11:16 shangyu.wh Exp $ + */ +public interface ClientNodeService { + + void pushWithCallback(Object object, URL url, CallbackHandler callbackHandler); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeServiceImpl.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeServiceImpl.java new file mode 100644 index 000000000..7ab6333cf --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/ClientNodeServiceImpl.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.service; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: ClientNode.java, v 0.1 2017-12-12 11:56 shangyu.wh Exp $ + */ +public class ClientNodeServiceImpl implements ClientNodeService { + @Autowired + private NodeExchanger clientNodeExchanger; + + @Override + public void pushWithCallback(Object object, URL url, CallbackHandler callbackHandler) { + + try { + Request request = new Request() { + + @Override + public Object getRequestBody() { + return object; + } + + @Override + public URL getRequestUrl() { + return url; + } + + @Override + public CallbackHandler getCallBackHandler() { + return callbackHandler; + } + }; + + clientNodeExchanger.request(request); + + } catch (RequestException e) { + throw new RuntimeException("Push data to client node error !" + e.getRequestMessage(), + e); + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeService.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeService.java new file mode 100644 index 000000000..df1180ba8 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeService.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.service; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.SessionServerRegisterRequest; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.URL; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: NodeService.java, v 0.1 2017-11-28 11:09 shangyu.wh Exp $ + */ +public interface DataNodeService { + + /** + * new publisher data transform to data server + * + * @param publisher + */ + void register(Publisher publisher); + + /** + * remove publisher data from data server + * + * @param publisher + */ + void unregister(Publisher publisher); + + /** + * session server support api to stop some client node,all register data on data server will be removed + * data on session server will be remove too + * + * @param connectIds + */ + void clientOff(List connectIds); + + /** + * Get some dataInfoId version from one data server + * + * @param dataNodeUrl + * @param dataInfoIdList + * @return + */ + Map> fetchDataVersion(URL dataNodeUrl, + Collection dataInfoIdList); + + /** + * fetch one dataCenter publisher data from data server + * + * @param dataInfoId + * @param dataCenterId + * @return + */ + Datum fetchDataCenter(String dataInfoId, String dataCenterId); + + /** + * fetch all dataCenter datum + * @param dataInfoId + * @return + */ + Map fetchGlobal(String dataInfoId); + + /** + * fetch datum by specify dataCenter and dataInfoId + * @param dataInfoId + * @param dataCenterId + * @return + */ + Map getDatumMap(String dataInfoId, String dataCenterId); + + /** + * register session process id when connect to data node + * process id see SessionProcessIdGenerator + * @param sessionServerRegisterRequest + * @param dataUrl + */ + void registerSessionProcessId(SessionServerRegisterRequest sessionServerRegisterRequest, + URL dataUrl); + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeServiceImpl.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeServiceImpl.java new file mode 100644 index 000000000..4337f2432 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/DataNodeServiceImpl.java @@ -0,0 +1,469 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.service; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.dataserver.ClientOffRequest; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.GetDataRequest; +import com.alipay.sofa.registry.common.model.dataserver.GetDataVersionRequest; +import com.alipay.sofa.registry.common.model.dataserver.PublishDataRequest; +import com.alipay.sofa.registry.common.model.dataserver.SessionServerRegisterRequest; +import com.alipay.sofa.registry.common.model.dataserver.UnPublishDataRequest; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.SessionProcessIdGenerator; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer.TaskFailedCallback; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: DataNode.java, v 0.1 2017-12-01 11:30 shangyu.wh Exp $ + */ +public class DataNodeServiceImpl implements DataNodeService { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeServiceImpl.class); + + @Autowired + private NodeExchanger dataNodeExchanger; + + @Autowired + private NodeManager dataNodeManager; + + @Autowired + private SessionServerConfig sessionServerConfig; + + private AsyncHashedWheelTimer asyncHashedWheelTimer; + + public DataNodeServiceImpl() { + ThreadFactoryBuilder threadFactoryBuilder = new ThreadFactoryBuilder(); + threadFactoryBuilder.setDaemon(true); + asyncHashedWheelTimer = new AsyncHashedWheelTimer(threadFactoryBuilder.setNameFormat( + "Registry-DataNodeServiceImpl-WheelTimer").build(), 100, TimeUnit.MILLISECONDS, 1024, + threadFactoryBuilder.setNameFormat("Registry-DataNodeServiceImpl-WheelExecutor-%d") + .build(), new TaskFailedCallback() { + @Override + public void executionRejected(Throwable e) { + LOGGER.error("executionRejected: " + e.getMessage(), e); + } + + @Override + public void executionFailed(Throwable e) { + LOGGER.error("executionFailed: " + e.getMessage(), e); + } + }); + } + + @Override + public void register(final Publisher publisher) { + + try { + + Request publisherRequest = new Request() { + + private URL url; + + @Override + public PublishDataRequest getRequestBody() { + PublishDataRequest publishDataRequest = new PublishDataRequest(); + publishDataRequest.setPublisher(publisher); + publishDataRequest.setSessionServerProcessId(SessionProcessIdGenerator + .getSessionProcessId()); + return publishDataRequest; + } + + @Override + public URL getRequestUrl() { + if (url == null) { + url = getUrl(publisher.getDataInfoId()); + } + return url; + } + }; + + Response response = dataNodeExchanger.request(publisherRequest); + + Object result = response.getResult(); + if (result instanceof CommonResponse) { + CommonResponse commonResponse = (CommonResponse) result; + if (!commonResponse.isSuccess()) { + LOGGER.error( + "PublishDataRequest get server response failed!target url:{},message:{}", + publisherRequest.getRequestUrl(), commonResponse.getMessage()); + throw new RuntimeException( + "PublishDataRequest get server response failed! msg:" + + commonResponse.getMessage()); + } + } + } catch (RequestException e) { + LOGGER.error("DataNodeService register new publisher error! " + e.getRequestMessage(), + e); + throw new RuntimeException("DataNodeService register new publisher error! " + + e.getRequestMessage(), e); + } + } + + @Override + public void unregister(final Publisher publisher) { + try { + Request unPublishRequest = new Request() { + + private URL url; + + @Override + public UnPublishDataRequest getRequestBody() { + UnPublishDataRequest unPublishDataRequest = new UnPublishDataRequest(); + unPublishDataRequest.setDataInfoId(publisher.getDataInfoId()); + unPublishDataRequest.setRegisterId(publisher.getRegisterId()); + unPublishDataRequest.setRegisterTimestamp(publisher.getRegisterTimestamp()); + return unPublishDataRequest; + } + + @Override + public URL getRequestUrl() { + if (url == null) { + url = getUrl(publisher.getDataInfoId()); + } + return url; + } + }; + + Response response = dataNodeExchanger.request(unPublishRequest); + + Object result = response.getResult(); + if (result instanceof CommonResponse) { + CommonResponse commonResponse = (CommonResponse) result; + if (!commonResponse.isSuccess()) { + LOGGER.error( + "UnPublishRequest get server response failed!target url:{},message:{}", + unPublishRequest.getRequestUrl(), commonResponse.getMessage()); + throw new RuntimeException("UnPublishRequest get server response failed! msg:" + + commonResponse.getMessage()); + } + } + + } catch (RequestException e) { + LOGGER.error("Unregister publisher to data node error! " + e.getRequestMessage(), e); + throw new RuntimeException("Unregister publisher to data node error! " + + e.getRequestMessage(), e); + } + + } + + @Override + public void clientOff(List connectIds) { + if (connectIds == null || connectIds.isEmpty()) { + return; + } + //get all local dataCenter data node + Collection nodes = dataNodeManager.getDataCenterNodes(); + if (nodes != null && nodes.size() > 0) { + + for (Node node : nodes) { + Request clientOffRequestRequest = new Request() { + + private AtomicInteger retryTimes = new AtomicInteger(); + + @Override + public ClientOffRequest getRequestBody() { + ClientOffRequest clientOffRequest = new ClientOffRequest(); + clientOffRequest.setHosts(connectIds); + clientOffRequest.setGmtOccur(System.currentTimeMillis()); + return clientOffRequest; + } + + @Override + public URL getRequestUrl() { + return new URL(node.getNodeUrl().getIpAddress(), + sessionServerConfig.getDataServerPort()); + } + + @Override + public AtomicInteger getRetryTimes() { + return retryTimes; + } + }; + try { + + Response response = dataNodeExchanger.request(clientOffRequestRequest); + Object result = response.getResult(); + if (result instanceof CommonResponse) { + CommonResponse commonResponse = (CommonResponse) result; + if (!commonResponse.isSuccess()) { + LOGGER + .error( + "ClientOff RequestRequest get response failed!target url:{},message:{}", + node.getNodeUrl(), commonResponse.getMessage()); + throw new RuntimeException( + "ClientOff RequestRequest get response failed! msg:" + + commonResponse.getMessage()); + } + } else { + LOGGER + .error( + "ClientOff Request has not get response or response type illegal!url:{}", + node.getNodeUrl()); + throw new RuntimeException( + "ClientOff Request has not get response or response type illegal!"); + } + } catch (Exception e) { + LOGGER.error("Client Off request error! ", e); + clientOffRetry(clientOffRequestRequest); + } + + } + } + } + + private void clientOffRetry(Request clientOffRequestRequest) { + + URL url = clientOffRequestRequest.getRequestUrl(); + + int retryTimes = clientOffRequestRequest.getRetryTimes().incrementAndGet(); + + if (retryTimes <= sessionServerConfig.getCancelDataTaskRetryTimes()) { + asyncHashedWheelTimer.newTimeout(timeout -> { + try { + Response response = dataNodeExchanger.request(clientOffRequestRequest); + Object result = response.getResult(); + if (result instanceof CommonResponse) { + CommonResponse commonResponse = (CommonResponse) result; + if (!commonResponse.isSuccess()) { + LOGGER.error( + "ClientOff retry RequestRequest get response failed!retryTimes={},target url:{},message:{}", + retryTimes, + url, commonResponse.getMessage()); + throw new RuntimeException( + "ClientOff retry RequestRequest get response failed! msg:" + + commonResponse.getMessage()); + } + } else { + LOGGER.error( + "ClientOff retry Request has not get response or response type illegal!retryTimes={},url:{}", + retryTimes, url); + throw new RuntimeException( + "ClientOff retry Request has not get response or response type illegal!"); + } + } catch (Exception e) { + clientOffRetry(clientOffRequestRequest); + } + }, getBlockTime(retryTimes), TimeUnit.MILLISECONDS); + } else { + LOGGER.error("ClientOff retryTimes have exceeded! stop retry! retryTimes={}, url={}, request={}", + retryTimes, url, clientOffRequestRequest.getRequestBody()); + } + } + + private long getBlockTime(int retry) { + long initialSleepTime = TimeUnit.MILLISECONDS.toMillis(sessionServerConfig + .getCancelDataTaskRetryFirstDelay()); + long increment = TimeUnit.MILLISECONDS.toMillis(sessionServerConfig + .getCancelDataTaskRetryIncrementDelay()); + long result = initialSleepTime + (increment * (retry - 1)); + return result >= 0L ? result : 0L; + } + + @Override + public void registerSessionProcessId(final SessionServerRegisterRequest sessionServerRegisterRequest, + final URL dataUrl) { + + try { + + Request request = new Request() { + + @Override + public SessionServerRegisterRequest getRequestBody() { + return sessionServerRegisterRequest; + } + + @Override + public URL getRequestUrl() { + return dataUrl; + } + }; + + dataNodeExchanger.request(request); + } catch (RequestException e) { + LOGGER.error("DataNodeService register processId error! " + e.getRequestMessage(), e); + throw new RuntimeException("DataNodeService register processId error! " + + e.getRequestMessage(), e); + } + } + + @Override + public Map> fetchDataVersion(URL dataNodeUrl, + Collection dataInfoIdList) { + + Map> map = new HashMap<>(); + try { + + Request getDataVersionRequestRequest = new Request() { + @Override + public GetDataVersionRequest getRequestBody() { + GetDataVersionRequest getDataVersionRequest = new GetDataVersionRequest(); + getDataVersionRequest.setDataInfoIds((List) dataInfoIdList); + return getDataVersionRequest; + } + + @Override + public URL getRequestUrl() { + return dataNodeUrl; + } + }; + + Response response = dataNodeExchanger.request(getDataVersionRequestRequest); + + Object result = response.getResult(); + if (result instanceof GenericResponse) { + GenericResponse genericResponse = (GenericResponse) result; + if (genericResponse.isSuccess()) { + map = (Map>) genericResponse.getData(); + if (map.isEmpty()) { + LOGGER + .warn( + "GetDataVersionRequestRequest get response contains no data!target data Node url:{} about dataInfoIds size:{}", + dataNodeUrl.getAddressString(), dataInfoIdList.size()); + } + } else { + LOGGER.error("fetchDataVersion has not get fail response!msg:{}", + genericResponse.getMessage()); + throw new RuntimeException("fetchDataVersion has not get fail response! msg:" + + genericResponse.getMessage()); + } + } else { + LOGGER + .error("GetDataVersionRequestRequest has not get response or response type illegal!"); + } + + } catch (RequestException e) { + LOGGER.error("Fetch data Version request error! " + e.getRequestMessage(), e); + throw new RuntimeException( + "Fetch data Version request error! " + e.getRequestMessage(), e); + } + + return map; + } + + @Override + public Datum fetchDataCenter(String dataInfoId, String dataCenterId) { + + Map map = getDatumMap(dataInfoId, dataCenterId); + if (map != null && map.size() > 0) { + return map.get(dataCenterId); + } + return null; + } + + @Override + public Map fetchGlobal(String dataInfoId) { + //get all dataCenter data + return getDatumMap(dataInfoId); + } + + private Map getDatumMap(String dataInfoId) { + return getDatumMap(dataInfoId, null); + } + + @Override public Map getDatumMap(String dataInfoId, String dataCenterId) { + + Map map; + + try { + + GetDataRequest getDataRequest = new GetDataRequest(); + + //dataCenter null means all dataCenters + if (dataCenterId != null) { + getDataRequest.setDataCenter(dataCenterId); + } + + getDataRequest.setDataInfoId(dataInfoId); + + Request getDataRequestStringRequest = new Request() { + + @Override + public GetDataRequest getRequestBody() { + return getDataRequest; + } + + @Override + public URL getRequestUrl() { + return getUrl(dataInfoId); + } + }; + + Response response = dataNodeExchanger.request(getDataRequestStringRequest); + Object result = response.getResult(); + if (result instanceof GenericResponse) { + GenericResponse genericResponse = (GenericResponse) result; + if (genericResponse.isSuccess()) { + map = (Map) genericResponse.getData(); + if (map == null || map.isEmpty()) { + LOGGER.warn("GetDataRequest get response contains no datum!"); + } else { + map.forEach((dataCenter, datum) -> Datum.processDatum(datum)); + } + } else { + LOGGER.error("GetDataRequest has not get fail response!msg:{}", genericResponse.getMessage()); + throw new RuntimeException("GetDataRequest has not get fail response! msg:" + + genericResponse.getMessage()); + } + } else { + LOGGER.error("GetDataRequest has not get response or response type illegal!"); + throw new RuntimeException("GetDataRequest has not get response or response type illegal!"); + } + } catch (RequestException e) { + LOGGER.error("Get data request to data node error! " + e.getRequestMessage(), e); + throw new RuntimeException( + "Get data request to data node error! " + e.getRequestMessage(), e); + } + + return map; + } + + private URL getUrl(String dataInfoId) { + + Node dataNode = dataNodeManager.getNode(dataInfoId); + if (dataNode != null) { + //meta push data node has not port + String dataIp = dataNode.getNodeUrl().getIpAddress(); + return new URL(dataIp, sessionServerConfig.getDataServerPort()); + } + return null; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeService.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeService.java new file mode 100644 index 000000000..e0a478ed5 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeService.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.service; + +import com.alipay.sofa.registry.common.model.metaserver.ProvideData; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNodeService.java, v 0.1 2018-04-17 19:57 shangyu.wh Exp $ + */ +public interface MetaNodeService { + + /** + * fetch persistence data from meta server + * @param dataInfoId + * @return + */ + ProvideData fetchData(String dataInfoId); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeServiceImpl.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeServiceImpl.java new file mode 100644 index 000000000..85eef1f9a --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/node/service/MetaNodeServiceImpl.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.node.service; + +import com.alipay.sofa.registry.common.model.metaserver.FetchProvideDataRequest; +import com.alipay.sofa.registry.common.model.metaserver.ProvideData; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.RaftClientManager; +import com.alipay.sofa.registry.server.session.node.SessionNodeManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: MetaNodeServiceImpl.java, v 0.1 2018-04-17 21:23 shangyu.wh Exp $ + */ +public class MetaNodeServiceImpl implements MetaNodeService { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionNodeManager.class, + "[MetaNodeService]"); + + @Autowired + protected SessionServerConfig sessionServerConfig; + + @Autowired + protected NodeExchanger metaNodeExchanger; + + @Autowired + RaftClientManager raftClientManager; + + @Override + public ProvideData fetchData(String dataInfoId) { + try { + + Request request = new Request() { + + @Override + public FetchProvideDataRequest getRequestBody() { + + return new FetchProvideDataRequest(dataInfoId); + } + + @Override + public URL getRequestUrl() { + return new URL(raftClientManager.getLeader().getIp(), + sessionServerConfig.getMetaServerPort()); + } + }; + + Response response = metaNodeExchanger.request(request); + + Object result = response.getResult(); + if (result instanceof ProvideData) { + return (ProvideData) result; + } else { + LOGGER.error("fetch null provider data!"); + throw new RuntimeException("MetaNodeService fetch null provider data!"); + } + } catch (RequestException e) { + LOGGER.error("fetch provider data error! " + e.getRequestMessage(), e); + throw new RuntimeException("fetch provider data error! " + e.getRequestMessage(), e); + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/Registry.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/Registry.java new file mode 100644 index 000000000..6d4920f14 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/Registry.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.registry; + +import com.alipay.sofa.registry.common.model.store.StoreData; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: SessionRegistry.java, v 0.1 2017-11-27 19:49 shangyu.wh Exp $ + */ +public interface Registry { + + /** + * register new publisher or subscriber data + * + * @param data + */ + void register(StoreData data); + + /** + * cancel publisher or subscriber data by client ip address and port(ip:port),one ip address has more than one processId + * when disconnection between client node and session node,disconnect event fire remove all pub and sub info on session and data node + * this function always use in Console manage Client node list,input ip list must transform to connectId through connect manage + * + * @param connectIds + */ + void cancel(List connectIds); + + /** + * message mode com.alipay.sofa.registry.client.provider for client node to unregister single subscriber or publisher data + * + * @param data + */ + void unRegister(StoreData data); + + /** + * Timing tasks to send all subscriber dataInfoId version to data, + * Select higher version data push to client node + * + */ + void fetchChangData(); + + /** + * for fetchChangData first invoke + */ + void fetchChangDataProcess(); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/SessionRegistry.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/SessionRegistry.java new file mode 100644 index 000000000..fe40e3a48 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/registry/SessionRegistry.java @@ -0,0 +1,284 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.registry; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.store.BaseInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.StoreData; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.server.session.strategy.SessionRegistryStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractSessionRegistry.java, v 0.1 2017-11-30 18:13 shangyu.wh Exp $ + */ +public class SessionRegistry implements Registry { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionRegistry.class); + + private static final Logger TASK_LOGGER = LoggerFactory.getLogger(SessionRegistry.class, + "[Task]"); + + /** + * store subscribers + */ + @Autowired + private Interests sessionInterests; + + /** + * store watchers + */ + @Autowired + private Watchers sessionWatchers; + + /** + * store publishers + */ + @Autowired + private DataStore sessionDataStore; + + /** + * transfer data to DataNode + */ + @Autowired + private DataNodeService dataNodeService; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + /** + * calculate data node url + */ + @Autowired + private NodeManager dataNodeManager; + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionRegistryStrategy sessionRegistryStrategy; + + @Override + public void register(StoreData storeData) { + + //check connect already existed + checkConnect(storeData); + + switch (storeData.getDataType()) { + case PUBLISHER: + Publisher publisher = (Publisher) storeData; + + dataNodeService.register(publisher); + + sessionDataStore.add(publisher); + + sessionRegistryStrategy.afterPublisherRegister(publisher); + break; + case SUBSCRIBER: + Subscriber subscriber = (Subscriber) storeData; + + sessionInterests.add(subscriber); + + sessionRegistryStrategy.afterSubscriberRegister(subscriber); + break; + case WATCHER: + Watcher watcher = (Watcher) storeData; + + sessionWatchers.add(watcher); + + sessionRegistryStrategy.afterWatcherRegister(watcher); + break; + default: + break; + } + + } + + @Override + public void unRegister(StoreData storeData) { + + switch (storeData.getDataType()) { + case PUBLISHER: + Publisher publisher = (Publisher) storeData; + + sessionDataStore.deleteById(storeData.getId(), publisher.getDataInfoId()); + + dataNodeService.unregister(publisher); + + sessionRegistryStrategy.afterPublisherUnRegister(publisher); + break; + + case SUBSCRIBER: + Subscriber subscriber = (Subscriber) storeData; + sessionInterests.deleteById(storeData.getId(), subscriber.getDataInfoId()); + sessionRegistryStrategy.afterSubscriberUnRegister(subscriber); + break; + + case WATCHER: + Watcher watcher = (Watcher) storeData; + + sessionWatchers.deleteById(watcher.getId(), watcher.getDataInfoId()); + + sessionRegistryStrategy.afterWatcherUnRegister(watcher); + break; + default: + break; + } + + } + + @Override + public void cancel(List connectIds) { + TaskEvent taskEvent = new TaskEvent(connectIds, TaskType.CANCEL_DATA_TASK); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public void fetchChangData() { + if (!sessionServerConfig.isBeginDataFetchTask()) { + try { + TimeUnit.MILLISECONDS.sleep(500); + } catch (InterruptedException e) { + LOGGER.error("fetchChangData task sleep InterruptedException", e); + } + return; + } + + fetchChangDataProcess(); + } + + @Override + public void fetchChangDataProcess() { + + //check dataInfoId's sub list is not empty + List checkDataInfoIds = new ArrayList<>(); + sessionInterests.getInterestDataInfoIds().forEach((dataInfoId) -> { + Collection subscribers = sessionInterests.getInterests(dataInfoId); + if (subscribers != null && !subscribers.isEmpty()) { + checkDataInfoIds.add(dataInfoId); + } + }); + Map/*dataInfoIds*/> map = calculateDataNode(checkDataInfoIds); + + map.forEach((address, dataInfoIds) -> { + + //TODO asynchronous fetch version + Map> dataVersions = dataNodeService + .fetchDataVersion(URL.valueOf(address), dataInfoIds); + + if (dataVersions != null) { + sessionRegistryStrategy.doFetchChangDataProcess(dataVersions); + } else { + LOGGER.warn("Fetch no change data versions info from {}", address); + } + }); + + } + + private Map> calculateDataNode(Collection dataInfoIds) { + + Map> map = new HashMap<>(); + if (dataInfoIds != null) { + dataInfoIds.forEach(dataInfoId -> { + Node dataNode = dataNodeManager.getNode(dataInfoId); + URL url = new URL(dataNode.getNodeUrl().getIpAddress(), + sessionServerConfig.getDataServerPort()); + Collection list = map.computeIfAbsent(url.getAddressString(), + k -> new ArrayList<>()); + list.add(dataInfoId); + }); + } + + return map; + } + + private void checkConnect(StoreData storeData) { + + BaseInfo baseInfo = (BaseInfo) storeData; + + Server sessionServer = boltExchange.getServer(sessionServerConfig.getServerPort()); + + Channel channel = sessionServer.getChannel(baseInfo.getSourceAddress()); + + if (channel == null) { + throw new RuntimeException(String.format( + "Register address %s has not connected session server!", + baseInfo.getSourceAddress())); + } + + } + + /** + * Getter method for property sessionInterests. + * + * @return property value of sessionInterests + */ + public Interests getSessionInterests() { + return sessionInterests; + } + + /** + * Getter method for property sessionDataStore. + * + * @return property value of sessionDataStore + */ + public DataStore getSessionDataStore() { + return sessionDataStore; + } + + /** + * Getter method for property taskListenerManager. + * + * @return property value of taskListenerManager + */ + public TaskListenerManager getTaskListenerManager() { + return taskListenerManager; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/ClientNodeExchanger.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/ClientNodeExchanger.java new file mode 100644 index 000000000..86d5bedba --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/ClientNodeExchanger.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.remoting.exchange.message.Response.ResultStatus; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: ClientNodeExchanger.java, v 0.1 2017-12-12 12:13 shangyu.wh Exp $ + */ +public class ClientNodeExchanger implements NodeExchanger { + private static final Logger LOGGER = LoggerFactory.getLogger("SESSION-PUSH", "[Exchange]"); + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Override + public Response request(Request request) throws RequestException { + Response response = null; + try { + //sender who session node send message to client node + Server sessionServer = boltExchange.getServer(sessionServerConfig.getServerPort()); + + if (sessionServer != null) { + URL url = request.getRequestUrl(); + if (url != null) { + Channel channel = sessionServer.getChannel(url); + + if (channel != null && channel.isConnected()) { + if (null != request.getCallBackHandler()) { + //TODO log ASYNC + sessionServer.sendCallback(channel, request.getRequestBody(), + request.getCallBackHandler(), + sessionServerConfig.getClientNodeExchangeTimeOut()); + response = () -> ResultStatus.SUCCESSFUL; + } else { + final Object result = sessionServer.sendSync(channel, + request.getRequestBody(), + sessionServerConfig.getClientNodeExchangeTimeOut()); + response = () -> result; + } + } else { + LOGGER.error( + "ClientNode Exchanger get channel {} error! Can't be null or disconnected!", + url); + throw new RequestException("ClientNode Exchanger get channel " + url + + "error! Can't be null or disconnected!", + request); + } + } + } + } catch (Exception e) { + throw new RequestException("ClientNode Exchanger request data error!", request, e); + } + return response; + } + + @Override + public Client connectServer() { + return null; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/DataNodeExchanger.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/DataNodeExchanger.java new file mode 100644 index 000000000..fb49eb26f --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/DataNodeExchanger.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.remoting.handler.AbstractClientHandler; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * The type Data node exchanger. + * @author shangyu.wh + * @version $Id : DataNodeExchanger.java, v 0.1 2017-12-01 11:51 shangyu.wh Exp $ + */ +public class DataNodeExchanger implements NodeExchanger { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataNodeExchanger.class); + private static final Logger EXCHANGE_LOGGER = LoggerFactory + .getLogger("SESSION-EXCHANGE"); + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Resource(name = "dataClientHandlers") + private Collection dataClientHandlers; + + @Autowired + private NodeManager dataNodeManager; + + /** + * @see DataNodeExchanger#request(Request) + */ + @Override + public Response request(Request request) throws RequestException { + + Response response; + URL url = request.getRequestUrl(); + try { + Client sessionClient = boltExchange.getClient(Exchange.DATA_SERVER_TYPE); + + if (sessionClient == null) { + LOGGER.warn( + "DataNode Exchanger get dataServer connection {} error! Connection can not be null or disconnected!", + url); + //first start session maybe case sessionClient null,try to auto connect + sessionClient = boltExchange.connect(Exchange.DATA_SERVER_TYPE, url, + dataClientHandlers.toArray(new ChannelHandler[dataClientHandlers.size()])); + } + //try to connect data + Channel channel = sessionClient.getChannel(url); + if (channel == null) { + channel = sessionClient.connect(url); + } + EXCHANGE_LOGGER.info("DataNode Exchanger request={},url={}", request.getRequestBody(), url); + + final Object result = sessionClient.sendSync(channel, request.getRequestBody(), + sessionServerConfig.getDataNodeExchangeTimeOut()); + if (result == null) { + LOGGER.error("DataNode Exchanger request data get null result!Request url:" + url); + throw new RequestException("DataNode Exchanger request data get null result!", + request); + } + response = () -> result; + } catch (Exception e) { + LOGGER.error("DataNode Exchanger request data error!request={},url={}", request.getRequestBody(), url, e); + throw new RequestException("DataNode Exchanger request data error!Request url:" + url, + request, e); + } + + return response; + } + + @Override + public Client connectServer() { + + Collection dataNodes = dataNodeManager.getDataCenterNodes(); + if (dataNodes == null || dataNodes.isEmpty()) { + dataNodeManager.getAllDataCenterNodes(); + dataNodes = dataNodeManager.getDataCenterNodes(); + } + + Client dataClient = null; + for (Node dataNode : dataNodes) { + if (dataNode.getNodeUrl() == null || dataNode.getNodeUrl().getIpAddress() == null) { + LOGGER.error("get data node address error!url{}", dataNode.getNodeUrl()); + continue; + } + + URL url = new URL(dataNode.getNodeUrl().getIpAddress(), + sessionServerConfig.getDataServerPort()); + try { + dataClient = boltExchange.getClient(Exchange.DATA_SERVER_TYPE); + if (dataClient == null) { + dataClient = boltExchange.connect(Exchange.DATA_SERVER_TYPE, url, + dataClientHandlers.toArray(new ChannelHandler[dataClientHandlers.size()])); + } + } catch (Exception e) { + LOGGER.error("DataNode Exchanger connect DataServer error!url:" + url, e); + continue; + } + + try { + Channel channel = dataClient.getChannel(url); + if (channel == null) { + dataClient.connect(url); + } + } catch (Exception e) { + LOGGER.error("DataNode Exchanger connect channel error!url:" + url, e); + } + } + return dataClient; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/MetaNodeExchanger.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/MetaNodeExchanger.java new file mode 100644 index 000000000..5f66bf863 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/MetaNodeExchanger.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting; + +import com.alipay.sofa.registry.common.model.metaserver.MetaNode; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Client; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.remoting.exchange.RequestException; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.remoting.exchange.message.Response; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.RaftClientManager; +import com.alipay.sofa.registry.server.session.remoting.handler.AbstractClientHandler; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Resource; +import java.util.Collection; + +/** + * The type Data node exchanger. + * @author shangyu.wh + * @version $Id : DataNodeExchanger.java, v 0.1 2017-12-01 11:51 shangyu.wh Exp $ + */ +public class MetaNodeExchanger implements NodeExchanger { + + private static final Logger LOGGER = LoggerFactory + .getLogger(MetaNodeExchanger.class); + + @Autowired + private Exchange boltExchange; + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Resource(name = "metaClientHandlers") + private Collection metaClientHandlers; + + @Autowired + private RaftClientManager raftClientManager; + + @Autowired + private NodeManager metaNodeManager; + + /** + * @see MetaNodeExchanger#request(Request) + */ + @Override + public Response request(Request request) throws RequestException { + + Response response; + URL url = request.getRequestUrl(); + try { + Client sessionClient = boltExchange.getClient(Exchange.META_SERVER_TYPE); + + if (sessionClient == null) { + LOGGER.warn( + "MetaNode Exchanger get dataServer connection {} error! Connection can not be null or disconnected!", + url); + sessionClient = boltExchange.connect(Exchange.META_SERVER_TYPE, url, + metaClientHandlers.toArray(new ChannelHandler[metaClientHandlers.size()])); + } + //try to connect data + Channel channel = sessionClient.getChannel(url); + if (channel == null) { + channel = sessionClient.connect(url); + } + try { + + final Object result = sessionClient.sendSync(channel, request.getRequestBody(), + sessionServerConfig.getDataNodeExchangeTimeOut()); + response = () -> result; + + } catch (Exception e) { + //retry + url = new URL(raftClientManager.refreshLeader().getIp(), + sessionServerConfig.getMetaServerPort()); + channel = sessionClient.getChannel(url); + if (channel == null) { + channel = sessionClient.connect(url); + } + LOGGER.warn("MetaNode Exchanger request send error!It will be retry once!Request url:{}", url); + + final Object result = sessionClient.sendSync(channel, request.getRequestBody(), + sessionServerConfig.getDataNodeExchangeTimeOut()); + response = () -> result; + } + } catch (Exception e) { + LOGGER.error("MetaNode Exchanger request data error!Request url:" + url, e); + throw new RequestException("MetaNode Exchanger request data error!Request url:" + url, + request, e); + } + + return response; + } + + @Override + public Client connectServer() { + + Collection nodes = metaNodeManager.getDataCenterNodes(); + if (nodes == null || nodes.isEmpty()) { + metaNodeManager.getAllDataCenterNodes(); + nodes = metaNodeManager.getDataCenterNodes(); + } + Client sessionClient = null; + for (MetaNode node : nodes) { + URL url = new URL(node.getIp(), sessionServerConfig.getMetaServerPort()); + try { + sessionClient = boltExchange.getClient(Exchange.META_SERVER_TYPE); + if (sessionClient == null) { + sessionClient = boltExchange.connect(Exchange.META_SERVER_TYPE, url, + metaClientHandlers.toArray(new ChannelHandler[metaClientHandlers.size()])); + } + } catch (Exception e) { + LOGGER.error("MetaNode Exchanger connect MetaServer error!url:" + url, e); + continue; + } + try { + Channel channel = sessionClient.getChannel(url); + if (channel == null) { + sessionClient.connect(url); + } + } catch (Exception e) { + LOGGER.error("MetaNode Exchanger connect channel error!url:" + url, e); + } + } + return sessionClient; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractClientHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractClientHandler.java new file mode 100644 index 000000000..7cbeebdc3 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractClientHandler.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; + +/** + * + * @author shangyu.wh + * @version $Id: ClientHandler.java, v 0.1 2017-11-28 18:06 shangyu.wh Exp $ + */ +public abstract class AbstractClientHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("SESSION-CONNECT"); + + @Override + public void connected(Channel channel) throws RemotingException { + if (channel != null && channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node connected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) { + if (channel != null && !channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node disconnected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + protected abstract NodeType getConnectNodeType(); + + @Override + public void caught(Channel channel, T message, Throwable exception) { + + } + + @Override + public void received(Channel channel, T message) { + + } + + @Override + public Object reply(Channel channel, T message) { + return null; + } + + @Override + public Class interest() { + return null; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractServerHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractServerHandler.java new file mode 100644 index 000000000..bf8e42e81 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/AbstractServerHandler.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; + +/** + * + * @author shangyu.wh + * @version $Id: ServerHandler.java, v 0.1 2017-11-28 18:06 shangyu.wh Exp $ + */ +public abstract class AbstractServerHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("SESSION-CONNECT"); + + @Override + public void connected(Channel channel) throws RemotingException { + if (channel != null && channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node connected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + if (channel != null && !channel.isConnected()) { + LOGGER + .info(getConnectNodeType() + " node disconnected,remote address:" + + channel.getRemoteAddress() + " localAddress:" + channel.getLocalAddress()); + } + } + + protected NodeType getConnectNodeType() { + return NodeType.CLIENT; + } + + @Override + public void caught(Channel channel, T message, Throwable exception) { + + } + + @Override + public void received(Channel channel, T message) { + + } + + @Override + public Object reply(Channel channel, T message) throws RemotingException { + return null; + } + + @Override + public Class interest() { + return null; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/CancelAddressRequestHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/CancelAddressRequestHandler.java new file mode 100644 index 000000000..83f77ff2a --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/CancelAddressRequestHandler.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.sessionserver.CancelAddressRequest; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: CancelHandler.java, v 0.1 2017-11-30 15:29 shangyu.wh Exp $ + */ +public class CancelAddressRequestHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(CancelAddressRequestHandler.class); + + private static final Logger EXCHANGE_LOGGER = LoggerFactory.getLogger("SESSION-EXCHANGE", + "[CancelAddressRequestHandler]"); + + @Autowired + private Registry sessionRegistry; + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return CancelAddressRequest.class; + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.CLIENT; + } + + @Override + public Object reply(Channel channel, CancelAddressRequest cancelProcessRequest) { + + Result result = new Result(); + + try { + EXCHANGE_LOGGER.info("request={}", cancelProcessRequest); + List connectIds = cancelProcessRequest.getConnectIds(); + if (connectIds == null || connectIds.isEmpty()) { + LOGGER.error("Request connectIds cannot be null or empty!"); + result.setMessage("Request connectIds cannot be null or empty!"); + result.setSuccess(false); + return result; + } + sessionRegistry.cancel(connectIds); + } catch (Exception e) { + LOGGER.error("Cancel Address Request error!", e); + throw new RuntimeException("Cancel Address Request error!", e); + } + + result.setSuccess(true); + + return result; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/ClientNodeConnectionHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/ClientNodeConnectionHandler.java new file mode 100644 index 000000000..6c0dab457 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/ClientNodeConnectionHandler.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: ServerConnectionLisener.java, v 0.1 2017-11-30 15:04 shangyu.wh Exp $ + */ +public class ClientNodeConnectionHandler extends AbstractServerHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("SESSION-CONNECT"); + + @Autowired + private Registry sessionRegistry; + + @Autowired + private DataStore sessionDataStore; + + @Autowired + private Interests sessionInterests; + + @Autowired + private Watchers sessionWatchers; + + @Autowired + private ExecutorManager executorManager; + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public void disconnected(Channel channel) throws RemotingException { + super.disconnected(channel); + fireCancelClient(channel); + } + + public void fireCancelClient(Channel channel) { + //avoid block connect ConnectionEventExecutor thread pool + executorManager.getDisconnectClientExecutor().execute(()->{ + + String connectId = NetUtil.toAddressString(channel.getRemoteAddress()); + if(checkCache(connectId)) { + List connectIds = new ArrayList<>(); + connectIds.add(connectId); + sessionRegistry.cancel(connectIds); + } + }); + } + + private boolean checkCache(String connectId) { + boolean checkSub = checkSub(connectId); + boolean checkPub = checkPub(connectId); + boolean checkWatcher = checkWatcher(connectId); + LOGGER.info("Client off checkCache connectId:{} result pub:{},sub:{},wat:{}", connectId, + checkPub, checkSub, checkWatcher); + return checkPub || checkSub || checkWatcher; + } + + private boolean checkPub(String connectId) { + Map pubMap = sessionDataStore.queryByConnectId(connectId); + return pubMap != null && !pubMap.isEmpty(); + } + + private boolean checkSub(String connectId) { + Map subMap = sessionInterests.queryByConnectId(connectId); + return subMap != null && !subMap.isEmpty(); + } + + private boolean checkWatcher(String connectId) { + Map subMap = sessionWatchers.queryByConnectId(connectId); + return subMap != null && !subMap.isEmpty(); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataChangeRequestHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataChangeRequestHandler.java new file mode 100644 index 000000000..bc70a50c9 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataChangeRequestHandler.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.sessionserver.DataChangeRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.DatumKey; +import com.alipay.sofa.registry.server.session.cache.Key; +import com.alipay.sofa.registry.server.session.cache.Key.KeyType; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.strategy.DataChangeRequestHandlerStrategy; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.Executor; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeRequestHandler.java, v 0.1 2017-12-12 15:09 shangyu.wh Exp $ + */ +public class DataChangeRequestHandler extends AbstractClientHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataChangeRequestHandler.class); + + private static final Logger EXCHANGE_LOGGER = LoggerFactory + .getLogger("SESSION-EXCHANGE"); + + /** + * store subscribers + */ + @Autowired + private Interests sessionInterests; + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private ExecutorManager executorManager; + + @Autowired + private CacheService sessionCacheService; + + @Autowired + private DataChangeRequestHandlerStrategy dataChangeRequestHandlerStrategy; + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.DATA; + } + + @Override + public Executor getExecutor() { + return executorManager.getDataChangeRequestExecutor(); + } + + @Override + public Object reply(Channel channel, Object message) { + + DataChangeRequest dataChangeRequest = (DataChangeRequest) message; + + dataChangeRequest.setDataCenter(dataChangeRequest.getDataCenter()); + dataChangeRequest.setDataInfoId(dataChangeRequest.getDataInfoId()); + + //update cache when change + sessionCacheService.invalidate(new Key(KeyType.OBJ, DatumKey.class.getName(), new DatumKey( + dataChangeRequest.getDataInfoId(), dataChangeRequest.getDataCenter()))); + + if (sessionServerConfig.isStopPushSwitch()) { + LOGGER.info("Stop Push data with switch on,dataChangeRequest: {}", dataChangeRequest); + return null; + } + try { + boolean result = sessionInterests.checkInterestVersions( + dataChangeRequest.getDataCenter(), dataChangeRequest.getDataInfoId(), + dataChangeRequest.getVersion()); + if (!result) { + return null; + } + + EXCHANGE_LOGGER.info( + "Data version has change,and will fetch to update!Request={},URL={}", + dataChangeRequest, channel.getRemoteAddress()); + + fireChangFetch(dataChangeRequest); + + } catch (Exception e) { + LOGGER.error("DataChange Request error!", e); + throw new RuntimeException("DataChangeRequest Request error!", e); + } + + return null; + } + + /** + * + * @param dataChangeRequest + */ + private void fireChangFetch(DataChangeRequest dataChangeRequest) { + dataChangeRequestHandlerStrategy.doFireChangFetch(dataChangeRequest); + } + + @Override + public Class interest() { + return DataChangeRequest.class; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataNodeConnectionHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataNodeConnectionHandler.java new file mode 100644 index 000000000..e5f29820a --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataNodeConnectionHandler.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.session.registry.SessionRegistry; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: ClientConnectionHandler.java, v 0.1 2017-12-08 20:17 shangyu.wh Exp $ + */ +public class DataNodeConnectionHandler extends AbstractClientHandler { + + private static final Logger taskLogger = LoggerFactory.getLogger(SessionRegistry.class, + "[Task]"); + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public void connected(Channel channel) throws RemotingException { + super.connected(channel); + fireRegisterProcessIdTask(new URL(channel.getRemoteAddress())); + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.DATA; + } + + private void fireRegisterProcessIdTask(URL dataURL) { + TaskEvent taskEvent = new TaskEvent(dataURL, TaskType.SESSION_REGISTER_DATA_TASK); + taskLogger.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataPushRequestHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataPushRequestHandler.java new file mode 100644 index 000000000..5d8e9c486 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/DataPushRequestHandler.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.sessionserver.DataPushRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * current for standard env temp publisher push + * + * @author shangyu.wh + * @version $Id: DataChangeRequestHandler.java, v 0.1 2017-12-12 15:09 shangyu.wh Exp $ + */ +public class DataPushRequestHandler extends AbstractClientHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(DataPushRequestHandler.class); + + private static final Logger TASK_LOGGER = LoggerFactory.getLogger( + DataPushRequestHandler.class, "[Task]"); + + private static final Logger EXCHANGE_LOGGER = LoggerFactory.getLogger("SESSION-EXCHANGE", + "[DataPushRequestHandler]"); + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.DATA; + } + + @Override + public Object reply(Channel channel, Object message) { + if (!(message instanceof DataPushRequest)) { + LOGGER.error("Request message type {} is not mach the require data type!", message + .getClass().getName()); + return null; + } + DataPushRequest dataPushRequest = (DataPushRequest) message; + EXCHANGE_LOGGER.info("request={}", dataPushRequest); + + try { + fireDataPushTask(dataPushRequest); + } catch (Exception e) { + LOGGER.error("DataPush Request error!", e); + throw new RuntimeException("DataPush Request error!", e); + } + + return null; + } + + private void fireDataPushTask(DataPushRequest dataPushRequest) { + //trigger fetch data for subscriber,and push to client node + TaskEvent taskEvent = new TaskEvent(dataPushRequest, TaskType.DATA_PUSH_TASK); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public Class interest() { + return DataPushRequest.class; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/MetaNodeConnectionHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/MetaNodeConnectionHandler.java new file mode 100644 index 000000000..c1ebd7f4a --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/MetaNodeConnectionHandler.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; + +/** + * + * @author shangyu.wh + * @version $Id: ClientConnectionHandler.java, v 0.1 2017-12-08 20:17 shangyu.wh Exp $ + */ +public class MetaNodeConnectionHandler extends AbstractClientHandler { + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.META; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NodeChangeResultHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NodeChangeResultHandler.java new file mode 100644 index 000000000..4847ac681 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NodeChangeResultHandler.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.metaserver.NodeChangeResult; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManagerFactory; + +/** + * + * @author shangyu.wh + * @version $Id: NodeChangeRequestHandler.java, v 0.1 2018-03-03 11:21 shangyu.wh Exp $ + */ +public class NodeChangeResultHandler extends AbstractClientHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(NodeChangeResultHandler.class); + + @Override + public Object reply(Channel channel, Object message) { + + if (!(message instanceof NodeChangeResult)) { + LOGGER.error("Request message type {} is not mach the require data type!", message + .getClass().getName()); + return null; + } + NodeChangeResult nodeChangeResult = (NodeChangeResult) message; + + NodeManager nodeManager = NodeManagerFactory.getNodeManager(nodeChangeResult.getNodeType()); + nodeManager.updateNodes(nodeChangeResult); + LOGGER.info("Update {} node list success!info:{}", nodeChangeResult.getNodeType(), + nodeChangeResult); + return null; + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.META; + } + + @Override + public void received(Channel channel, Object message) { + + } + + @Override + public Class interest() { + return NodeChangeResult.class; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NotifyProvideDataChangeHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NotifyProvideDataChangeHandler.java new file mode 100644 index 000000000..eb59882c1 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/NotifyProvideDataChangeHandler.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeRequestHandler.java, v 0.1 2017-12-12 15:09 shangyu.wh Exp $ + */ +public class NotifyProvideDataChangeHandler extends AbstractClientHandler { + + private static final Logger LOGGER = LoggerFactory + .getLogger(NotifyProvideDataChangeHandler.class); + + private static final Logger TASK_LOGGER = LoggerFactory.getLogger( + NotifyProvideDataChangeHandler.class, "[Task]"); + /** + * store watchers + */ + @Autowired + private Watchers sessionWatchers; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + protected NodeType getConnectNodeType() { + return NodeType.DATA; + } + + @Override + public Object reply(Channel channel, Object message) { + + NotifyProvideDataChange notifyProvideDataChange = (NotifyProvideDataChange) message; + + if (!ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID.equals(notifyProvideDataChange + .getDataInfoId())) { + boolean result = sessionWatchers.checkWatcherVersions( + notifyProvideDataChange.getDataInfoId(), notifyProvideDataChange.getVersion()); + if (!result) { + LOGGER + .info( + "Request message dataInfo {}, version {} not be interested or lower than current version!", + notifyProvideDataChange.getDataInfoId(), + notifyProvideDataChange.getVersion()); + return null; + } + + } + fireDataChangeFetchTask(notifyProvideDataChange); + return null; + } + + private void fireDataChangeFetchTask(NotifyProvideDataChange notifyProvideDataChange) { + + TaskEvent taskEvent = new TaskEvent(notifyProvideDataChange, + TaskType.PROVIDE_DATA_CHANGE_FETCH_TASK); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public Class interest() { + return NotifyProvideDataChange.class; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/PublisherHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/PublisherHandler.java new file mode 100644 index 000000000..82e04e37b --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/PublisherHandler.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.core.model.PublisherRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.strategy.PublisherHandlerStrategy; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.Executor; + +/** + * TODO + * + * @author shangyu.wh + * @version $Id: SessionHandler.java, v 0.1 2017-11-29 11:32 shangyu.wh Exp $ + */ +public class PublisherHandler extends AbstractServerHandler { + @Autowired + private ExecutorManager executorManager; + + @Autowired + private PublisherHandlerStrategy publisherHandlerStrategy; + + @Override + public Object reply(Channel channel, Object message) throws RemotingException { + + RegisterResponse result = new RegisterResponse(); + PublisherRegister publisherRegister = (PublisherRegister) message; + publisherHandlerStrategy.handlePublisherRegister(channel, publisherRegister, result); + return result; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return PublisherRegister.class; + } + + @Override + public Executor getExecutor() { + return executorManager.getAccessDataExecutor(); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SubscriberHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SubscriberHandler.java new file mode 100644 index 000000000..f02295f28 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SubscriberHandler.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.core.model.SubscriberRegister; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.strategy.SubscriberHandlerStrategy; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.concurrent.Executor; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberHandler.java, v 0.1 2017-11-30 15:01 shangyu.wh Exp $ + */ +public class SubscriberHandler extends AbstractServerHandler { + @Autowired + private ExecutorManager executorManager; + + @Autowired + private SubscriberHandlerStrategy subscriberHandlerStrategy; + + @Override + public Object reply(Channel channel, Object message) throws RemotingException { + RegisterResponse registerResponse = new RegisterResponse(); + SubscriberRegister subscriberRegister = (SubscriberRegister) message; + subscriberHandlerStrategy.handleSubscriberRegister(channel, subscriberRegister, + registerResponse); + return registerResponse; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return SubscriberRegister.class; + } + + @Override + public Executor getExecutor() { + return executorManager.getAccessDataExecutor(); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SyncConfigHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SyncConfigHandler.java new file mode 100644 index 000000000..c97e2608d --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/SyncConfigHandler.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.core.model.SyncConfigRequest; +import com.alipay.sofa.registry.core.model.SyncConfigResponse; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.server.session.strategy.SyncConfigHandlerStrategy; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author zhuoyu.sjw + * @version $Id: SyncConfigHandler.java, v 0.1 2018-03-14 23:15 zhuoyu.sjw Exp $$ + */ +public class SyncConfigHandler extends AbstractServerHandler { + @Autowired + private SyncConfigHandlerStrategy syncConfigHandlerStrategy; + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public InvokeType getInvokeType() { + return InvokeType.SYNC; + } + + @Override + public Object reply(Channel channel, Object message) throws RemotingException { + SyncConfigResponse response = new SyncConfigResponse(); + response.setSuccess(true); + syncConfigHandlerStrategy.handleSyncConfigResponse(response); + return response; + } + + @Override + public Class interest() { + return SyncConfigRequest.class; + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/WatcherHandler.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/WatcherHandler.java new file mode 100644 index 000000000..07fd647ab --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/remoting/handler/WatcherHandler.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.remoting.handler; + +import com.alipay.sofa.registry.core.model.ConfiguratorRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.strategy.WatcherHandlerStrategy; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberHandler.java, v 0.1 2017-11-30 15:01 shangyu.wh Exp $ + */ +public class WatcherHandler extends AbstractServerHandler { + @Autowired + private WatcherHandlerStrategy watcherHandlerStrategy; + + @Override + public Object reply(Channel channel, Object message) { + RegisterResponse result = new RegisterResponse(); + ConfiguratorRegister configuratorRegister = (ConfiguratorRegister) message; + watcherHandlerStrategy.handleConfiguratorRegister(channel, configuratorRegister, result); + return result; + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return ConfiguratorRegister.class; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/ClientsOpenResource.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/ClientsOpenResource.java new file mode 100644 index 000000000..f081f7f2b --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/ClientsOpenResource.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.resource; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.sessionserver.CancelAddressRequest; +import com.alipay.sofa.registry.server.session.registry.Registry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import java.util.List; + +/** + * The type Clients open resource. + * @author zhuoyu.sjw + * @version $Id : ClientsResource.java, v 0.1 2018-04-11 19:04 zhuoyu.sjw Exp $$ + */ +@Path("api/clients") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public class ClientsOpenResource { + + @Autowired + private Registry sessionRegistry; + + /** + * Client off common response. + * + * @param request the request + * @return the common response + */ + @POST + @Path("/off") + public CommonResponse clientOff(CancelAddressRequest request) { + + if (null == request) { + return CommonResponse.buildFailedResponse("Request can not be null."); + } + + if (CollectionUtils.isEmpty(request.getConnectIds())) { + return CommonResponse.buildFailedResponse("ConnectIds can not be null."); + } + + final List connectIds = request.getConnectIds(); + sessionRegistry.cancel(connectIds); + return CommonResponse.buildSuccessResponse(); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/HealthResource.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/HealthResource.java new file mode 100644 index 000000000..37afbd6c2 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/HealthResource.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.resource; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerBootstrap; +import com.alipay.sofa.registry.server.session.node.RaftClientManager; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author shangyu.wh + * @version $Id: PushSwitchResource.java, v 0.1 2018-10-29 16:51 shangyu.wh Exp $ + */ +@Path("health") +public class HealthResource { + + @Autowired + private RaftClientManager raftClientManager; + + @Autowired + private SessionServerBootstrap sessionServerBootstrap; + + @GET + @Path("check") + @Produces(MediaType.APPLICATION_JSON) + public CommonResponse checkHealth() { + + CommonResponse response; + + StringBuilder sb = new StringBuilder("SessionServerBoot "); + + boolean start = raftClientManager.getClientStart().get(); + boolean ret = start; + sb.append("RaftClientManager:").append(start); + + start = sessionServerBootstrap.getMetaStart().get(); + ret = ret && start; + sb.append(", MetaServerStart:").append(start); + + start = sessionServerBootstrap.getSchedulerStart().get(); + ret = ret && start; + sb.append(", SchedulerStart:").append(start); + + start = sessionServerBootstrap.getHttpStart().get(); + ret = ret && start; + sb.append(", HttpServerStart:").append(start); + + start = sessionServerBootstrap.getServerStart().get(); + ret = ret && start; + sb.append(", SessionServerStart:").append(start); + + start = sessionServerBootstrap.getDataStart().get(); + ret = ret && start; + sb.append(", ConnectDataServer:").append(start); + + if (ret) { + response = CommonResponse.buildSuccessResponse(sb.toString()); + } else { + response = CommonResponse.buildFailedResponse(sb.toString()); + } + + return response; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionDigestResource.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionDigestResource.java new file mode 100644 index 000000000..25148c948 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionDigestResource.java @@ -0,0 +1,193 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.resource; + +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.StoreData; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; + +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: SessionOpenResource.java, v 0.1 2018-03-21 11:06 shangyu.wh Exp $ + */ +@Path("digest") +public class SessionDigestResource { + + /** + * store subscribers + */ + @Autowired + private Interests sessionInterests; + + /** + * store watchers + */ + @Autowired + private Watchers sessionWatchers; + + /** + * store publishers + */ + @Autowired + private DataStore sessionDataStore; + + @Autowired + private SessionServerConfig sessionServerConfig; + + private final static String SUB = "SUB"; + + private final static String PUB = "PUB"; + + private final static String WAT = "WAT"; + + @GET + @Path("{type}/data/query") + @Produces(MediaType.APPLICATION_JSON) + public Map> getSessionDataByDataInfoId(@QueryParam("dataInfoId") String dataInfoId, + @PathParam("type") String type) { + Map> serverList = new HashMap<>(); + if (dataInfoId != null) { + Collection publishers = sessionDataStore + .getStoreDataByDataInfoId(dataInfoId); + Collection subscribers = sessionInterests.getInterests(dataInfoId); + Collection watchers = sessionWatchers.getWatchers(dataInfoId); + fillServerList(type, serverList, publishers, subscribers, watchers); + } + + return serverList; + } + + @POST + @Path("{type}/connect/query") + @Produces(MediaType.APPLICATION_JSON) + public Map> getSessionDataByConnectId(List connectIds, + final @PathParam("type") String type) { + Map> serverList = new HashMap<>(); + + if (connectIds != null) { + connectIds.forEach(connectId -> { + Map pubMap = sessionDataStore.queryByConnectId(connectId); + Map subMap = sessionInterests.queryByConnectId(connectId); + Map watcherMap = sessionWatchers.queryByConnectId(connectId); + + Collection publishers = + pubMap != null && !pubMap.isEmpty() ? pubMap.values() : new ArrayList<>(); + Collection subscribers = + subMap != null && !subMap.isEmpty() ? subMap.values() : new ArrayList<>(); + Collection watchers = + watcherMap != null && !watcherMap.isEmpty() ? watcherMap.values() : new ArrayList<>(); + fillServerList(type, serverList, publishers, subscribers, watchers); + }); + } + + return serverList; + } + + @GET + @Path("/data/count") + @Produces(MediaType.APPLICATION_JSON) + public String getSessionDataCount() { + long countSub = sessionInterests.count(); + long countPub = sessionDataStore.count(); + long countSubW = sessionWatchers.count(); + + return String.format("Subscriber count: %s, Publisher count: %s, Watcher count: %s", + countSub, countPub, countSubW); + } + + /** + * return true mean push switch on + */ + @GET + @Path("pushSwitch") + @Produces(MediaType.APPLICATION_JSON) + public Map getPushSwitch() { + Map resultMap = new HashMap<>(1); + resultMap.put("pushSwitch", !sessionServerConfig.isStopPushSwitch() ? "open" : "closed"); + return resultMap; + } + + private void fillServerList(String type, + Map> serverList, + Collection publishers, + Collection subscribers, Collection watchers) { + if (type != null && !type.isEmpty()) { + String inputType = type.toUpperCase(); + + switch (inputType) { + case PUB: + if (!CollectionUtils.isEmpty(publishers)) { + serverList.put(PUB, publishers); + } + break; + case SUB: + if (!CollectionUtils.isEmpty(subscribers)) { + serverList.put(SUB, subscribers); + } + break; + case WAT: + if (!CollectionUtils.isEmpty(watchers)) { + serverList.put(WAT, watchers); + } + break; + default: + if (!CollectionUtils.isEmpty(publishers)) { + serverList.put(PUB, publishers); + } + if (!CollectionUtils.isEmpty(subscribers)) { + serverList.put(SUB, subscribers); + } + if (!CollectionUtils.isEmpty(watchers)) { + serverList.put(WAT, watchers); + } + break; + } + + } else { + if (publishers != null) { + serverList.put(PUB, publishers); + } + if (subscribers != null) { + serverList.put(SUB, subscribers); + } + if (watchers != null) { + serverList.put(WAT, watchers); + } + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionOpenResource.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionOpenResource.java new file mode 100644 index 000000000..f0ce93c22 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/resource/SessionOpenResource.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.resource; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManagerFactory; +import com.alipay.sofa.registry.server.session.node.SessionNodeManager; +import com.google.common.base.Joiner; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: SessionOpenResource.java, v 0.1 2018-03-21 11:06 shangyu.wh Exp $ + */ +@Path("api/servers") +public class SessionOpenResource { + + @Autowired + private SessionServerConfig sessionServerConfig; + + @GET + @Path("query.json") + @Produces(MediaType.APPLICATION_JSON) + public List getSessionServerListJson(@QueryParam("zone") String zone) { + + List serverList = new ArrayList<>(); + NodeManager nodeManager = NodeManagerFactory.getNodeManager(NodeType.SESSION); + + if (StringUtils.isEmpty(zone)) { + zone = sessionServerConfig.getSessionServerRegion(); + } + + if (StringUtils.isNotBlank(zone)) { + zone = zone.toUpperCase(); + } + + if (nodeManager instanceof SessionNodeManager) { + SessionNodeManager sessionNodeManager = (SessionNodeManager) nodeManager; + serverList = sessionNodeManager.getZoneServerList(zone); + + serverList = serverList.stream() + .map(server -> server + ":" + sessionServerConfig.getServerPort()) + .collect(Collectors.toList()); + } + + return serverList; + } + + @GET + @Path("query") + @Produces(MediaType.TEXT_PLAIN) + public String getSessionServerList(@QueryParam("zone") String zone) { + return Joiner.on(";").join(getSessionServerListJson(zone)); + } + + @GET + @Path("alive") + public String checkAlive() { + return "OK"; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/ExecutorManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/ExecutorManager.java new file mode 100644 index 000000000..cd11a6ae6 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/ExecutorManager.java @@ -0,0 +1,293 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler; + +import com.alipay.sofa.registry.metrics.TaskMetrics; +import com.alipay.sofa.registry.remoting.exchange.NodeExchanger; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.task.scheduler.TimedSupervisorTask; +import com.alipay.sofa.registry.util.NamedThreadFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ExecutorManager.java, v 0.1 2017-11-28 14:41 shangyu.wh Exp $ + */ +public class ExecutorManager { + + private final ScheduledExecutorService scheduler; + + private final ThreadPoolExecutor fetchDataExecutor; + private final ThreadPoolExecutor standaloneCheckVersionExecutor; + private final ThreadPoolExecutor renNewDataExecutor; + private final ThreadPoolExecutor getSessionNodeExecutor; + private final ThreadPoolExecutor connectMetaExecutor; + private final ThreadPoolExecutor connectDataExecutor; + + private final ExecutorService checkPushExecutor; + private final ExecutorService pushTaskClosureExecutor; + private final ThreadPoolExecutor accessDataExecutor; + private final ThreadPoolExecutor dataChangeRequestExecutor; + private final ThreadPoolExecutor pushTaskExecutor; + private final ThreadPoolExecutor disconnectClientExecutor; + + private SessionServerConfig sessionServerConfig; + + @Autowired + private Registry sessionRegistry; + + @Autowired + private NodeManager sessionNodeManager; + + @Autowired + private NodeManager dataNodeManager; + + @Autowired + private NodeManager metaNodeManager; + + @Autowired + protected NodeExchanger metaNodeExchanger; + + @Autowired + private NodeExchanger dataNodeExchanger; + + private Map reportExecutors = new HashMap<>(); + + private static final String PUSH_TASK_EXECUTOR = "PushTaskExecutor"; + + private static final String ACCESS_DATA_EXECUTOR = "AccessDataExecutor"; + + private static final String DATA_CHANGE_REQUEST_EXECUTOR = "DataChangeRequestExecutor"; + + private static final String USER_DATA_ELEMENT_PUSH_TASK_CHECK_EXECUTOR = "UserDataElementPushCheckExecutor"; + + private static final String PUSH_TASK_CLOSURE_CHECK_EXECUTOR = "PushTaskClosureCheckExecutor"; + + private static final String DISCONNECT_CLIENT_EXECUTOR = "DisconnectClientExecutor"; + + public ExecutorManager(SessionServerConfig sessionServerConfig) { + + this.sessionServerConfig = sessionServerConfig; + + scheduler = new ScheduledThreadPoolExecutor(7, new NamedThreadFactory("SessionScheduler")); + + fetchDataExecutor = new ThreadPoolExecutor(1, 2/*CONFIG*/, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SessionScheduler-fetchData")); + + renNewDataExecutor = new ThreadPoolExecutor(1, 2/*CONFIG*/, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SessionScheduler-reNewData")); + + getSessionNodeExecutor = new ThreadPoolExecutor(1, 2/*CONFIG*/, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SessionScheduler-getSessionNode")); + + standaloneCheckVersionExecutor = new ThreadPoolExecutor(1, 2/*CONFIG*/, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SessionScheduler-standaloneCheckVersion")); + + connectMetaExecutor = new ThreadPoolExecutor(1, 2/*CONFIG*/, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SessionScheduler-connectMetaServer")); + + connectDataExecutor = new ThreadPoolExecutor(1, 2/*CONFIG*/, 0, TimeUnit.SECONDS, + new SynchronousQueue<>(), new NamedThreadFactory("SessionScheduler-connectDataServer")); + + accessDataExecutor = reportExecutors + .computeIfAbsent(ACCESS_DATA_EXECUTOR, k -> new SessionThreadPoolExecutor(ACCESS_DATA_EXECUTOR, + sessionServerConfig.getAccessDataExecutorMinPoolSize(), + sessionServerConfig.getAccessDataExecutorMaxPoolSize(), + sessionServerConfig.getAccessDataExecutorKeepAliveTime(), + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(sessionServerConfig.getAccessDataExecutorQueueSize()), + new NamedThreadFactory("AccessData-executor", true))); + + pushTaskExecutor = reportExecutors.computeIfAbsent(PUSH_TASK_EXECUTOR, + k -> new ThreadPoolExecutor(sessionServerConfig.getPushTaskExecutorMinPoolSize(), + sessionServerConfig.getPushTaskExecutorMaxPoolSize(), + sessionServerConfig.getPushTaskExecutorKeepAliveTime(), TimeUnit.SECONDS, + new LinkedBlockingQueue<>(sessionServerConfig.getPushTaskExecutorQueueSize()), + new NamedThreadFactory("PushTask-executor", true))); + + TaskMetrics.getInstance().registerThreadExecutor(PUSH_TASK_EXECUTOR, pushTaskExecutor); + + dataChangeRequestExecutor = reportExecutors.computeIfAbsent(DATA_CHANGE_REQUEST_EXECUTOR, + k -> new SessionThreadPoolExecutor(DATA_CHANGE_REQUEST_EXECUTOR, + sessionServerConfig.getDataChangeExecutorMinPoolSize(), + sessionServerConfig.getDataChangeExecutorMaxPoolSize(), + sessionServerConfig.getDataChangeExecutorKeepAliveTime(), + TimeUnit.SECONDS, + new ArrayBlockingQueue<>(sessionServerConfig.getDataChangeExecutorQueueSize()), + new NamedThreadFactory( + "DataChangeRequestHandler-executor", true))); + + checkPushExecutor = reportExecutors + .computeIfAbsent(USER_DATA_ELEMENT_PUSH_TASK_CHECK_EXECUTOR, k -> new SessionThreadPoolExecutor( + USER_DATA_ELEMENT_PUSH_TASK_CHECK_EXECUTOR, 100, 600, 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(100000), + new NamedThreadFactory("UserDataElementPushCheck-executor", true))); + + pushTaskClosureExecutor = reportExecutors + .computeIfAbsent(PUSH_TASK_CLOSURE_CHECK_EXECUTOR, k -> new SessionThreadPoolExecutor( + PUSH_TASK_CLOSURE_CHECK_EXECUTOR, 80, 400, 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(10000), + new NamedThreadFactory("PushTaskClosureCheck", true))); + + disconnectClientExecutor = reportExecutors.computeIfAbsent(DISCONNECT_CLIENT_EXECUTOR,k->new SessionThreadPoolExecutor( + DISCONNECT_CLIENT_EXECUTOR, sessionServerConfig.getDisconnectClientExecutorMinPoolSize(), + sessionServerConfig.getDisconnectClientExecutorMaxPoolSize(), 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(sessionServerConfig.getDisconnectClientExecutorQueueSize()), + new NamedThreadFactory("DisconnectClientExecutor", true))); + + } + + public void startScheduler() { + scheduler.schedule( + new TimedSupervisorTask("FetchData", scheduler, fetchDataExecutor, + sessionServerConfig.getSchedulerFetchDataTimeout(), TimeUnit.MINUTES, + sessionServerConfig.getSchedulerFetchDataExpBackOffBound(), + () -> sessionRegistry.fetchChangData()), + sessionServerConfig.getSchedulerFetchDataFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("ReNewData", scheduler, renNewDataExecutor, + sessionServerConfig.getSchedulerHeartbeatTimeout(), TimeUnit.SECONDS, + sessionServerConfig.getSchedulerHeartbeatExpBackOffBound(), + () -> sessionNodeManager.reNewNode()), + sessionServerConfig.getSchedulerHeartbeatFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("GetSessionNode", scheduler, getSessionNodeExecutor, + sessionServerConfig.getSchedulerGetSessionNodeTimeout(), TimeUnit.SECONDS, + sessionServerConfig.getSchedulerGetSessionNodeExpBackOffBound(), + () -> { + sessionNodeManager.getAllDataCenterNodes(); + dataNodeManager.getAllDataCenterNodes(); + metaNodeManager.getAllDataCenterNodes(); + }), + sessionServerConfig.getSchedulerGetSessionNodeFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("ConnectMetaServer", scheduler, connectMetaExecutor, + sessionServerConfig.getSchedulerConnectMetaTimeout(), TimeUnit.SECONDS, + sessionServerConfig.getSchedulerConnectMetaExpBackOffBound(), + () -> metaNodeExchanger.connectServer()), + sessionServerConfig.getSchedulerConnectMetaFirstDelay(), TimeUnit.SECONDS); + + scheduler.schedule( + new TimedSupervisorTask("ConnectDataServer", scheduler, connectDataExecutor, + sessionServerConfig.getSchedulerConnectDataTimeout(), TimeUnit.SECONDS, + sessionServerConfig.getSchedulerConnectDataExpBackOffBound(), + () -> dataNodeExchanger.connectServer()), + sessionServerConfig.getSchedulerConnectDataFirstDelay(), TimeUnit.SECONDS); + } + + public void stopScheduler() { + if (scheduler != null && !scheduler.isShutdown()) { + scheduler.shutdown(); + } + + if (standaloneCheckVersionExecutor != null && !standaloneCheckVersionExecutor.isShutdown()) { + standaloneCheckVersionExecutor.shutdown(); + } + + if (renNewDataExecutor != null && !renNewDataExecutor.isShutdown()) { + renNewDataExecutor.shutdown(); + } + if (fetchDataExecutor != null && !fetchDataExecutor.isShutdown()) { + fetchDataExecutor.shutdown(); + } + + if (getSessionNodeExecutor != null && !getSessionNodeExecutor.isShutdown()) { + getSessionNodeExecutor.shutdown(); + } + + if (connectMetaExecutor != null && !connectMetaExecutor.isShutdown()) { + connectMetaExecutor.shutdown(); + } + + if (connectDataExecutor != null && !connectDataExecutor.isShutdown()) { + connectDataExecutor.shutdown(); + } + + if (accessDataExecutor != null && !accessDataExecutor.isShutdown()) { + accessDataExecutor.shutdown(); + } + + if (pushTaskExecutor != null && !pushTaskExecutor.isShutdown()) { + pushTaskExecutor.shutdown(); + } + + if (checkPushExecutor != null && !checkPushExecutor.isShutdown()) { + checkPushExecutor.shutdown(); + } + + if (dataChangeRequestExecutor != null && !dataChangeRequestExecutor.isShutdown()) { + dataChangeRequestExecutor.shutdown(); + } + + if (pushTaskClosureExecutor != null && !pushTaskClosureExecutor.isShutdown()) { + pushTaskClosureExecutor.shutdown(); + } + + if (disconnectClientExecutor != null && !disconnectClientExecutor.isShutdown()) { + disconnectClientExecutor.shutdown(); + } + } + + public Map getReportExecutors() { + return reportExecutors; + } + + public ThreadPoolExecutor getAccessDataExecutor() { + return accessDataExecutor; + } + + public ThreadPoolExecutor getPushTaskExecutor() { + return pushTaskExecutor; + } + + public ExecutorService getCheckPushExecutor() { + return checkPushExecutor; + } + + public ThreadPoolExecutor getDataChangeRequestExecutor() { + return dataChangeRequestExecutor; + } + + public ExecutorService getPushTaskClosureExecutor() { + return pushTaskClosureExecutor; + } + + public ThreadPoolExecutor getDisconnectClientExecutor() { + return disconnectClientExecutor; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/SessionThreadPoolExecutor.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/SessionThreadPoolExecutor.java new file mode 100644 index 000000000..18652a22c --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/SessionThreadPoolExecutor.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.metrics.TaskMetrics; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: ThreadPoolExecutorSession.java, v 0.1 2018-10-11 19:07 shangyu.wh Exp $ + */ +public class SessionThreadPoolExecutor extends ThreadPoolExecutor { + + private static final Logger LOGGER = LoggerFactory.getLogger(SessionThreadPoolExecutor.class); + + private String executorName; + + public SessionThreadPoolExecutor(String executorName, int corePoolSize, int maximumPoolSize, + long keepAliveTime, TimeUnit unit, + BlockingQueue workQueue, ThreadFactory threadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); + this.executorName = executorName; + registerTaskMetrics(); + } + + private void registerTaskMetrics() { + + TaskMetrics.getInstance().registerThreadExecutor(executorName, this); + } + + @Override + public String toString() { + + return (new StringBuilder(executorName).append(" ").append(super.toString())).toString(); + } + + @Override + public void execute(Runnable command) { + + try { + super.execute(command); + } catch (Exception e) { + if (e instanceof RejectedExecutionException) { + LOGGER.error("Processor session executor {} Rejected Execution!command {}", this, + command.getClass(), e); + } + throw e; + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/AbstractSessionTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/AbstractSessionTask.java new file mode 100644 index 000000000..3135c1461 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/AbstractSessionTask.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.task.Retryable; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractSessionTask.java, v 0.1 2018-01-15 14:35 shangyu.wh Exp $ + */ +public abstract class AbstractSessionTask implements SessionTask, Retryable { + + private final static Logger LOGGER = LoggerFactory.getLogger(AbstractSessionTask.class, + "[Task]"); + + protected volatile String taskId; + + private AtomicInteger execCount = new AtomicInteger(1); + + @Override + public synchronized String getTaskId() { + if (taskId == null) { + taskId = UUID.randomUUID().toString(); + } + + return taskId; + } + + protected boolean checkRetryTimes(int configTimes) { + if (configTimes > 0) { + if (execCount.incrementAndGet() > configTimes) { + LOGGER.info(" info:{} retry times more than {}", this, configTimes); + return false; + } else { + return true; + } + } + return false; + } + + @Override + public long getExpiryTime() { + return -1; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/CancelDataTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/CancelDataTask.java new file mode 100644 index 000000000..df380c58b --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/CancelDataTask.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: CancelDataTask.java, v 0.1 2017-12-27 12:15 shangyu.wh Exp $ + */ +public class CancelDataTask extends AbstractSessionTask { + /** + * store subscribers + */ + private final Interests sessionInterests; + /** + * store publishers + */ + private final DataStore sessionDataStore; + + private final Watchers sessionWatchers; + /** + * transfer data to DataNode + */ + private final DataNodeService dataNodeService; + private final SessionServerConfig sessionServerConfig; + private List connectIds; + + public CancelDataTask(Interests sessionInterests, DataStore sessionDataStore, + Watchers sessionWatchers, DataNodeService dataNodeService, + SessionServerConfig sessionServerConfig) { + this.sessionInterests = sessionInterests; + this.sessionDataStore = sessionDataStore; + this.sessionWatchers = sessionWatchers; + this.dataNodeService = dataNodeService; + this.sessionServerConfig = sessionServerConfig; + } + + @Override + public void execute() { + if (connectIds.isEmpty()) { + throw new IllegalArgumentException("Input clientOff connectIds error!"); + } + + //remove local first,data node send error depend on other task check + List connectIdsPub = new ArrayList<>(); + for (String connectId : connectIds) { + + if (sessionDataStore.deleteByConnectId(connectId)) { + connectIdsPub.add(connectId); + } + sessionInterests.deleteByConnectId(connectId); + + sessionWatchers.deleteByConnectId(connectId); + } + + dataNodeService.clientOff(connectIdsPub); + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (obj instanceof List) { + this.connectIds = (List) obj; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + + @Override + public String toString() { + return "CANCEL_DATA_TASK{" + "taskId='" + getTaskId() + '\'' + ", connectIds=" + connectIds + + ", retry='" + sessionServerConfig.getCancelDataTaskRetryTimes() + '\'' + '}'; + } + + @Override + public boolean checkRetryTimes() { + //dataNodeService.clientOff will be retry all the failed + return false; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/Constant.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/Constant.java new file mode 100644 index 000000000..b801489cf --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/Constant.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +/** + * + * @author shangyu.wh + * @version $Id: Constant.java, v 0.1 2018-08-17 17:07 shangyu.wh Exp $ + */ +public class Constant { + + public final static String PUSH_CLIENT_SUBSCRIBERS = "PUSH_CLIENT_SUBSCRIBERS"; + + public final static String PUSH_CLIENT_DATUM = "PUSH_CLIENT_DATUM"; + + public final static String PUSH_CLIENT_URL = "PUSH_CLIENT_URL"; +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchCloudTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchCloudTask.java new file mode 100644 index 000000000..d6a423adc --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchCloudTask.java @@ -0,0 +1,306 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.Node.NodeType; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.BaseInfo.ClientVersion; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.DatumKey; +import com.alipay.sofa.registry.server.session.cache.Key; +import com.alipay.sofa.registry.server.session.cache.Key.KeyType; +import com.alipay.sofa.registry.server.session.cache.Value; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManagerFactory; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.ReSubscribers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeFetchCloudTask.java, v 0.1 2018-03-16 15:28 shangyu.wh Exp $ + */ +public class DataChangeFetchCloudTask extends AbstractSessionTask { + + private final static Logger LOGGER = LoggerFactory + .getLogger(DataChangeFetchCloudTask.class); + + private static final Logger taskLogger = LoggerFactory.getLogger( + DataChangeFetchCloudTask.class, "[Task]"); + + private final SessionServerConfig sessionServerConfig; + + private Interests sessionInterests; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + private final TaskListenerManager taskListenerManager; + + private final ExecutorManager executorManager; + + private String fetchDataInfoId; + + private final CacheService sessionCacheService; + + public DataChangeFetchCloudTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + Interests sessionInterests, ExecutorManager executorManager, + CacheService sessionCacheService) { + this.sessionServerConfig = sessionServerConfig; + this.taskListenerManager = taskListenerManager; + this.sessionInterests = sessionInterests; + this.executorManager = executorManager; + this.sessionCacheService = sessionCacheService; + } + + @Override + public long getExpiryTime() { + return -1; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof String)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.fetchDataInfoId = (String) obj; + } + + @Override + public void execute() { + + Map datumMap = getDatumsCache(); + + if (datumMap != null && !datumMap.isEmpty()) { + + PushTaskClosure pushTaskClosure = getTaskClosure(datumMap); + + for (ScopeEnum scopeEnum : ScopeEnum.values()) { + Map> map = getCache(fetchDataInfoId, + scopeEnum); + if (map != null && !map.isEmpty()) { + for (Entry> entry : map.entrySet()) { + Map subscriberMap = entry.getValue(); + if (subscriberMap != null && !subscriberMap.isEmpty()) { + List subscriberRegisterIdList = new ArrayList<>( + subscriberMap.keySet()); + + //select one row decide common info + Subscriber subscriber = subscriberMap.values().iterator().next(); + + //remove stopPush subscriber avoid push duplicate + evictReSubscribers(subscriberMap.values()); + + fireReceivedDataMultiPushTask(datumMap, subscriberRegisterIdList, + scopeEnum, subscriber, subscriberMap, pushTaskClosure); + } + } + } + } + + pushTaskClosure.start(); + } else { + LOGGER.error("Get publisher data error,which dataInfoId:{}", fetchDataInfoId); + } + } + + public PushTaskClosure getTaskClosure(Map datumMap) { + PushTaskClosure pushTaskClosure = new PushTaskClosure(executorManager.getPushTaskClosureExecutor()); + pushTaskClosure.setTaskClosure((status, task) -> { + if (status == ProcessingResult.Success) { + if (sessionServerConfig.isStopPushSwitch()) { + LOGGER.info("Stop Push switch on,dataInfoId {} version can not be update!", fetchDataInfoId); + return; + } + datumMap.forEach((dataCenter, datum) -> { + String dataInfoId = fetchDataInfoId; + Long version = datum.getVersion(); + boolean result = sessionInterests.checkAndUpdateInterestVersions(dataCenter, dataInfoId, version); + if (result) { + LOGGER.info("Push all tasks success,dataCenter:{} dataInfoId:{} version:{} update!", dataCenter, + dataInfoId, version); + } else { + LOGGER.info( + "Push all tasks success,but dataCenter:{} dataInfoId:{} version:{} need not update!", + dataCenter, + dataInfoId, version); + } + }); + } else { + LOGGER.warn("Push tasks found error,subscribers version can not be update!dataInfoId={}", + fetchDataInfoId); + } + }); + return pushTaskClosure; + } + + private void evictReSubscribers(Collection subscribersPush) { + if (this.sessionInterests instanceof ReSubscribers) { + ReSubscribers reSubscribers = (ReSubscribers) sessionInterests; + subscribersPush.forEach(reSubscribers::deleteReSubscriber); + } + } + + private Map> getCache(String dataInfoId, + ScopeEnum scopeEnum) { + + return sessionInterests.querySubscriberIndex(dataInfoId, scopeEnum); + } + + private Map getDatumsCache() { + + Map map = new HashMap<>(); + NodeManager nodeManager = NodeManagerFactory.getNodeManager(NodeType.META); + Collection dataCenters = nodeManager.getDataCenters(); + if (dataCenters != null) { + Collection keys = dataCenters.stream(). + map(dataCenter -> new Key(KeyType.OBJ, DatumKey.class.getName(), + new DatumKey(fetchDataInfoId, dataCenter))). + collect(Collectors.toList()); + + Map values = sessionCacheService.getValues(keys); + + if (values != null) { + values.forEach((key, value) -> { + if (value != null && value.getPayload() != null) { + map.put(((DatumKey) key.getEntityType()).getDataCenter(), (Datum) value.getPayload()); + } + }); + } + + } + return map; + } + + private void fireReceivedDataMultiPushTask(Map datums, + List subscriberRegisterIdList, + ScopeEnum scopeEnum, Subscriber subscriber, + Map subscriberMap, + PushTaskClosure pushTaskClosure) { + boolean isOldVersion = !ClientVersion.StoreData.equals(subscriber.getClientVersion()); + if (!isOldVersion) { + fireReceiveDataPushTask(datums, subscriberRegisterIdList, scopeEnum, subscriber, + subscriberMap, pushTaskClosure); + } else { + if (subscriber.getScope() == ScopeEnum.zone) { + fireUserDataElementPushTask(ReceivedDataConverter.getMergeDatum(datums), + subscriber, subscriberMap, pushTaskClosure); + } else { + fireUserDataElementMultiPushTask(ReceivedDataConverter.getMergeDatum(datums), + subscriber, subscriberMap, pushTaskClosure); + } + } + } + + private void fireReceiveDataPushTask(Map datums, + List subscriberRegisterIdList, + ScopeEnum scopeEnum, Subscriber subscriber, + Map subscriberMap, + PushTaskClosure pushTaskClosure) { + Collection subscribers = new ArrayList<>(subscriberMap.values()); + ReceivedData receivedData = ReceivedDataConverter.getReceivedDataMulti(datums, scopeEnum, + subscriberRegisterIdList, subscriber); + + //trigger push to client node + Map parameter = new HashMap<>(); + parameter.put(receivedData, subscriber.getSourceAddress()); + TaskEvent taskEvent = new TaskEvent(parameter, TaskType.RECEIVED_DATA_MULTI_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskLogger.info("send {} taskURL:{},taskScope:{}", taskEvent.getTaskType(), + subscriber.getSourceAddress(), scopeEnum); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataElementPushTask(Datum datum, Subscriber subscriber, + Map subscriberMap, + PushTaskClosure pushTaskClosure) { + + Collection subscribers = new ArrayList<>(subscriberMap.values()); + + TaskEvent taskEvent = new TaskEvent(TaskType.USER_DATA_ELEMENT_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, subscriber.getSourceAddress()); + + int size = datum != null && datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), subscriber.getSourceAddress(), datum.getDataInfoId(), + datum.getDataCenter(), size, subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataElementMultiPushTask(Datum datum, Subscriber subscriber, + Map subscriberMap, + PushTaskClosure pushTaskClosure) { + Collection subscribers = new ArrayList<>(subscriberMap.values()); + + TaskEvent taskEvent = new TaskEvent(TaskType.USER_DATA_ELEMENT_MULTI_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, subscriber.getSourceAddress()); + + int size = datum != null && datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), subscriber.getSourceAddress(), datum.getDataInfoId(), + datum.getDataCenter(), size, subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getDataChangeFetchTaskRetryTimes()); + } + + @Override + public String toString() { + return "DATA_CHANGE_FETCH_CLOUD_TASK{" + "taskId='" + getTaskId() + '\'' + + ", fetchDataInfoId=" + fetchDataInfoId + ", expiryTime='" + getExpiryTime() + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchTask.java new file mode 100644 index 000000000..3757a3117 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataChangeFetchTask.java @@ -0,0 +1,341 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.sessionserver.DataChangeRequest; +import com.alipay.sofa.registry.common.model.store.BaseInfo.ClientVersion; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.DatumKey; +import com.alipay.sofa.registry.server.session.cache.Key; +import com.alipay.sofa.registry.server.session.cache.Key.KeyType; +import com.alipay.sofa.registry.server.session.cache.Value; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.ReSubscribers; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Predicate; + +/** + * + * @author shangyu.wh + * @version $Id: DataChangeFetchTask.java, v 0.1 2017-12-13 12:25 shangyu.wh Exp $ + */ +public class DataChangeFetchTask extends AbstractSessionTask { + + private final static Logger LOGGER = LoggerFactory + .getLogger(DataChangeFetchTask.class); + + private static final Logger taskLogger = LoggerFactory.getLogger( + DataChangeFetchTask.class, "[Task]"); + + private final SessionServerConfig sessionServerConfig; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + private final TaskListenerManager taskListenerManager; + + private final ExecutorManager executorManager; + + private DataChangeRequest dataChangeRequest; + + private final Interests sessionInterests; + + private final CacheService sessionCacheService; + + public DataChangeFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + ExecutorManager executorManager, Interests sessionInterests, + CacheService sessionCacheService) { + this.sessionServerConfig = sessionServerConfig; + this.taskListenerManager = taskListenerManager; + this.executorManager = executorManager; + this.sessionInterests = sessionInterests; + this.sessionCacheService = sessionCacheService; + } + + @Override + public void execute() { + + String localDataCenterID = sessionServerConfig.getSessionServerDataCenter(); + + boolean ifLocalDataCenter = localDataCenterID.equals(dataChangeRequest.getDataCenter()); + + Datum datum = getDatumCache(); + + if (datum != null) { + PushTaskClosure pushTaskClosure = getTaskClosure(); + + for (ScopeEnum scopeEnum : ScopeEnum.values()) { + Map> map = getCache(scopeEnum); + if (map != null && !map.isEmpty()) { + for (Entry> entry : map.entrySet()) { + Map subscriberMap = entry.getValue(); + if (subscriberMap != null && !subscriberMap.isEmpty()) { + + //check subscriber push version + Collection subscribersSend = subscribersVersionCheck(subscriberMap + .values()); + if (subscribersSend.isEmpty()) { + continue; + } + + //remove stopPush subscriber avoid push duplicate + evictReSubscribers(subscribersSend); + + List subscriberRegisterIdList = new ArrayList<>( + subscriberMap.keySet()); + + Subscriber subscriber = subscriberMap.values().iterator().next(); + boolean isOldVersion = !ClientVersion.StoreData.equals(subscriber + .getClientVersion()); + + switch (scopeEnum) { + case zone: + if (ifLocalDataCenter) { + if (isOldVersion) { + fireUserDataElementPushTask(entry.getKey(), datum, + subscribersSend, pushTaskClosure); + } else { + fireReceivedDataMultiPushTask(datum, + subscriberRegisterIdList, subscribersSend, + ScopeEnum.zone, subscriber, pushTaskClosure); + } + } + break; + case dataCenter: + if (ifLocalDataCenter) { + if (isOldVersion) { + fireUserDataElementMultiPushTask(entry.getKey(), datum, + subscribersSend, pushTaskClosure); + } else { + fireReceivedDataMultiPushTask(datum, + subscriberRegisterIdList, subscribersSend, + scopeEnum, subscriber, pushTaskClosure); + } + } + break; + case global: + fireReceivedDataMultiPushTask(datum, subscriberRegisterIdList, + subscribersSend, scopeEnum, subscriber, pushTaskClosure); + break; + default: + LOGGER.warn("unknown scope, {}", subscriber); + } + } + } + } + } + + pushTaskClosure.start(); + + } else { + LOGGER.error("Get publisher data error,which dataInfoId:" + + dataChangeRequest.getDataInfoId() + " on dataCenter:" + + dataChangeRequest.getDataCenter()); + } + } + + private Collection subscribersVersionCheck(Collection subscribers) { + Collection subscribersSend = new ArrayList<>(); + for (Subscriber subscriber : subscribers) { + if (subscriber.checkVersion(dataChangeRequest.getDataCenter(), + dataChangeRequest.getVersion())) { + subscribersSend.add(subscriber); + } + } + return subscribersSend; + } + + public PushTaskClosure getTaskClosure() { + //this for all this dataInfoId push result get and call back to change version + PushTaskClosure pushTaskClosure = new PushTaskClosure(executorManager.getPushTaskClosureExecutor()); + pushTaskClosure.setTaskClosure((status, task) -> { + String dataCenter = dataChangeRequest.getDataCenter(); + String dataInfoId = dataChangeRequest.getDataInfoId(); + Long version = dataChangeRequest.getVersion(); + if (status == ProcessingResult.Success) { + + if (sessionServerConfig.isStopPushSwitch()) { + LOGGER.info("Stop Push switch on,dataCenter {} dataInfoId {} version {} can not be update!", + dataCenter, dataInfoId, version); + return; + } + boolean result = sessionInterests.checkAndUpdateInterestVersions(dataCenter, dataInfoId, version); + if (result) { + LOGGER.info("Push all tasks success,dataCenter:{} dataInfoId:{} version:{} update!", dataCenter, + dataInfoId, version); + } else { + LOGGER.info("Push all tasks success,but dataCenter:{} dataInfoId:{} version:{} need not update!", + dataCenter, + dataInfoId, version); + } + } else { + LOGGER.warn( + "Push tasks found error,subscribers version can not be update!dataCenter:{} dataInfoId:{} version:{}", + dataCenter, dataInfoId, version); + } + }); + return pushTaskClosure; + } + + private void evictReSubscribers(Collection subscribersPush) { + if (this.sessionInterests instanceof ReSubscribers) { + ReSubscribers reSubscribers = (ReSubscribers) sessionInterests; + subscribersPush.forEach(reSubscribers::deleteReSubscriber); + } + } + + private void fireReceivedDataMultiPushTask(Datum datum, List subscriberRegisterIdList, + Collection subscribers, + ScopeEnum scopeEnum, Subscriber subscriber, + PushTaskClosure pushTaskClosure) { + String dataId = datum.getDataId(); + Predicate zonePredicate = (zone) -> { + if (!sessionServerConfig.getSessionServerRegion().equals(zone)) { + if (ScopeEnum.zone == scopeEnum) { + // zone scope subscribe only return zone list + return true; + + } else if (ScopeEnum.dataCenter == scopeEnum) { + // disable zone config + return sessionServerConfig.isInvalidForeverZone(zone) + && !sessionServerConfig.isInvalidIgnored(dataId); + } + } + return false; + }; + ReceivedData receivedData = ReceivedDataConverter.getReceivedDataMulti(datum, scopeEnum, + subscriberRegisterIdList, sessionServerConfig.getSessionServerRegion(), zonePredicate); + + //trigger push to client node + Map parameter = new HashMap<>(); + parameter.put(receivedData, subscriber.getSourceAddress()); + TaskEvent taskEvent = new TaskEvent(parameter, TaskType.RECEIVED_DATA_MULTI_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskLogger.info("send {} taskURL:{},taskScope:{}", taskEvent.getTaskType(), subscriber.getSourceAddress(), + scopeEnum); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private Map> getCache(ScopeEnum scopeEnum) { + return sessionInterests.querySubscriberIndex(dataChangeRequest.getDataInfoId(), scopeEnum); + } + + private Datum getDatumCache() { + DatumKey datumKey = new DatumKey(dataChangeRequest.getDataInfoId(), + dataChangeRequest.getDataCenter()); + Key key = new Key(KeyType.OBJ, datumKey.getClass().getName(), datumKey); + Value value = sessionCacheService.getValue(key); + return value == null ? null : value.getPayload(); + } + + private void fireUserDataElementPushTask(InetSocketAddress address, Datum datum, + Collection subscribers, + PushTaskClosure pushTaskClosure) { + + TaskEvent taskEvent = new TaskEvent(TaskType.USER_DATA_ELEMENT_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setSendTimeStamp(datum.getVersion()); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, new URL(address)); + + int size = datum != null && datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), address, datum.getDataInfoId(), datum.getDataCenter(), size, + subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataElementMultiPushTask(InetSocketAddress address, Datum datum, + Collection subscribers, + PushTaskClosure pushTaskClosure) { + + TaskEvent taskEvent = new TaskEvent(TaskType.USER_DATA_ELEMENT_MULTI_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setSendTimeStamp(datum.getVersion()); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, new URL(address)); + + int size = datum != null && datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), address, datum.getDataInfoId(), datum.getDataCenter(), size, + subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public long getExpiryTime() { + return -1; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof DataChangeRequest)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.dataChangeRequest = (DataChangeRequest) obj; + } + + /** + * Setter method for property dataChangeRequest. + * + * @param dataChangeRequest value to be assigned to property dataChangeRequest + */ + public void setDataChangeRequest(DataChangeRequest dataChangeRequest) { + this.dataChangeRequest = dataChangeRequest; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getDataChangeFetchTaskRetryTimes()); + } + + @Override + public String toString() { + return "DATA_CHANGE_FETCH_TASK{" + "taskId='" + getTaskId() + '\'' + ", dataChangeRequest=" + + dataChangeRequest + ", expiryTime='" + getExpiryTime() + '\'' + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataPushTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataPushTask.java new file mode 100644 index 000000000..e372dc21c --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/DataPushTask.java @@ -0,0 +1,280 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.sessionserver.DataPushRequest; +import com.alipay.sofa.registry.common.model.store.BaseInfo.ClientVersion; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Predicate; + +/** + * + * @author shangyu.wh + * @version $Id: DataPushTask.java, v 0.1 2018-08-29 19:46 shangyu.wh Exp $ + */ +public class DataPushTask extends AbstractSessionTask { + + private final static Logger LOGGER = LoggerFactory.getLogger(DataPushTask.class); + + private static final Logger taskLogger = LoggerFactory.getLogger(DataPushTask.class, + "[Task]"); + + private final SessionServerConfig sessionServerConfig; + + private final Interests sessionInterests; + + private final ExecutorManager executorManager; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + private final TaskListenerManager taskListenerManager; + + private DataPushRequest dataPushRequest; + + public DataPushTask(Interests sessionInterests, SessionServerConfig sessionServerConfig, + ExecutorManager executorManager, TaskListenerManager taskListenerManager) { + this.sessionInterests = sessionInterests; + this.sessionServerConfig = sessionServerConfig; + this.executorManager = executorManager; + this.taskListenerManager = taskListenerManager; + } + + @Override + public void execute() { + + String localDataCenterID = sessionServerConfig.getSessionServerDataCenter(); + + Datum datum = dataPushRequest.getDatum(); + + if (datum != null) { + + boolean ifLocalDataCenter = localDataCenterID.equals(datum.getDataCenter()); + + String dataInfoId = datum.getDataInfoId(); + + PushTaskClosure pushTaskClosure = getTaskClosure(); + + for (ScopeEnum scopeEnum : ScopeEnum.values()) { + Map> map = getCache(scopeEnum, + dataInfoId); + if (map != null && !map.isEmpty()) { + for (Entry> entry : map.entrySet()) { + Map subscriberMap = entry.getValue(); + if (subscriberMap != null && !subscriberMap.isEmpty()) { + List subscriberRegisterIdList = new ArrayList<>( + subscriberMap.keySet()); + + Subscriber subscriber = subscriberMap.values().iterator().next(); + boolean isOldVersion = !ClientVersion.StoreData.equals(subscriber + .getClientVersion()); + + Collection subscribersSend = new ArrayList<>( + subscriberMap.values()); + + switch (scopeEnum) { + case zone: + if (ifLocalDataCenter) { + if (isOldVersion) { + fireUserDataElementPushTask(entry.getKey(), datum, + subscribersSend, pushTaskClosure); + } else { + fireReceivedDataMultiPushTask(datum, + subscriberRegisterIdList, ScopeEnum.zone, + subscriber, pushTaskClosure, subscriberMap); + } + } + break; + case dataCenter: + if (ifLocalDataCenter) { + if (isOldVersion) { + fireUserDataElementMultiPushTask(entry.getKey(), datum, + subscribersSend, pushTaskClosure); + } else { + fireReceivedDataMultiPushTask(datum, + subscriberRegisterIdList, scopeEnum, subscriber, + pushTaskClosure, subscriberMap); + } + } + break; + case global: + fireReceivedDataMultiPushTask(datum, subscriberRegisterIdList, + scopeEnum, subscriber, pushTaskClosure, subscriberMap); + break; + default: + LOGGER.warn("unknown scope, {}", subscriber); + } + } + } + } + } + pushTaskClosure.start(); + } + } + + public PushTaskClosure getTaskClosure() { + PushTaskClosure pushTaskClosure = new PushTaskClosure(executorManager.getPushTaskClosureExecutor()); + pushTaskClosure.setTaskClosure((status, task) -> { + if (status == ProcessingResult.Success) { + Datum datum = dataPushRequest.getDatum(); + String dataCenter = datum.getDataCenter(); + String dataInfoId = datum.getDataInfoId(); + Long version = datum.getVersion(); + + if (sessionServerConfig.isStopPushSwitch()) { + LOGGER.info("Stop Push switch on,dataCenter {} dataInfoId {} version {} can not be update!", + dataCenter, dataInfoId, version); + return; + } + + LOGGER.info("Push all temp data tasks success,dataCenter:{} dataInfoId:{} version:{} update!", + dataCenter, dataInfoId, + version); + } else { + LOGGER.warn("Push temp data tasks found error,subscribers version can not be update!"); + } + }); + return pushTaskClosure; + } + + private void fireReceivedDataMultiPushTask(Datum datum, List subscriberRegisterIdList, + ScopeEnum scopeEnum, Subscriber subscriber, + PushTaskClosure pushTaskClosure, Map subscriberMap) { + Collection subscribers = new ArrayList<>(subscriberMap.values()); + String dataId = datum.getDataId(); + Predicate zonePredicate = (zone) -> { + if (!sessionServerConfig.getSessionServerRegion().equals(zone)) { + if (ScopeEnum.zone == scopeEnum) { + // zone scope subscribe only return zone list + return true; + + } else if (ScopeEnum.dataCenter == scopeEnum) { + // disable zone config + if (sessionServerConfig.isInvalidForeverZone(zone) + && !sessionServerConfig.isInvalidIgnored(dataId)) { + return true; + } + } + } + return false; + }; + ReceivedData receivedData = ReceivedDataConverter.getReceivedDataMulti(datum, scopeEnum, + subscriberRegisterIdList, sessionServerConfig.getSessionServerRegion(), zonePredicate); + + //trigger push to client node + Map parameter = new HashMap<>(); + parameter.put(receivedData, subscriber.getSourceAddress()); + TaskEvent taskEvent = new TaskEvent(parameter, TaskType.RECEIVED_DATA_MULTI_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskLogger.info("send {} taskURL:{},taskScope:{}", taskEvent.getTaskType(), subscriber.getSourceAddress(), + scopeEnum); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private Map> getCache(ScopeEnum scopeEnum, + String dataInfoId) { + return sessionInterests.querySubscriberIndex(dataInfoId, scopeEnum); + } + + private void fireUserDataElementPushTask(InetSocketAddress address, Datum datum, + Collection subscribers, + PushTaskClosure pushTaskClosure) { + + TaskEvent taskEvent = new TaskEvent(TaskType.USER_DATA_ELEMENT_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, new URL(address)); + + int size = datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), address, datum.getDataInfoId(), datum.getDataCenter(), size, + subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataElementMultiPushTask(InetSocketAddress address, Datum datum, + Collection subscribers, + PushTaskClosure pushTaskClosure) { + + TaskEvent taskEvent = new TaskEvent(TaskType.USER_DATA_ELEMENT_MULTI_PUSH_TASK); + taskEvent.setTaskClosure(pushTaskClosure); + + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, new URL(address)); + + int size = datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), address, datum.getDataInfoId(), datum.getDataCenter(), size, + subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public long getExpiryTime() { + return -1; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof DataPushRequest)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.dataPushRequest = (DataPushRequest) obj; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getDataChangeFetchTaskRetryTimes()); + } + + @Override + public String toString() { + return "DATA_PUSH_TASK{" + "taskId='" + getTaskId() + '\'' + ", dataPushRequest=" + + dataPushRequest + ", expiryTime='" + getExpiryTime() + '\'' + '}'; + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ProvideDataChangeFetchTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ProvideDataChangeFetchTask.java new file mode 100644 index 000000000..19ffb86c1 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ProvideDataChangeFetchTask.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.metaserver.DataOperator; +import com.alipay.sofa.registry.common.model.metaserver.NotifyProvideDataChange; +import com.alipay.sofa.registry.common.model.metaserver.ProvideData; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.node.service.MetaNodeService; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.ReSubscribers; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTask.java, v 0.1 2017-12-07 16:23 shangyu.wh Exp $ + */ +public class ProvideDataChangeFetchTask extends AbstractSessionTask { + + private static final Logger TASK_LOGGER = LoggerFactory.getLogger( + ProvideDataChangeFetchTask.class, "[Task]"); + + private static final Logger LOGGER = LoggerFactory + .getLogger(ProvideDataChangeFetchTask.class); + + private final SessionServerConfig sessionServerConfig; + /** + * trigger push client process + */ + private final TaskListenerManager taskListenerManager; + /** + * Meta Node service + */ + private final MetaNodeService metaNodeService; + + private final Watchers sessionWatchers; + + private final Exchange boltExchange; + + private final Interests sessionInterests; + + private final Registry sessionRegistry; + + private NotifyProvideDataChange notifyProvideDataChange; + + public ProvideDataChangeFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + MetaNodeService metaNodeService, Watchers sessionWatchers, + Exchange boltExchange, Interests sessionInterests, + Registry sessionRegistry) { + this.sessionServerConfig = sessionServerConfig; + this.taskListenerManager = taskListenerManager; + this.metaNodeService = metaNodeService; + this.sessionWatchers = sessionWatchers; + this.boltExchange = boltExchange; + this.sessionInterests = sessionInterests; + this.sessionRegistry = sessionRegistry; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof NotifyProvideDataChange)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.notifyProvideDataChange = (NotifyProvideDataChange) obj; + } + + @Override + public void execute() { + + ProvideData provideData = null; + String dataInfoId = notifyProvideDataChange.getDataInfoId(); + if (notifyProvideDataChange.getDataOperator() != DataOperator.REMOVE) { + provideData = metaNodeService.fetchData(dataInfoId); + + if (ValueConstants.STOP_PUSH_DATA_SWITCH_DATA_ID.equals(dataInfoId)) { + if (provideData != null) { + if (provideData.getProvideData() == null || provideData.getProvideData().getObject() == null) { + LOGGER.info("Fetch session stop push switch no data existed,config not change!"); + return; + } + String data = (String) provideData.getProvideData().getObject(); + LOGGER.info("Fetch session stop push data switch {} success!", data); + + //receive stop push switch off + if (data != null) { + boolean switchData = Boolean.valueOf(data); + boolean ifChange = sessionServerConfig.isStopPushSwitch() != switchData; + sessionServerConfig.setStopPushSwitch(switchData); + if (!switchData) { + //avoid duplicate false receive + if (ifChange) { + fireReSubscriber(); + } + } else { + //stop push and stop fetch data task + sessionServerConfig.setBeginDataFetchTask(false); + } + } else { + LOGGER.error("Fetch session stop push data switch is null!"); + } + return; + } else { + LOGGER.info("Fetch session stop push switch data null,config not change!"); + } + return; + } + if (provideData == null) { + LOGGER.warn("Notify provider data Change request {} fetch no provider data!", notifyProvideDataChange); + return; + } + } + DataInfo dataInfo = DataInfo.valueOf(dataInfoId); + + Server sessionServer = boltExchange.getServer(sessionServerConfig.getServerPort()); + if (sessionServer != null) { + for (Channel channel : sessionServer.getChannels()) { + + //filter all connect client has watcher registerId + String connectId = NetUtil.toAddressString(channel.getRemoteAddress()); + Map map = getCache(connectId); + List registerIds = new ArrayList<>(); + map.forEach((registerId, watchers) -> { + if (watchers != null && watchers.getDataInfoId().equals(dataInfoId)) { + registerIds.add(registerId); + } + }); + if (!registerIds.isEmpty()) { + ReceivedConfigData receivedConfigData; + if (notifyProvideDataChange.getDataOperator() == DataOperator.REMOVE) { + receivedConfigData = ReceivedDataConverter.getReceivedConfigData(null, dataInfo, + notifyProvideDataChange.getVersion()); + } else { + receivedConfigData = ReceivedDataConverter.getReceivedConfigData( + provideData.getProvideData(), dataInfo, provideData.getVersion()); + } + receivedConfigData.setConfiguratorRegistIds(registerIds); + firePushTask(receivedConfigData, new URL(channel.getRemoteAddress())); + } + } + } + } + + /** + * open push switch to push all reSubscribers + */ + private void fireReSubscriber() { + + //try catch avoid to error cancel beginDataFetchTask switch on + try { + //begin push fire data fetch task first,avoid reSubscriber push duplicate + sessionRegistry.fetchChangDataProcess(); + } catch (Throwable e) { + LOGGER.error("Open push switch first fetch task execute error",e); + } + + try { + //wait 1 MINUTES for dataFetch task evict duplicate subscriber push + TimeUnit.MINUTES.sleep(1); + } catch (InterruptedException e) { + LOGGER.error("Wait for dataFetch Task Interrupted!"); + } + + //fetch task process 1 minutes,can schedule execute fetch task + sessionServerConfig.setBeginDataFetchTask(true); + + if (this.sessionInterests instanceof ReSubscribers) { + ReSubscribers reSubscriber = (ReSubscribers) sessionInterests; + + Map> reSubscribers = reSubscriber + .getReSubscribers(); + + if (reSubscribers != null && !reSubscribers.isEmpty()) { + reSubscribers.forEach( + (dataInfoId, subscribers) -> fireSubscriberMultiFetchTask(dataInfoId, subscribers.values())); + reSubscriber.clearReSubscribers(); + } + } + } + + private void fireSubscriberMultiFetchTask(String dataInfoId, Collection subscribers) { + //trigger fetch data for subscriber,and push to client node + if (!CollectionUtils.isEmpty(subscribers)) { + TaskEvent taskEvent = new TaskEvent(dataInfoId, TaskType.SUBSCRIBER_MULTI_FETCH_TASK); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + + " subscribersSize:{},dataInfoId:{}", subscribers.size(), dataInfoId); + taskListenerManager.sendTaskEvent(taskEvent); + } + } + + private void firePushTask(ReceivedConfigData receivedConfigData, URL clientUrl) { + + Map parameter = new HashMap<>(); + parameter.put(receivedConfigData, clientUrl); + TaskEvent taskEvent = new TaskEvent(parameter, TaskType.RECEIVED_DATA_CONFIG_PUSH_TASK); + TASK_LOGGER.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private Map getCache(String connectId) { + Map map = sessionWatchers.queryByConnectId(connectId); + return map == null ? new ConcurrentHashMap<>() : map; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getSubscriberRegisterFetchRetryTimes()); + } + + @Override + public String toString() { + return "PROVIDE_DATA_CHANGE_FETCH_TASK{" + "taskId='" + getTaskId() + '\'' + + ", notifyProvideDataChange=" + notifyProvideDataChange + ", retryTimes='" + + sessionServerConfig.getSubscriberRegisterFetchRetryTimes() + '\'' + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/PushTaskClosure.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/PushTaskClosure.java new file mode 100644 index 000000000..cf7d46ece --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/PushTaskClosure.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.task.Task; +import com.alipay.sofa.registry.task.TaskClosure; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; + +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: PushTaskClosure.java, v 0.1 2018-06-04 17:13 shangyu.wh Exp $ + */ +public class PushTaskClosure implements TaskClosure { + + private final static Logger LOGGER = LoggerFactory + .getLogger(PushTaskClosure.class); + + private ConcurrentHashMap taskMap = new ConcurrentHashMap<>(); + + private ConcurrentHashMap taskResultMap = new ConcurrentHashMap<>(); + + private TaskClosure taskClosure; + + private final BlockingQueue completionQueue = new LinkedBlockingQueue<>(); + + private final ExecutorService pushTaskClosureExecutor; + + public PushTaskClosure(ExecutorService pushTaskClosureExecutor) { + this.pushTaskClosureExecutor = pushTaskClosureExecutor; + } + + @Override + public void run(ProcessingResult processingResult, Task task) { + if (task != null) { + ProcessingResult existed = taskResultMap + .putIfAbsent(task.getTaskId(), processingResult); + if (existed == null) { + completionQueue.add(task.getTaskId()); + } + } + } + + public void addTask(Task task) { + taskMap.putIfAbsent(task.getTaskId(), task); + } + + public void start() { + pushTaskClosureExecutor.execute(() -> { + try { + int size = taskMap.size(); + LOGGER.info("Push task queue size {},map size {}", completionQueue.size(), size); + for (int i = 0; i < size; i++) { + String taskId = completionQueue.poll(6000, TimeUnit.MILLISECONDS); + if(taskId != null) { + ProcessingResult result = taskResultMap.get(taskId); + if (result == ProcessingResult.Success) { + taskMap.remove(taskId); + } + } + } + } catch (InterruptedException e) { + LOGGER.error("Push task check InterruptedException!", e); + } + + if (taskMap.isEmpty()) { + LOGGER.info("Push all tasks success"); + if (taskClosure != null) { + taskClosure.run(ProcessingResult.Success, null); + } + + } else { + LOGGER.warn("Push tasks found error tasks {} !", taskMap); + if (taskClosure != null) { + taskClosure.run(ProcessingResult.PermanentError, null); + } + } + }); + } + + /** + * Getter method for property taskMap. + * + * @return property value of taskMap + */ + public Map getTaskMap() { + return taskMap; + } + + /** + * Setter method for property taskClosure. + * + * @param taskClosure value to be assigned to property taskClosure + */ + public void setTaskClosure(TaskClosure taskClosure) { + this.taskClosure = taskClosure; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedConfigDataPushTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedConfigDataPushTask.java new file mode 100644 index 000000000..168e86474 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedConfigDataPushTask.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.ClientNodeService; +import com.alipay.sofa.registry.server.session.strategy.ReceivedConfigDataPushTaskStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.Map; +import java.util.Map.Entry; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterPushTask.java, v 0.1 2017-12-11 20:57 shangyu.wh Exp $ + */ +public class ReceivedConfigDataPushTask extends AbstractSessionTask { + + private static final Logger LOGGER = LoggerFactory.getLogger( + ReceivedConfigDataPushTask.class, + "[Task]"); + + private final SessionServerConfig sessionServerConfig; + private final ClientNodeService clientNodeService; + private ReceivedConfigData receivedConfigData; + private URL url; + private ReceivedConfigDataPushTaskStrategy receivedConfigDataPushTaskStrategy; + + public ReceivedConfigDataPushTask(SessionServerConfig sessionServerConfig, + ClientNodeService clientNodeService, + ReceivedConfigDataPushTaskStrategy receivedConfigDataPushTaskStrategy) { + this.sessionServerConfig = sessionServerConfig; + this.clientNodeService = clientNodeService; + this.receivedConfigDataPushTaskStrategy = receivedConfigDataPushTaskStrategy; + } + + @Override + public void execute() { + + if (sessionServerConfig.isStopPushSwitch()) { + LOGGER + .info( + "Stop Push receivedConfigData with switch on! dataId: {},group: {},Instance: {}, url: {}", + receivedConfigData.getDataId(), receivedConfigData.getGroup(), + receivedConfigData.getInstanceId(), url); + return; + } + + CallbackHandler callbackHandler = new CallbackHandler() { + @Override + public void onCallback(Channel channel, Object message) { + LOGGER.info( + "Push receivedConfigData success! dataId: {},group: {},Instance: {}, url: {}", + receivedConfigData.getDataId(), receivedConfigData.getGroup(), + receivedConfigData.getInstanceId(), url); + } + + @Override + public void onException(Channel channel, Throwable exception) { + LOGGER.error( + "Push receivedConfigData error! dataId: {},group: {},Instance: {}, url: {}", + receivedConfigData.getDataId(), receivedConfigData.getGroup(), + receivedConfigData.getInstanceId(), url); + } + }; + + clientNodeService.pushWithCallback( + receivedConfigDataPushTaskStrategy.convert2PushData(receivedConfigData, url), url, + callbackHandler); + } + + @Override + public long getExpiryTime() { + //TODO CONFIG + return -1; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (obj instanceof Map) { + + Map parameter = (Map) obj; + + if (parameter.size() == 1) { + + Entry entry = (parameter.entrySet()).iterator().next(); + ReceivedConfigData receivedData = entry.getKey(); + URL url = entry.getValue(); + + this.receivedConfigData = receivedData; + this.url = url; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + } + + @Override + public String toString() { + return "RECEIVED_DATA_CONFIG_PUSH_TASK{" + "taskId='" + getTaskId() + '\'' + + ", receivedConfigData=" + receivedConfigData + ", url=" + url + ", retry='" + + sessionServerConfig.getReceivedDataMultiPushTaskRetryTimes() + '\'' + '}'; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getReceivedDataMultiPushTaskRetryTimes()); + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedDataMultiPushTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedDataMultiPushTask.java new file mode 100644 index 000000000..dde2fd9be --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/ReceivedDataMultiPushTask.java @@ -0,0 +1,284 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.PushDataRetryRequest; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.CallbackHandler; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.service.ClientNodeService; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.strategy.ReceivedDataMultiPushTaskStrategy; +import com.alipay.sofa.registry.task.Task; +import com.alipay.sofa.registry.task.TaskClosure; +import com.alipay.sofa.registry.task.batcher.TaskProcessor.ProcessingResult; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.timer.AsyncHashedWheelTimer; + +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterPushTask.java, v 0.1 2017-12-11 20:57 shangyu.wh Exp $ + */ +public class ReceivedDataMultiPushTask extends AbstractSessionTask implements TaskClosure { + + private static final Logger LOGGER = LoggerFactory.getLogger("SESSION-PUSH", + "[Receive]"); + + private final SessionServerConfig sessionServerConfig; + private final ClientNodeService clientNodeService; + private final ExecutorManager executorManager; + private final Exchange boltExchange; + private ReceivedData receivedData; + private URL url; + private TaskClosure taskClosure; + private Collection subscribers; + private ReceivedDataMultiPushTaskStrategy receivedDataMultiPushTaskStrategy; + private AsyncHashedWheelTimer asyncHashedWheelTimer; + + public ReceivedDataMultiPushTask(SessionServerConfig sessionServerConfig, + ClientNodeService clientNodeService, + ExecutorManager executorManager, + Exchange boltExchange, + ReceivedDataMultiPushTaskStrategy receivedDataMultiPushTaskStrategy, + AsyncHashedWheelTimer asyncHashedWheelTimer) { + this.sessionServerConfig = sessionServerConfig; + this.clientNodeService = clientNodeService; + this.executorManager = executorManager; + this.boltExchange = boltExchange; + this.receivedDataMultiPushTaskStrategy = receivedDataMultiPushTaskStrategy; + this.asyncHashedWheelTimer = asyncHashedWheelTimer; + } + + @Override + public void execute() { + + if (sessionServerConfig.isStopPushSwitch()) { + LOGGER + .info( + "Stop Push ReceivedData with switch on! dataId: {},group: {},Instance: {}, url: {}", + receivedData.getDataId(), receivedData.getGroup(), + receivedData.getInstanceId(), url); + return; + } + + Object receivedDataPush = receivedDataMultiPushTaskStrategy.convert2PushData(receivedData, + url); + + CallbackHandler callbackHandler = new CallbackHandler() { + @Override + public void onCallback(Channel channel, Object message) { + LOGGER.info( + "Push ReceivedData success! dataId:{},group:{},Instance:{},version:{},url: {}", + receivedData.getDataId(), receivedData.getGroup(), + receivedData.getInstanceId(), receivedData.getVersion(), url); + + if (taskClosure != null) { + confirmCallBack(true); + } + } + + @Override + public void onException(Channel channel, Throwable exception) { + LOGGER.error( + "Push ReceivedData error! dataId:{},group:{},Instance:{},version:{},url: {}", + receivedData.getDataId(), receivedData.getGroup(), + receivedData.getInstanceId(), receivedData.getVersion(), url, exception); + + if (taskClosure != null) { + confirmCallBack(false); + throw new RuntimeException("Push ReceivedData got exception from callback!"); + } else { + retrySendReceiveData(new PushDataRetryRequest(receivedDataPush, url)); + } + } + }; + + try { + clientNodeService.pushWithCallback(receivedDataPush, url, callbackHandler); + } catch (Exception e) { + if (taskClosure != null) { + confirmCallBack(false); + throw e; + } else { + retrySendReceiveData(new PushDataRetryRequest(receivedDataPush, url)); + } + } + } + + private void retrySendReceiveData(PushDataRetryRequest pushDataRetryRequest) { + ///taskClosure null means send task need not confirm + if (taskClosure == null) { + + Object infoPackage = pushDataRetryRequest.getPushObj(); + + int retryTimes = pushDataRetryRequest.getRetryTimes().incrementAndGet(); + + URL targetUrl = pushDataRetryRequest.getUrl(); + + if (checkRetryTimes(retryTimes)) { + Server sessionServer = boltExchange.getServer(sessionServerConfig.getServerPort()); + + Channel channel = sessionServer.getChannel(targetUrl); + + if (channel != null && channel.isConnected()) { + + asyncHashedWheelTimer.newTimeout(timeout -> { + try { + clientNodeService.pushWithCallback(infoPackage, targetUrl, new CallbackHandler() { + @Override + public void onCallback(Channel channel, Object message) { + LOGGER.info("Retry Push ReceivedData success! dataId:{}, group:{},url:{},retryTimes:{}", + receivedData.getDataId(), receivedData.getGroup(), targetUrl,retryTimes); + } + + @Override + public void onException(Channel channel, Throwable exception) { + LOGGER.error("Retry Push ReceivedData callback error! url:{}, dataId:{}, group:{},taskId:{},retryTimes:{}", targetUrl, + receivedData.getDataId(), receivedData.getGroup(),getTaskId(),retryTimes); + retrySendReceiveData(pushDataRetryRequest); + } + }); + + } catch (Exception e) { + LOGGER.error("Retry Push ReceivedData error! url:{}, dataId:{}, group:{},taskId:{},retryTimes:{}", targetUrl, + receivedData.getDataId(), receivedData.getGroup(),getTaskId(),retryTimes); + retrySendReceiveData(pushDataRetryRequest); + } + },getBlockTime(retryTimes),TimeUnit.MILLISECONDS); + } else { + LOGGER.error("Retry Push ReceivedData error, connect be null or disconnected,stop retry!dataId:{}, group:{},url:{},taskId:{},retryTimes:{}", + receivedData.getDataId(), receivedData.getGroup(), targetUrl,getTaskId(),retryTimes); + } + } else { + LOGGER.error("Retry Push ReceivedData times have exceeded!dataId:{}, group:{},url:{},taskId:{},retryTimes:{}", + receivedData.getDataId(), receivedData.getGroup(), targetUrl,getTaskId(),retryTimes); + } + } + } + + @Override + public long getExpiryTime() { + //TODO CONFIG + return -1; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (obj instanceof Map) { + + Map parameter = (Map) obj; + + if (parameter.size() == 1) { + + Entry entry = (parameter.entrySet()).iterator().next(); + ReceivedData receivedData = entry.getKey(); + URL url = entry.getValue(); + + this.receivedData = receivedData; + this.url = url; + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + } + + taskClosure = taskEvent.getTaskClosure(); + + if (taskClosure instanceof PushTaskClosure) { + ((PushTaskClosure) taskClosure).addTask(this); + } + + subscribers = (Collection) taskEvent + .getAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS); + //taskClosure must confirm all subscriber push success + if (taskClosure != null && subscribers.isEmpty()) { + LOGGER.error("send Receive data subscribers is empty!"); + throw new RuntimeException("Push Receive data got exception!send subscribers is empty"); + } + } + + private void confirmCallBack(final boolean result) { + + if (taskClosure != null) { + + executorManager.getCheckPushExecutor().execute(() -> { + + if (result) { + //change all subscribers push version + subscribers.forEach(subscriber -> subscriber + .checkAndUpdateVersion(receivedData.getSegment(), receivedData.getVersion())); + + taskClosure.run(ProcessingResult.Success, ReceivedDataMultiPushTask.this); + } else { + taskClosure.run(ProcessingResult.PermanentError, ReceivedDataMultiPushTask.this); + } + + }); + } + } + + @Override + public String toString() { + return "RECEIVED_DATA_MULTI_PUSH_TASK{" + "taskId='" + getTaskId() + '\'' + + ", receivedData=" + receivedData + ", url=" + url + ", expiryTime='" + + getExpiryTime() + '\'' + '}'; + } + + @Override + protected boolean checkRetryTimes(int retryTimes) { + int configTimes = sessionServerConfig.getReceivedDataMultiPushTaskRetryTimes(); + if (configTimes > 0) { + return retryTimes <= configTimes; + } + return false; + } + + private long getBlockTime(int retry) { + long initialSleepTime = TimeUnit.MILLISECONDS.toMillis(sessionServerConfig + .getPushDataTaskRetryFirstDelay()); + long increment = TimeUnit.MILLISECONDS.toMillis(sessionServerConfig + .getPushDataTaskRetryIncrementDelay()); + long result = initialSleepTime + (increment * (retry - 1)); + return result >= 0L ? result : 0L; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getReceivedDataMultiPushTaskRetryTimes()); + } + + @Override + public void run(ProcessingResult processingResult, Task task) { + if (taskClosure != null) { + taskClosure.run(processingResult, task); + } + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionRegisterDataTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionRegisterDataTask.java new file mode 100644 index 000000000..0640760ed --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionRegisterDataTask.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.dataserver.SessionServerRegisterRequest; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.exchange.Exchange; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.node.SessionProcessIdGenerator; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author shangyu.wh + * @version $Id: SessionRegisterDataTask.java, v 0.1 2018-04-16 16:07 shangyu.wh Exp $ + */ +public class SessionRegisterDataTask extends AbstractSessionTask { + + private static final Logger LOGGER = LoggerFactory.getLogger( + SessionRegisterDataTask.class, "[Task]"); + + private final Exchange boltExchange; + private final DataNodeService dataNodeService; + private final SessionServerConfig sessionServerConfig; + + private SessionServerRegisterRequest sessionServerRegisterRequest; + private URL dataUrl; + + public SessionRegisterDataTask(Exchange boltExchange, DataNodeService dataNodeService, + SessionServerConfig sessionServerConfig) { + this.boltExchange = boltExchange; + this.dataNodeService = dataNodeService; + this.sessionServerConfig = sessionServerConfig; + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getSessionRegisterDataServerTaskRetryTimes()); + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (obj instanceof URL) { + + this.dataUrl = (URL) obj; + + } else { + throw new IllegalArgumentException("Input task event object error!"); + } + Server sessionServer = boltExchange.getServer(sessionServerConfig.getServerPort()); + + if (sessionServer != null) { + + Collection chs = sessionServer.getChannels(); + Set clientHosts = new HashSet<>(); + chs.forEach(channel -> clientHosts.add(NetUtil.toAddressString(channel.getRemoteAddress()))); + + sessionServerRegisterRequest = new SessionServerRegisterRequest( + SessionProcessIdGenerator.getSessionProcessId(), clientHosts); + } else { + LOGGER.error("get null session server,please check server started before register!port {}", + sessionServerConfig.getServerPort()); + sessionServerRegisterRequest = new SessionServerRegisterRequest( + SessionProcessIdGenerator.getSessionProcessId(), new HashSet<>()); + } + } + + @Override + public void execute() { + dataNodeService.registerSessionProcessId(sessionServerRegisterRequest, dataUrl); + } + + @Override + public String toString() { + return "SESSION_REGISTER_DATA_TASK{" + "taskId='" + taskId + '\'' + + ", sessionServerRegisterRequest=" + sessionServerRegisterRequest.getProcessId() + + ", clientList=" + sessionServerRegisterRequest.getClientHosts().size() + + ", dataUrl=" + dataUrl + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionTask.java new file mode 100644 index 000000000..eea3c4f93 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SessionTask.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.task.Task; + +/** + * + * @author shangyu.wh + * @version $Id: SessionTask.java, v 0.1 2017-12-07 20:57 shangyu.wh Exp $ + */ +public interface SessionTask extends Task { + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberMultiFetchTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberMultiFetchTask.java new file mode 100644 index 000000000..ffb1495c0 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberMultiFetchTask.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.strategy.SubscriberMultiFetchTaskStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberMultiFetchTask.java, v 0.1 2018-11-08 11:54 shangyu.wh Exp $ + */ +public class SubscriberMultiFetchTask extends AbstractSessionTask { + private static final Logger LOGGER = LoggerFactory + .getLogger(SubscriberMultiFetchTask.class); + + private final SessionServerConfig sessionServerConfig; + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + private final TaskListenerManager taskListenerManager; + + private final CacheService sessionCacheService; + + private String fetchDataInfoId; + + private Collection subscribers; + + private SubscriberMultiFetchTaskStrategy subscriberMultiFetchTaskStrategy; + + public SubscriberMultiFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + CacheService sessionCacheService, + SubscriberMultiFetchTaskStrategy subscriberMultiFetchTaskStrategy) { + this.sessionServerConfig = sessionServerConfig; + this.taskListenerManager = taskListenerManager; + this.sessionCacheService = sessionCacheService; + this.subscriberMultiFetchTaskStrategy = subscriberMultiFetchTaskStrategy; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof String)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.fetchDataInfoId = (String) obj; + + subscribers = (Collection) taskEvent + .getAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS); + + if (subscribers.isEmpty()) { + LOGGER.error("Subscriber MultiFetchTask subscribers is empty!"); + throw new RuntimeException( + "Subscriber MultiFetchTask got exception!send subscribers is empty"); + } + } + + @Override + public void execute() { + subscriberMultiFetchTaskStrategy.doSubscriberMultiFetchTask(sessionServerConfig, + taskListenerManager, sessionCacheService, fetchDataInfoId, subscribers); + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getDataChangeFetchTaskRetryTimes()); + } + + @Override + public String toString() { + return "SUBSCRIBER_MULTI_FETCH_TASK {" + "taskId='" + getTaskId() + '\'' + + ", fetchDataInfoId=" + fetchDataInfoId + ", expiryTime='" + getExpiryTime() + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberRegisterFetchTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberRegisterFetchTask.java new file mode 100644 index 000000000..815325337 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/SubscriberRegisterFetchTask.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.strategy.SubscriberRegisterFetchTaskStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTask.java, v 0.1 2017-12-07 16:23 shangyu.wh Exp $ + */ +public class SubscriberRegisterFetchTask extends AbstractSessionTask { + + private final SessionServerConfig sessionServerConfig; + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + private final TaskListenerManager taskListenerManager; + /** + * DataNode service + */ + private final DataNodeService dataNodeService; + + private final CacheService sessionCacheService; + + private final SubscriberRegisterFetchTaskStrategy subscriberRegisterFetchTaskStrategy; + private Subscriber subscriber; + + public SubscriberRegisterFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + DataNodeService dataNodeService, + CacheService sessionCacheService, + SubscriberRegisterFetchTaskStrategy subscriberRegisterFetchTaskStrategy) { + this.sessionServerConfig = sessionServerConfig; + this.taskListenerManager = taskListenerManager; + this.dataNodeService = dataNodeService; + this.sessionCacheService = sessionCacheService; + this.subscriberRegisterFetchTaskStrategy = subscriberRegisterFetchTaskStrategy; + } + + @Override + public long getExpiryTime() { + //TODO CONFIG + return -1; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof Subscriber)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.subscriber = (Subscriber) obj; + } + + @Override + public void execute() { + subscriberRegisterFetchTaskStrategy.doSubscriberRegisterFetchTask(sessionServerConfig, + taskListenerManager, dataNodeService, sessionCacheService, subscriber); + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getSubscriberRegisterFetchRetryTimes()); + } + + @Override + public String toString() { + return "SUBSCRIBER_REGISTER_FETCH_TASK{" + "taskId='" + getTaskId() + '\'' + + ", subscriber=" + subscriber + ", expiryTime='" + getExpiryTime() + '\'' + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/WatcherRegisterFetchTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/WatcherRegisterFetchTask.java new file mode 100644 index 000000000..ad5bdf1b0 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/task/WatcherRegisterFetchTask.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.task; + +import com.alipay.sofa.registry.common.model.metaserver.ProvideData; +import com.alipay.sofa.registry.common.model.store.BaseInfo.ClientVersion; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.node.service.MetaNodeService; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskEvent.TaskType; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: SubscriberRegisterFetchTask.java, v 0.1 2017-12-07 16:23 shangyu.wh Exp $ + */ +public class WatcherRegisterFetchTask extends AbstractSessionTask { + + private static final Logger taskLogger = LoggerFactory.getLogger( + WatcherRegisterFetchTask.class, "[Task]"); + + private final SessionServerConfig sessionServerConfig; + /** + * trigger push client process + */ + private final TaskListenerManager taskListenerManager; + /** + * Meta Node service + */ + private final MetaNodeService metaNodeService; + + private Watcher watcher; + + public WatcherRegisterFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + MetaNodeService metaNodeService) { + this.sessionServerConfig = sessionServerConfig; + this.taskListenerManager = taskListenerManager; + this.metaNodeService = metaNodeService; + } + + @Override + public void setTaskEvent(TaskEvent taskEvent) { + Object obj = taskEvent.getEventObj(); + + if (!(obj instanceof Watcher)) { + throw new IllegalArgumentException("Input task event object error!"); + } + + this.watcher = (Watcher) obj; + } + + @Override + public void execute() { + + if (watcher == null) { + throw new IllegalArgumentException("watcher can not be null!"); + } + + List subscriberRegisterIdList = Collections.singletonList(watcher.getRegisterId()); + + boolean isOldVersion = !ClientVersion.StoreData.equals(watcher.getClientVersion()); + + ProvideData provideData = metaNodeService.fetchData(watcher.getDataInfoId()); + if (provideData != null) { + if (!isOldVersion) { + DataInfo dataInfo = DataInfo.valueOf(provideData.getDataInfoId()); + ReceivedConfigData receivedConfigData = ReceivedDataConverter + .getReceivedConfigData(provideData.getProvideData(), dataInfo, + provideData.getVersion()); + receivedConfigData.setConfiguratorRegistIds(subscriberRegisterIdList); + firePushTask(receivedConfigData); + } + } + } + + private void firePushTask(ReceivedConfigData receivedConfigData) { + Map parameter = new HashMap<>(); + parameter.put(receivedConfigData, watcher.getSourceAddress()); + TaskEvent taskEvent = new TaskEvent(parameter, TaskType.RECEIVED_DATA_CONFIG_PUSH_TASK); + taskLogger.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public boolean checkRetryTimes() { + return checkRetryTimes(sessionServerConfig.getSubscriberRegisterFetchRetryTimes()); + } + + @Override + public String toString() { + return "WATCHER_REGISTER_FETCH_TASK{" + "taskId='" + getTaskId() + '\'' + ", watcher=" + + watcher + ", retryTimes='" + + sessionServerConfig.getSubscriberRegisterFetchRetryTimes() + '\'' + '}'; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/timertask/SyncClientsHeartbeatTask.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/timertask/SyncClientsHeartbeatTask.java new file mode 100644 index 000000000..7f2d58464 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/scheduler/timertask/SyncClientsHeartbeatTask.java @@ -0,0 +1,186 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.scheduler.timertask; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.metrics.TaskMetrics; +import com.alipay.sofa.registry.server.session.listener.ReceivedDataMultiPushTaskListener; +import com.alipay.sofa.registry.server.session.scheduler.ExecutorManager; +import com.alipay.sofa.registry.server.session.store.DataStore; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.Watchers; +import com.alipay.sofa.registry.task.batcher.AcceptorExecutor; +import com.alipay.sofa.registry.task.batcher.TaskDispatcher; +import com.alipay.sofa.registry.task.batcher.TaskDispatchers; +import com.alipay.sofa.registry.task.listener.TaskListener; +import com.codahale.metrics.Gauge; +import com.codahale.metrics.MetricRegistry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * The type Sync clients heartbeat task. + * @author zhuoyu.sjw + * @version $Id : SyncClientsHeartbeatTask.java, v 0.1 2018-03-31 16:07 zhuoyu.sjw Exp $$ + */ +public class SyncClientsHeartbeatTask { + private static final Logger CONSOLE_COUNT_LOGGER = LoggerFactory.getLogger("SESSION-CONSOLE", + "[Count]"); + + private static final Logger PRO_LOGGER = LoggerFactory.getLogger( + "SESSION-PROFILE-DIGEST", "[TaskExecute]"); + + private static final Logger EXE_LOGGER = LoggerFactory.getLogger( + "SESSION-PROFILE-DIGEST", + "[ExecutorMetrics]"); + + public static final String SYMBOLIC1 = " ├─ "; + public static final String SYMBOLIC2 = " └─ "; + + /** + * store subscribers + */ + @Autowired + private Interests sessionInterests; + + /** + * store watchers + */ + @Autowired + private Watchers sessionWatchers; + + /** + * store publishers + */ + @Autowired + private DataStore sessionDataStore; + + @Autowired + private ExecutorManager executorManager; + + @Autowired + private TaskListener receivedDataMultiPushTaskListener; + + @Scheduled(initialDelayString = "${session.server.syncHeartbeat.fixedDelay}", fixedDelayString = "${session.server.syncHeartbeat.fixedDelay}") + public void syncCounte() { + long countSub = sessionInterests.count(); + long countPub = sessionDataStore.count(); + long countSubW = sessionWatchers.count(); + + CONSOLE_COUNT_LOGGER.info("Subscriber count: {}, Publisher count: {}, Watcher count: {},", + countSub, countPub, countSubW); + } + + @Scheduled(initialDelayString = "${session.server.printTask.fixedDelay}", fixedDelayString = "${session.server.printTask.fixedDelay}") + public void printTaskExecute() { + + Map taskDispatcherMap = TaskDispatchers.getTaskDispatcherMap(); + if (taskDispatcherMap != null) { + + StringBuilder sb = new StringBuilder(); + logInfo(sb, taskDispatcherMap, "TaskDispatcher"); + PRO_LOGGER.info(sb.toString()); + } + + } + + protected void logInfo(StringBuilder sb0, Map taskDispatcherMap, + String info) { + sb0.append("\n").append(info).append(" >>>>>>>"); + StringBuilder sb = new StringBuilder(); + for (Iterator> i = taskDispatcherMap.entrySet().iterator(); i + .hasNext();) { + Entry entry = i.next(); + AcceptorExecutor acceptorExecutor = entry.getValue().getAcceptorExecutor(); + String outterTreeSymbol = SYMBOLIC1; + if (!i.hasNext()) { + outterTreeSymbol = SYMBOLIC2; + } + sb.append(outterTreeSymbol).append(entry.getKey()); + sb.append(", AcceptedTasks:").append(acceptorExecutor.getAcceptedTasks()); + sb.append(", ReplayedTasks:").append(acceptorExecutor.getReplayedTasks()); + sb.append(", QueueOverflows:").append(acceptorExecutor.getQueueOverflows()); + sb.append(" ,PendingTaskSize:").append(acceptorExecutor.getPendingTaskSize()); + sb.append(", ExpiredTasks:").append(acceptorExecutor.getExpiredTasks()); + sb.append(", OverriddenTasks:").append(acceptorExecutor.getOverriddenTasks()); + sb.append(", MaxBuffer:").append(acceptorExecutor.getMaxBufferSize()).append("\n"); + } + sb0.append("\n").append(sb); + } + + @Scheduled(initialDelayString = "${session.server.printTask.fixedDelay}", fixedDelayString = "${session.server.printTask.fixedDelay}") + public void printExecutorTaskExecute() { + + Map reportExecutors = executorManager.getReportExecutors(); + if (reportExecutors != null) { + + StringBuilder sb = new StringBuilder(); + logInfoExecutor(sb, reportExecutors, "ExecutorMetrics"); + EXE_LOGGER.info(sb.toString()); + } + + } + + protected void logInfoExecutor(StringBuilder sb0, Map reportExecutors, String info) { + sb0.append("\n").append(info).append(" >>>>>>>"); + StringBuilder sb = new StringBuilder(); + for (Iterator> i = reportExecutors.entrySet().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + String executorName = entry.getKey(); + + MetricRegistry metricRegistry = TaskMetrics.getInstance().getMetricRegistry(); + Map map = metricRegistry.getGauges((name, value) -> name.startsWith(executorName)); + + String outterTreeSymbol = SYMBOLIC1; + if (!i.hasNext()) { + outterTreeSymbol = SYMBOLIC2; + } + sb.append(outterTreeSymbol).append(executorName); + map.forEach((key, gauge) -> { + String name = key.substring(executorName.length() + 1); + sb.append(", ").append(name).append(":").append(gauge.getValue()); + }); + sb.append("\n"); + } + sb0.append("\n").append(sb); + } + + @Scheduled(initialDelayString = "${session.server.printTask.fixedDelay}", fixedDelayString = "${session.server.printTask.fixedDelay}") + public void printPushMultiTaskExecute() { + if (receivedDataMultiPushTaskListener instanceof ReceivedDataMultiPushTaskListener) { + ReceivedDataMultiPushTaskListener listener = (ReceivedDataMultiPushTaskListener) receivedDataMultiPushTaskListener; + StringBuilder sb = new StringBuilder(); + sb.append("ReceivedDataPush").append(" >>>>>>>"); + sb.append(", AcceptedTasks:").append( + listener.getTaskMergeProcessorStrategy().getPutTaskSize()); + sb.append(", SendTasks:").append( + listener.getTaskMergeProcessorStrategy().getSendTaskSize()); + sb.append(" ,PendingTaskSize:").append( + listener.getTaskMergeProcessorStrategy().getPendingTaskSize()); + sb.append(", OverriddenTasks:").append( + listener.getTaskMergeProcessorStrategy().getOverrideTaskSize()); + sb.append("\n"); + PRO_LOGGER.info(sb.toString()); + } + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataManager.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataManager.java new file mode 100644 index 000000000..5ec0bce95 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataManager.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import java.util.Map; + +/** + * Session Data store manager,according base data function + * + * Session Data struct + * + * - DataInfo ID + * | + * - Publisher List + * | + * - Subscriber List + * + * @author shangyu.wh + * @version $Id: DataManager.java, v 0.1 2017-11-30 17:57 shangyu.wh Exp $ + */ +public interface DataManager { + + /** + * new publisher and subscriber data add + * + * @param data + */ + void add(DATA data); + + /** + * remove single data by register id + * @param registerId + * @param dataInfoId + * @return + */ + boolean deleteById(ID registerId, DATAINFOID dataInfoId); + + /** + * query data by client node connectId + * + * @param connectId + * @return + */ + Map queryByConnectId(String connectId); + + /** + * remove data by client node connectId + * + * @param connectId + */ + boolean deleteByConnectId(String connectId); + + /** + * count pub and sub number + * @return + */ + long count(); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataStore.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataStore.java new file mode 100644 index 000000000..2b1fe2970 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/DataStore.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Publisher; + +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: DataStore.java, v 0.1 2017-12-01 18:13 shangyu.wh Exp $ + */ +public interface DataStore extends DataManager { + + Collection getStoreDataByDataInfoId(String dataInfoId); + + Publisher queryById(String registerId, String dataInfoId); + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Interests.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Interests.java new file mode 100644 index 000000000..3fcf99a39 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Interests.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.core.model.ScopeEnum; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: SessionInterests.java, v 0.1 2017-11-30 15:53 shangyu.wh Exp $ + */ +public interface Interests extends DataManager { + + /** + * query subscribers by dataInfoID + * + * @param dataInfoId + * @return + */ + Collection getInterests(String dataInfoId); + + /** + * check subscribers interest dataInfoId version,very dataCenter dataInfoId version different + * if return false + * else check return bigger version + * + * @param dataCenter + * @param dataInfoId + * @param version + * @return + */ + boolean checkInterestVersions(String dataCenter, String dataInfoId, Long version); + + /** + * check subscribers interest dataInfoId version,very dataCenter dataInfoId version different + * if not exist add + * else check and update big version + * + * @param dataCenter + * @param dataInfoId + * @param version + * @return + */ + boolean checkAndUpdateInterestVersions(String dataCenter, String dataInfoId, Long version); + + /** + * get all subscriber dataInfoIds + * + * @return + */ + Collection getInterestDataInfoIds(); + + /** + * get subscribers whith specify dataInfo and scope,and order by source InetSocketAddress + * @param dataInfoId + * @param scope + * @return + */ + Map> querySubscriberIndex(String dataInfoId, + ScopeEnum scope); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/ReSubscribers.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/ReSubscribers.java new file mode 100644 index 000000000..7bd3460fd --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/ReSubscribers.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Subscriber; + +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: ReSubscribers.java, v 0.1 2018-08-13 22:23 shangyu.wh Exp $ + */ +public interface ReSubscribers { + + void addReSubscriber(Subscriber subscriber); + + boolean deleteReSubscriber(Subscriber subscriber); + + Map> getReSubscribers(); + + void clearReSubscribers(); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionDataStore.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionDataStore.java new file mode 100644 index 000000000..080e46bd8 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionDataStore.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: SessionDataStore.java, v 0.1 2017-12-01 18:14 shangyu.wh Exp $ + */ +public class SessionDataStore implements DataStore { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionDataStore.class); + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock write = readWriteLock + .writeLock(); + + /** + * publisher store + */ + private Map> registry = new ConcurrentHashMap<>(); + + private Map> connectIndex = new ConcurrentHashMap<>(); + + @Override + public void add(Publisher publisher) { + + write.lock(); + try { + Map publishers = registry.get(publisher.getDataInfoId()); + + if (publishers == null) { + ConcurrentHashMap newmap = new ConcurrentHashMap<>(); + publishers = registry.putIfAbsent(publisher.getDataInfoId(), newmap); + if (publishers == null) { + publishers = newmap; + } + } + + Publisher existingPublisher = publishers.get(publisher.getRegisterId()); + + if (existingPublisher != null) { + + if (existingPublisher.getVersion() != null) { + long oldVersion = existingPublisher.getVersion(); + Long newVersion = publisher.getVersion(); + if (newVersion == null) { + LOGGER.error("There is publisher input version can't be null!"); + return; + } else if (oldVersion > newVersion) { + LOGGER + .warn( + "There is publisher already exists,but old version {} higher than input {},it will not be overwrite! {}", + oldVersion, newVersion, existingPublisher); + return; + } else if (oldVersion == newVersion) { + Long newTime = publisher.getRegisterTimestamp(); + long oldTime = existingPublisher.getRegisterTimestamp(); + if (newTime == null) { + LOGGER + .error("There is publisher input Register Timestamp can not be null!"); + return; + } + if (oldTime > newTime) { + LOGGER + .warn( + "There is publisher already exists,but old timestamp {} higher than input {},it will not be overwrite! {}", + oldTime, newTime, existingPublisher); + return; + } + } + } + LOGGER + .warn( + "There is publisher already exists,version:{},it will be overwrite!Input version:{},info:{}", + existingPublisher.getVersion(), publisher.getVersion(), existingPublisher); + } + publishers.put(publisher.getRegisterId(), publisher); + + addIndex(publisher); + + } finally { + write.unlock(); + } + } + + @Override + public boolean deleteById(String registerId, String dataInfoId) { + + write.lock(); + try { + Map publishers = registry.get(dataInfoId); + + if (publishers == null) { + LOGGER.error( + "Delete failed because publisher is not registered for dataInfoId: {}", + dataInfoId); + return false; + } else { + Publisher publisherTodelete = publishers.remove(registerId); + + if (publisherTodelete == null) { + LOGGER.error( + "Delete failed because publisher is not registered for registerId: {}", + registerId); + return false; + + } else { + removeIndex(publisherTodelete); + return true; + } + } + } finally { + write.unlock(); + } + } + + @Override + public Map queryByConnectId(String connectId) { + return connectIndex.get(connectId); + } + + @Override + public boolean deleteByConnectId(String connectId) { + + write.lock(); + try { + for (Map map : registry.values()) { + for (Iterator it = map.values().iterator(); it.hasNext();) { + Publisher publisher = (Publisher) it.next(); + if (publisher != null + && connectId.equals(publisher.getSourceAddress().getAddressString())) { + it.remove(); + invalidateIndex(publisher); + } + } + } + return true; + } catch (Exception e) { + LOGGER.error("Delete publisher by connectId {} error!", connectId, e); + return false; + } finally { + write.unlock(); + } + } + + @Override + public Collection getStoreDataByDataInfoId(String dataInfoId) { + + Map publishers = registry.get(dataInfoId); + + if (publishers == null) { + LOGGER.info("There is not registered publisher for dataInfoId: {}", dataInfoId); + return null; + } else { + return publishers.values(); + } + } + + @Override + public Publisher queryById(String registerId, String dataInfoId) { + + Map publishers = registry.get(dataInfoId); + + if (publishers == null) { + LOGGER.error("Publisher is not registered for dataInfoId: {}", dataInfoId); + return null; + } + return publishers.get(registerId); + } + + @Override + public long count() { + AtomicLong count = new AtomicLong(0); + for (Map map : registry.values()) { + count.addAndGet(map.size()); + } + return count.get(); + } + + private void addIndex(Publisher publisher) { + + addConnectIndex(publisher); + } + + private void addConnectIndex(Publisher publisher) { + + String connectId = publisher.getSourceAddress().getAddressString(); + Map publisherMap = connectIndex.get(connectId); + if (publisherMap == null) { + Map newPublisherMap = new ConcurrentHashMap<>(); + publisherMap = connectIndex.putIfAbsent(connectId, newPublisherMap); + if (publisherMap == null) { + publisherMap = newPublisherMap; + } + } + + publisherMap.put(publisher.getRegisterId(), publisher); + } + + private void removeIndex(Publisher publisher) { + removeConnectIndex(publisher); + } + + private void removeConnectIndex(Publisher publisher) { + String connectId = publisher.getSourceAddress().getAddressString(); + Map publisherMap = connectIndex.get(connectId); + if (publisherMap != null) { + publisherMap.remove(publisher.getRegisterId()); + } else { + LOGGER.warn("ConnectId {} not existed in Index to remove!", connectId); + } + } + + private void invalidateIndex(Publisher publisher) { + String connectId = publisher.getSourceAddress().getAddressString(); + invalidateConnectIndex(connectId); + } + + private void invalidateConnectIndex(String connectId) { + connectIndex.remove(connectId); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionInterests.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionInterests.java new file mode 100644 index 000000000..68341371e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionInterests.java @@ -0,0 +1,433 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.SubscriberResult; +import com.alipay.sofa.registry.util.VersionsMapUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.InetSocketAddress; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractSessionInterests.java, v 0.1 2017-11-30 20:42 shangyu.wh Exp $ + */ +public class SessionInterests implements Interests, ReSubscribers { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionInterests.class); + + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock + .readLock(); + private final Lock write = readWriteLock + .writeLock(); + + @Autowired + private SessionServerConfig sessionServerConfig; + + /** + * store all register subscriber + */ + private ConcurrentHashMap> interests = new ConcurrentHashMap<>(); + + private Map> connectIndex = new ConcurrentHashMap<>(); + + private Map>> resultIndex = new ConcurrentHashMap<>(); + + /** + * store subscriber interest dataInfo version belong one dataCenter + */ + private ConcurrentHashMap> interestVersions = new ConcurrentHashMap<>(); + + private Map> stopPushInterests = new ConcurrentHashMap<>(); + + @Override + public void add(Subscriber subscriber) { + + write.lock(); + try { + Map subscribers = interests.get(subscriber.getDataInfoId()); + + if (subscribers == null) { + Map newMap = new ConcurrentHashMap<>(); + subscribers = interests.putIfAbsent(subscriber.getDataInfoId(), newMap); + if (subscribers == null) { + subscribers = newMap; + } + } + + Subscriber existingSubscriber = subscribers.get(subscriber.getRegisterId()); + + if (existingSubscriber != null) { + LOGGER.warn("There is subscriber already exists,it will be overwrite! {}", + existingSubscriber); + } + + subscribers.put(subscriber.getRegisterId(), subscriber); + + addReSubscriber(subscriber); + + addIndex(subscriber); + + } finally { + write.unlock(); + } + + } + + @Override + public boolean deleteById(String registerId, String dataInfoId) { + + write.lock(); + try { + + Map subscribers = interests.get(dataInfoId); + + if (subscribers == null) { + LOGGER.error( + "Delete failed because subscriber is not registered for dataInfoId: {}", + dataInfoId); + return false; + } else { + Subscriber subscriberTodelete = subscribers.remove(registerId); + + if (subscriberTodelete == null) { + LOGGER.error( + "Delete failed because subscriber is not registered for registerId: {}", + registerId); + return false; + } else { + if (sessionServerConfig.isStopPushSwitch()) { + deleteReSubscriber(subscriberTodelete); + } + removeIndex(subscriberTodelete); + + return true; + } + } + } finally { + write.unlock(); + } + + } + + @Override + public boolean deleteByConnectId(String connectId) { + write.lock(); + try { + for (Map map : interests.values()) { + for (Iterator it = map.values().iterator(); it.hasNext();) { + Subscriber subscriber = (Subscriber) it.next(); + if (connectId.equals(subscriber.getSourceAddress().getAddressString())) { + + it.remove(); + if (sessionServerConfig.isStopPushSwitch()) { + deleteReSubscriber(subscriber); + } + + invalidateIndex(subscriber); + } + } + } + return true; + } catch (Exception e) { + LOGGER.error("Delete subscriber by connectId {} error!", connectId, e); + return false; + } finally { + write.unlock(); + } + } + + @Override + public long count() { + AtomicLong count = new AtomicLong(0); + for (Map map : interests.values()) { + count.addAndGet(map.size()); + } + return count.get(); + } + + @Override + public Map queryByConnectId(String connectId) { + return connectIndex.get(connectId); + } + + @Override + public Collection getInterests(String dataInfoId) { + Map subscribers = interests.get(dataInfoId); + if (subscribers == null) { + LOGGER.info("There is not registered subscriber for : {}", dataInfoId); + return null; + } + return subscribers.values(); + } + + @Override + public boolean checkInterestVersions(String dataCenter, String dataInfoId, Long version) { + + Map subscribers = interests.get(dataInfoId); + + if (subscribers == null || subscribers.isEmpty()) { + LOGGER.info("There are not Subscriber Existed! Who are interest with dataInfoId {} !", + dataInfoId); + return false; + } + + Map dataInfoVersions = interestVersions + .get(dataCenter); + if (dataInfoVersions == null) { + Map newDataInfoVersions = new ConcurrentHashMap<>(); + dataInfoVersions = interestVersions.putIfAbsent(dataCenter, newDataInfoVersions); + if (dataInfoVersions == null) { + dataInfoVersions = newDataInfoVersions; + } + } + + Long oldValue = dataInfoVersions.get(dataInfoId); + + return oldValue == null || version > oldValue; + + } + + @Override + public boolean checkAndUpdateInterestVersions(String dataCenter, String dataInfoId, Long version) { + read.lock(); + try { + + Map subscribers = interests.get(dataInfoId); + + if (subscribers == null || subscribers.isEmpty()) { + LOGGER.info( + "There are not Subscriber Existed! Who are interest with dataInfoId {} !", + dataInfoId); + return false; + } + + Map dataInfoVersions = interestVersions + .get(dataCenter); + if (dataInfoVersions == null) { + Map newDataInfoVersions = new ConcurrentHashMap<>(); + dataInfoVersions = interestVersions.putIfAbsent(dataCenter, newDataInfoVersions); + if (dataInfoVersions == null) { + dataInfoVersions = newDataInfoVersions; + } + } + + return VersionsMapUtils.checkAndUpdateVersions(dataInfoVersions, dataInfoId, version); + } finally { + read.unlock(); + } + } + + @Override + public Collection getInterestDataInfoIds() { + return interests.keySet(); + } + + private void addIndex(Subscriber subscriber) { + addConnectIndex(subscriber); + addResultIndex(subscriber); + } + + private void removeIndex(Subscriber subscriber) { + removeConnectIndex(subscriber); + removeResultIndex(subscriber); + } + + private void invalidateIndex(Subscriber subscriber) { + invalidateConnectIndex(subscriber.getSourceAddress().getAddressString()); + invalidateResultIndex(subscriber); + } + + private void addConnectIndex(Subscriber subscriber) { + + String connectId = subscriber.getSourceAddress().getAddressString(); + Map subscriberMap = connectIndex.get(connectId); + if (subscriberMap == null) { + Map newSubscriberMap = new ConcurrentHashMap<>(); + subscriberMap = connectIndex.putIfAbsent(connectId, newSubscriberMap); + if (subscriberMap == null) { + subscriberMap = newSubscriberMap; + } + } + + subscriberMap.put(subscriber.getRegisterId(), subscriber); + } + + private void addResultIndex(Subscriber subscriber) { + + SubscriberResult subscriberResult = new SubscriberResult(subscriber.getDataInfoId(), + subscriber.getScope()); + Map> mapSub = resultIndex.get(subscriberResult); + if (mapSub == null) { + Map> newMap = new ConcurrentHashMap<>(); + mapSub = resultIndex.putIfAbsent(subscriberResult, newMap); + if (mapSub == null) { + mapSub = newMap; + } + } + + InetSocketAddress address = new InetSocketAddress(subscriber.getSourceAddress() + .getIpAddress(), subscriber.getSourceAddress().getPort()); + + Map subscribers = mapSub.get(address); + if (subscribers == null) { + Map newSubs = new ConcurrentHashMap<>(); + subscribers = mapSub.putIfAbsent(address, newSubs); + if (subscribers == null) { + subscribers = newSubs; + } + } + + subscribers.put(subscriber.getRegisterId(), subscriber); + } + + private void removeConnectIndex(Subscriber subscriber) { + String connectId = subscriber.getSourceAddress().getAddressString(); + Map subscriberMap = connectIndex.get(connectId); + if (subscriberMap != null) { + subscriberMap.remove(subscriber.getRegisterId()); + } else { + LOGGER.warn("ConnectId {} not existed in Index to remove!", connectId); + } + } + + private void removeResultIndex(Subscriber subscriber) { + SubscriberResult subscriberResult = new SubscriberResult(subscriber.getDataInfoId(), + subscriber.getScope()); + Map> mapSub = resultIndex.get(subscriberResult); + if (mapSub != null) { + InetSocketAddress address = new InetSocketAddress(subscriber.getSourceAddress() + .getIpAddress(), subscriber.getSourceAddress().getPort()); + Map subscribers = mapSub.get(address); + if (subscribers != null) { + subscribers.remove(subscriber.getRegisterId()); + } else { + LOGGER.warn("InetSocketAddress {} not existed in Index to remove!", address); + } + + } else { + LOGGER.warn("SubscriberResult {} not existed in Index to remove!", subscriberResult); + } + } + + private void invalidateConnectIndex(String connectId) { + connectIndex.remove(connectId); + } + + private void invalidateResultIndex(Subscriber subscriber) { + + SubscriberResult subscriberResult = new SubscriberResult(subscriber.getDataInfoId(), + subscriber.getScope()); + Map> mapSub = resultIndex.get(subscriberResult); + if (mapSub != null) { + InetSocketAddress address = new InetSocketAddress(subscriber.getSourceAddress() + .getIpAddress(), subscriber.getSourceAddress().getPort()); + + mapSub.remove(address); + + } else { + LOGGER.warn("SubscriberResult {} not existed in Index to remove!", subscriberResult); + } + } + + @Override + public Map> querySubscriberIndex(String dataInfoId, + ScopeEnum scope) { + read.lock(); + try { + SubscriberResult subscriberResult = new SubscriberResult(dataInfoId, scope); + Map> map = resultIndex.get(subscriberResult); + if (map != null && !map.isEmpty()) { + return new ConcurrentHashMap<>(map); + } else { + return new ConcurrentHashMap<>(); + } + } finally { + read.unlock(); + } + + } + + @Override + public void addReSubscriber(Subscriber subscriber) { + if (sessionServerConfig.isStopPushSwitch()) { + + String dataInfoId = subscriber.getDataInfoId(); + + Map subscriberMap = stopPushInterests.get(dataInfoId); + if (subscriberMap == null) { + Map newMap = new ConcurrentHashMap<>(); + subscriberMap = stopPushInterests.putIfAbsent(dataInfoId, newMap); + if (subscriberMap == null) { + subscriberMap = newMap; + } + } + subscriberMap.put(subscriber.getRegisterId(), subscriber); + } + } + + @Override + public boolean deleteReSubscriber(Subscriber subscriber) { + + Map subscribers = stopPushInterests.get(subscriber.getDataInfoId()); + + if (subscribers == null) { + return false; + } else { + return subscribers.remove(subscriber.getRegisterId()) != null; + } + + } + + @Override + public Map> getReSubscribers() { + return stopPushInterests; + } + + @Override + public void clearReSubscribers() { + stopPushInterests.clear(); + } + + public SessionServerConfig getSessionServerConfig() { + return sessionServerConfig; + } + + /** + * Setter method for property sessionServerConfig. + * + * @param sessionServerConfig value to be assigned to property sessionServerConfig + */ + public void setSessionServerConfig(SessionServerConfig sessionServerConfig) { + this.sessionServerConfig = sessionServerConfig; + } +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionWatchers.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionWatchers.java new file mode 100644 index 000000000..381dbebe8 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/SessionWatchers.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.util.VersionsMapUtils; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author shangyu.wh + * @version $Id: SessionWatchers.java, v 0.1 2018-04-17 19:00 shangyu.wh Exp $ + */ +public class SessionWatchers implements Watchers { + + private static final Logger LOGGER = LoggerFactory + .getLogger(SessionWatchers.class); + + private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + private final Lock read = readWriteLock + .readLock(); + private final Lock write = readWriteLock + .writeLock(); + + /** + * store all register watchers + */ + private ConcurrentHashMap> watchers = new ConcurrentHashMap<>(); + + private Map> connectIndex = new ConcurrentHashMap<>(); + + /** + * store watcher dataInfo version + */ + private ConcurrentHashMap watcherVersions = new ConcurrentHashMap<>(); + + @Override + public void add(Watcher watcher) { + write.lock(); + try { + Map watcherMap = watchers.get(watcher.getDataInfoId()); + + if (watcherMap == null) { + Map newMap = new HashMap<>(); + watcherMap = watchers.putIfAbsent(watcher.getDataInfoId(), newMap); + if (watcherMap == null) { + watcherMap = newMap; + } + } + + Watcher existingWatcher = watcherMap.get(watcher.getRegisterId()); + + if (existingWatcher != null) { + LOGGER.warn("There is watcher already exists,it will be overwrite! {}", + existingWatcher); + } + + watcherMap.put(watcher.getRegisterId(), watcher); + + addConnectIndex(watcher); + + } finally { + write.unlock(); + } + } + + @Override + public boolean deleteByConnectId(String connectId) { + write.lock(); + try { + for (Map map : watchers.values()) { + for (Iterator it = map.values().iterator(); it.hasNext();) { + Watcher watcher = (Watcher) it.next(); + if (watcher != null + && connectId.equals(watcher.getSourceAddress().getAddressString())) { + it.remove(); + invalidateConnectIndex(watcher.getSourceAddress().getAddressString()); + } + } + } + return true; + } catch (Exception e) { + LOGGER.error("Delete watcher by connectId {} error!", connectId, e); + return false; + } finally { + write.unlock(); + } + } + + @Override + public boolean checkWatcherVersions(String dataInfoId, Long version) { + read.lock(); + try { + + Map watcherMap = watchers.get(dataInfoId); + + if (watcherMap == null || watcherMap.isEmpty()) { + LOGGER.info("There are not Watcher Existed! Who are interest with dataInfoId {} !", + dataInfoId); + return false; + } + + return VersionsMapUtils.checkAndUpdateVersions(watcherVersions, dataInfoId, version); + } finally { + read.unlock(); + } + } + + @Override + public Collection getWatchers(String dataInfoId) { + read.lock(); + try { + + if (dataInfoId == null) { + throw new IllegalArgumentException("Input dataInfoId can not be null!"); + } + Map watcherMap = watchers.get(dataInfoId); + if (watcherMap == null) { + LOGGER.info("There is not registered Watcher for : {}", dataInfoId); + return null; + } + return watcherMap.values(); + } finally { + read.unlock(); + } + } + + @Override + public boolean deleteById(String registerId, String dataInfoId) { + write.lock(); + try { + + Map watcherMap = watchers.get(dataInfoId); + + if (watcherMap == null) { + LOGGER.error("Delete failed because watcher is not registered for dataInfoId: {}", + dataInfoId); + return false; + } else { + Watcher watcher = watcherMap.remove(registerId); + + if (watcher == null) { + LOGGER.error( + "Delete failed because watcher is not registered for registerId: {}", + registerId); + return false; + } else { + removeConnectIndex(watcher); + return true; + } + } + } finally { + write.unlock(); + } + } + + @Override + public Map queryByConnectId(String connectId) { + read.lock(); + try { + return connectIndex.get(connectId); + } finally { + read.unlock(); + } + } + + @Override + public long count() { + AtomicLong count = new AtomicLong(0); + for (Map map : watchers.values()) { + count.addAndGet(map.size()); + } + return count.get(); + } + + private void addConnectIndex(Watcher watcher) { + + String connectId = watcher.getSourceAddress().getAddressString(); + Map subscriberMap = connectIndex.get(connectId); + if (subscriberMap == null) { + Map newSubscriberMap = new ConcurrentHashMap<>(); + subscriberMap = connectIndex.putIfAbsent(connectId, newSubscriberMap); + if (subscriberMap == null) { + subscriberMap = newSubscriberMap; + } + } + + subscriberMap.put(watcher.getRegisterId(), watcher); + } + + private void removeConnectIndex(Watcher watcher) { + String connectId = watcher.getSourceAddress().getAddressString(); + Map subscriberMap = connectIndex.get(connectId); + if (subscriberMap != null) { + subscriberMap.remove(watcher.getRegisterId()); + } else { + LOGGER.warn("ConnectId {} not existed in Index to invalidate!", connectId); + } + } + + private void invalidateConnectIndex(String connectId) { + connectIndex.remove(connectId); + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Watchers.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Watchers.java new file mode 100644 index 000000000..b4d401042 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/store/Watchers.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.Watcher; + +import java.util.Collection; + +/** + * + * @author shangyu.wh + * @version $Id: SessionInterests.java, v 0.1 2017-11-30 15:53 shangyu.wh Exp $ + */ +public interface Watchers extends DataManager { + + /** + * query watcher by dataInfoID + * + * @param dataInfoId + * @return + */ + Collection getWatchers(String dataInfoId); + + /** + * check watchers interest dataInfoId version + * if not exist add + * else check and update bigger one + * + * @param dataInfoId + * @param version + * @return + */ + boolean checkWatcherVersions(String dataInfoId, Long version); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/DataChangeRequestHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/DataChangeRequestHandlerStrategy.java new file mode 100644 index 000000000..3b5420455 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/DataChangeRequestHandlerStrategy.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.common.model.sessionserver.DataChangeRequest; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface DataChangeRequestHandlerStrategy { + void doFireChangFetch(DataChangeRequest dataChangeRequestExist); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/PublisherHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/PublisherHandlerStrategy.java new file mode 100644 index 000000000..09eaeaa7c --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/PublisherHandlerStrategy.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.core.model.PublisherRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.remoting.Channel; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface PublisherHandlerStrategy { + void handlePublisherRegister(Channel channel, PublisherRegister publisherRegister, + RegisterResponse registerResponse); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedConfigDataPushTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedConfigDataPushTaskStrategy.java new file mode 100644 index 000000000..f87fdf2b8 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedConfigDataPushTaskStrategy.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; + +/** + * @author xuanbei + * @since 2019/1/4 + */ +public interface ReceivedConfigDataPushTaskStrategy { + Object convert2PushData(ReceivedConfigData receivedConfigData, URL url); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedDataMultiPushTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedDataMultiPushTaskStrategy.java new file mode 100644 index 000000000..f6ce3089b --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/ReceivedDataMultiPushTaskStrategy.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; + +/** + * @author xuanbei + * @since 2019/1/4 + */ +public interface ReceivedDataMultiPushTaskStrategy { + Object convert2PushData(ReceivedData receivedData, URL url); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SessionRegistryStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SessionRegistryStrategy.java new file mode 100644 index 000000000..65f79cb29 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SessionRegistryStrategy.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.Watcher; + +import java.util.Map; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface SessionRegistryStrategy { + void doFetchChangDataProcess(Map> dataInfoIdVersions); + + void afterPublisherRegister(Publisher publisher); + + void afterSubscriberRegister(Subscriber subscriber); + + void afterWatcherRegister(Watcher watcher); + + void afterPublisherUnRegister(Publisher publisher); + + void afterSubscriberUnRegister(Subscriber subscriber); + + void afterWatcherUnRegister(Watcher watcher); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberHandlerStrategy.java new file mode 100644 index 000000000..ebaa36d68 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberHandlerStrategy.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.core.model.SubscriberRegister; +import com.alipay.sofa.registry.remoting.Channel; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface SubscriberHandlerStrategy { + void handleSubscriberRegister(Channel channel, SubscriberRegister subscriberRegister, + RegisterResponse registerResponse); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberMultiFetchTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberMultiFetchTaskStrategy.java new file mode 100644 index 000000000..8076452b5 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberMultiFetchTaskStrategy.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.util.Collection; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface SubscriberMultiFetchTaskStrategy { + void doSubscriberMultiFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + CacheService sessionCacheService, String fetchDataInfoId, + Collection subscribers); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberRegisterFetchTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberRegisterFetchTaskStrategy.java new file mode 100644 index 000000000..bd3d166b6 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SubscriberRegisterFetchTaskStrategy.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface SubscriberRegisterFetchTaskStrategy { + void doSubscriberRegisterFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + DataNodeService dataNodeService, + CacheService sessionCacheService, Subscriber subscriber); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SyncConfigHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SyncConfigHandlerStrategy.java new file mode 100644 index 000000000..a806c0143 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/SyncConfigHandlerStrategy.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.core.model.SyncConfigResponse; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface SyncConfigHandlerStrategy { + void handleSyncConfigResponse(SyncConfigResponse syncConfigResponse); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/TaskMergeProcessorStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/TaskMergeProcessorStrategy.java new file mode 100644 index 000000000..52c2879dd --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/TaskMergeProcessorStrategy.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: TaskMergeProcessorStrategy.java, v 0.1 2018-12-19 12:03 shangyu.wh Exp $ + */ +public interface TaskMergeProcessorStrategy { + + void init(T pushTaskSender); + + void handleEvent(TaskEvent event); + + AtomicInteger getPutTaskSize(); + + AtomicInteger getOverrideTaskSize(); + + AtomicInteger getSendTaskSize(); + + Integer getPendingTaskSize(); +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/WatcherHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/WatcherHandlerStrategy.java new file mode 100644 index 000000000..ff11fb645 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/WatcherHandlerStrategy.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy; + +import com.alipay.sofa.registry.core.model.ConfiguratorRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.remoting.Channel; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public interface WatcherHandlerStrategy { + void handleConfiguratorRegister(Channel channel, ConfiguratorRegister configuratorRegister, + RegisterResponse registerResponse); +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultDataChangeRequestHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultDataChangeRequestHandlerStrategy.java new file mode 100644 index 000000000..76c498598 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultDataChangeRequestHandlerStrategy.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.sessionserver.DataChangeRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.remoting.handler.DataChangeRequestHandler; +import com.alipay.sofa.registry.server.session.strategy.DataChangeRequestHandlerStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultDataChangeRequestHandlerStrategy implements DataChangeRequestHandlerStrategy { + private static final Logger taskLogger = LoggerFactory.getLogger( + DataChangeRequestHandler.class, "[Task]"); + + @Autowired + private TaskListenerManager taskListenerManager; + + @Override + public void doFireChangFetch(DataChangeRequest dataChangeRequest) { + TaskEvent taskEvent = new TaskEvent(dataChangeRequest.getDataInfoId(), + TaskEvent.TaskType.DATA_CHANGE_FETCH_CLOUD_TASK); + taskLogger.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPublisherHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPublisherHandlerStrategy.java new file mode 100644 index 000000000..4307f3859 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPublisherHandlerStrategy.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.PublisherRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.session.converter.PublisherConverter; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.remoting.handler.PublisherHandler; +import com.alipay.sofa.registry.server.session.strategy.PublisherHandlerStrategy; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultPublisherHandlerStrategy implements PublisherHandlerStrategy { + private static final Logger LOGGER = LoggerFactory.getLogger(PublisherHandler.class); + + @Autowired + private Registry sessionRegistry; + + @Override + public void handlePublisherRegister(Channel channel, PublisherRegister publisherRegister, + RegisterResponse registerResponse) { + try { + String ip = channel.getRemoteAddress().getAddress().getHostAddress(); + int port = channel.getRemoteAddress().getPort(); + publisherRegister.setIp(ip); + publisherRegister.setPort(port); + + if (StringUtils.isBlank(publisherRegister.getZone())) { + publisherRegister.setZone(ValueConstants.DEFAULT_ZONE); + } + + if (StringUtils.isBlank(publisherRegister.getInstanceId())) { + publisherRegister.setInstanceId(DEFAULT_INSTANCE_ID); + } + + Publisher publisher = PublisherConverter.convert(publisherRegister); + publisher.setProcessId(ip + ":" + port); + publisher.setSourceAddress(new URL(channel.getRemoteAddress())); + if (EventTypeConstants.REGISTER.equals(publisherRegister.getEventType())) { + sessionRegistry.register(publisher); + } else if (EventTypeConstants.UNREGISTER.equals(publisherRegister.getEventType())) { + sessionRegistry.unRegister(publisher); + } + registerResponse.setSuccess(true); + registerResponse.setVersion(publisher.getVersion()); + registerResponse.setRegistId(publisherRegister.getRegistId()); + registerResponse.setMessage("Publisher register success!"); + LOGGER.info("Publisher register success!Type:{} Info:{}", + publisherRegister.getEventType(), publisher); + } catch (Exception e) { + LOGGER.error("Publisher register error!Type {}", publisherRegister.getEventType(), e); + registerResponse.setSuccess(false); + registerResponse.setMessage("Publisher register failed!Type:" + + publisherRegister.getEventType()); + } + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPushTaskMergeProcessor.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPushTaskMergeProcessor.java new file mode 100644 index 000000000..07fa252e5 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultPushTaskMergeProcessor.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.server.session.listener.PushTaskSender; +import com.alipay.sofa.registry.server.session.strategy.TaskMergeProcessorStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + * @author shangyu.wh + * @version $Id: TaskMergeUtil.java, v 0.1 2018-12-10 18:35 shangyu.wh Exp $ + */ +public class DefaultPushTaskMergeProcessor implements + TaskMergeProcessorStrategy { + + private T pushTaskSender; + + @Override + public void init(T pushTaskSender) { + this.pushTaskSender = pushTaskSender; + } + + @Override + public void handleEvent(TaskEvent event) { + pushTaskSender.executePushAsync(event); + } + + @Override + public AtomicInteger getPutTaskSize() { + return null; + } + + @Override + public AtomicInteger getOverrideTaskSize() { + return null; + } + + @Override + public AtomicInteger getSendTaskSize() { + return null; + } + + @Override + public Integer getPendingTaskSize() { + return null; + } + +} \ No newline at end of file diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedConfigDataPushTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedConfigDataPushTaskStrategy.java new file mode 100644 index 000000000..73468fa4e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedConfigDataPushTaskStrategy.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedConfigData; +import com.alipay.sofa.registry.server.session.strategy.ReceivedConfigDataPushTaskStrategy; + +/** + * @author xuanbei + * @since 2019/1/4 + */ +public class DefaultReceivedConfigDataPushTaskStrategy implements + ReceivedConfigDataPushTaskStrategy { + @Override + public Object convert2PushData(ReceivedConfigData receivedConfigData, URL url) { + return receivedConfigData; + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedDataMultiPushTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedDataMultiPushTaskStrategy.java new file mode 100644 index 000000000..8c5fa3f4e --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultReceivedDataMultiPushTaskStrategy.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.server.session.strategy.ReceivedDataMultiPushTaskStrategy; + +/** + * @author xuanbei + * @since 2019/1/4 + */ +public class DefaultReceivedDataMultiPushTaskStrategy implements ReceivedDataMultiPushTaskStrategy { + @Override + public Object convert2PushData(ReceivedData receivedData, URL url) { + return receivedData; + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSessionRegistryStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSessionRegistryStrategy.java new file mode 100644 index 000000000..630058f56 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSessionRegistryStrategy.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.DatumKey; +import com.alipay.sofa.registry.server.session.cache.Key; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.strategy.SessionRegistryStrategy; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultSessionRegistryStrategy implements SessionRegistryStrategy { + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultSessionRegistryStrategy.class); + + private static final Logger CONSOLE_LOGGER = LoggerFactory.getLogger("SESSION-CONSOLE", + "[Task]"); + + private static final Logger taskLogger = LoggerFactory.getLogger( + DefaultSessionRegistryStrategy.class, "[Task]"); + + /** + * store subscribers + */ + @Autowired + private Interests sessionInterests; + + /** + * trigger task com.alipay.sofa.registry.server.meta.listener process + */ + @Autowired + private TaskListenerManager taskListenerManager; + + @Autowired + private SessionServerConfig sessionServerConfig; + + @Autowired + private CacheService sessionCacheService; + + @Override + public void doFetchChangDataProcess(Map> dataInfoIdVersions) { + //diff dataCenter same dataInfoId sent once fetch on cloud mode + Set changeDataInfoIds = new HashSet<>(); + dataInfoIdVersions.forEach((dataCenter, dataInfoIdMap) -> { + if (dataInfoIdMap != null) { + dataInfoIdMap.forEach((dataInfoID, version) -> { + if (checkInterestVersions(dataCenter, dataInfoID, version)) { + + //update cache + sessionCacheService.invalidate(new Key( + Key.KeyType.OBJ, DatumKey.class.getName(), new DatumKey(dataInfoID, dataCenter))); + + changeDataInfoIds.add(dataInfoID); + } + }); + } + }); + + changeDataInfoIds.forEach(this::fireDataChangeCloudTask); + } + + private boolean checkInterestVersions(String dataCenter, String dataInfoId, Long version) { + boolean result = sessionInterests.checkInterestVersions(dataCenter, dataInfoId, version); + if (result) { + LOGGER + .info( + "Request dataCenter {} dataInfo {} fetch version {} be interested,Higher than current version!Will fire data change Task", + dataCenter, dataInfoId, version); + } + return result; + } + + private void fireDataChangeCloudTask(String dataInfoId) { + //trigger fetch data for subscriber,and push to client node + TaskEvent taskEvent = new TaskEvent(dataInfoId, + TaskEvent.TaskType.DATA_CHANGE_FETCH_CLOUD_TASK); + taskLogger.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + + @Override + public void afterPublisherRegister(Publisher publisher) { + TaskEvent syncPublisherTask = new TaskEvent(publisher, + TaskEvent.TaskType.SYNC_PUBLISHER_TASK); + CONSOLE_LOGGER.info("send " + syncPublisherTask.getTaskType() + " taskEvent:{}", publisher); + taskListenerManager.sendTaskEvent(syncPublisherTask); + } + + @Override + public void afterSubscriberRegister(Subscriber subscriber) { + if (!sessionServerConfig.isStopPushSwitch()) { + //trigger fetch data for subscriber,and push to client node + TaskEvent taskEvent = new TaskEvent(subscriber, + TaskEvent.TaskType.SUBSCRIBER_REGISTER_FETCH_TASK); + taskLogger.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } + } + + @Override + public void afterWatcherRegister(Watcher watcher) { + fireWatcherRegisterFetchTask(watcher); + } + + @Override + public void afterPublisherUnRegister(Publisher publisher) { + + } + + @Override + public void afterSubscriberUnRegister(Subscriber subscriber) { + + } + + @Override + public void afterWatcherUnRegister(Watcher watcher) { + + } + + private void fireWatcherRegisterFetchTask(Watcher watcher) { + //trigger fetch data for watcher,and push to client node + TaskEvent taskEvent = new TaskEvent(watcher, TaskEvent.TaskType.WATCHER_REGISTER_FETCH_TASK); + taskLogger.info("send " + taskEvent.getTaskType() + " taskEvent:{}", taskEvent); + taskListenerManager.sendTaskEvent(taskEvent); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberHandlerStrategy.java new file mode 100644 index 000000000..52eb4de74 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberHandlerStrategy.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.core.model.SubscriberRegister; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.bolt.BoltChannelUtil; +import com.alipay.sofa.registry.server.session.converter.SubscriberConverter; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.strategy.SubscriberHandlerStrategy; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultSubscriberHandlerStrategy implements SubscriberHandlerStrategy { + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultSubscriberHandlerStrategy.class); + + @Autowired + private Registry sessionRegistry; + + @Override + public void handleSubscriberRegister(Channel channel, SubscriberRegister subscriberRegister, + RegisterResponse registerResponse) { + try { + String ip = channel.getRemoteAddress().getAddress().getHostAddress(); + int port = channel.getRemoteAddress().getPort(); + subscriberRegister.setIp(ip); + subscriberRegister.setPort(port); + + if (StringUtils.isBlank(subscriberRegister.getZone())) { + subscriberRegister.setZone(ValueConstants.DEFAULT_ZONE); + } + + if (StringUtils.isBlank(subscriberRegister.getInstanceId())) { + subscriberRegister.setInstanceId(DEFAULT_INSTANCE_ID); + } + + Subscriber subscriber = SubscriberConverter.convert(subscriberRegister); + subscriber.setProcessId(ip + ":" + port); + subscriber.setSourceAddress(new URL(channel.getRemoteAddress(), BoltChannelUtil + .getBoltCustomSerializer(channel))); + + if (EventTypeConstants.REGISTER.equals(subscriberRegister.getEventType())) { + sessionRegistry.register(subscriber); + } else if (EventTypeConstants.UNREGISTER.equals(subscriberRegister.getEventType())) { + sessionRegistry.unRegister(subscriber); + } + registerResponse.setVersion(subscriberRegister.getVersion()); + registerResponse.setRegistId(subscriberRegister.getRegistId()); + LOGGER.info("Subscriber register success! Type:{} Info:{}", + subscriberRegister.getEventType(), subscriber); + registerResponse.setSuccess(true); + registerResponse.setMessage("Subscriber register success!"); + } catch (Exception e) { + LOGGER.error("Subscriber register error!Type{}", subscriberRegister.getEventType(), e); + registerResponse.setSuccess(false); + registerResponse.setMessage("Subscriber register failed!"); + } + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberMultiFetchTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberMultiFetchTaskStrategy.java new file mode 100644 index 000000000..a33637d65 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberMultiFetchTaskStrategy.java @@ -0,0 +1,244 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.BaseInfo; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.DatumKey; +import com.alipay.sofa.registry.server.session.cache.Key; +import com.alipay.sofa.registry.server.session.cache.Value; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.node.NodeManager; +import com.alipay.sofa.registry.server.session.node.NodeManagerFactory; +import com.alipay.sofa.registry.server.session.scheduler.task.Constant; +import com.alipay.sofa.registry.server.session.strategy.SubscriberMultiFetchTaskStrategy; +import com.alipay.sofa.registry.server.session.utils.DatumUtils; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultSubscriberMultiFetchTaskStrategy implements SubscriberMultiFetchTaskStrategy { + private static final Logger taskLogger = LoggerFactory.getLogger( + DefaultSubscriberMultiFetchTaskStrategy.class, + "[Task]"); + + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultSubscriberMultiFetchTaskStrategy.class); + + @Override + public void doSubscriberMultiFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + CacheService sessionCacheService, + String fetchDataInfoId, + Collection subscribers) { + Map datumMap = getDatumsCache(fetchDataInfoId, + sessionCacheService); + + if (datumMap != null) { + + for (ScopeEnum scopeEnum : ScopeEnum.values()) { + Map> map = getPushSubscribers(scopeEnum, + subscribers); + + if (map != null && !map.isEmpty()) { + for (Map.Entry> entry : map + .entrySet()) { + Map subscriberMap = entry.getValue(); + if (subscriberMap != null && !subscriberMap.isEmpty()) { + Subscriber subscriber = subscriberMap.values().iterator().next(); + boolean isOldVersion = !BaseInfo.ClientVersion.StoreData + .equals(subscriber.getClientVersion()); + + if (isOldVersion) { + fireUserDataPushTaskCloud(entry.getKey(), datumMap, + subscriberMap.values(), subscriber, taskListenerManager); + } else { + fireReceivedDataPushTaskCloud(datumMap, + new ArrayList(subscriberMap.keySet()), subscriber, + taskListenerManager); + } + } + } + } + } + + } else { + //TODO EMPTY push empty + LOGGER.error( + "SubscriberMultiFetchTask cloud Get publisher data error,which dataInfoId:{}", + fetchDataInfoId); + } + } + + private Map getDatumsCache(String fetchDataInfoId, CacheService sessionCacheService) { + + Map map = new HashMap<>(); + NodeManager nodeManager = NodeManagerFactory.getNodeManager(Node.NodeType.META); + Collection dataCenters = nodeManager.getDataCenters(); + if (dataCenters != null) { + Collection keys = dataCenters.stream(). + map(dataCenter -> new Key(Key.KeyType.OBJ, DatumKey.class.getName(), + new DatumKey(fetchDataInfoId, dataCenter))). + collect(Collectors.toList()); + + Map values = sessionCacheService.getValues(keys); + + if (values != null) { + values.forEach((key, value) -> { + if (value != null && value.getPayload() != null) { + Datum datum = (Datum) value.getPayload(); + String dataCenter = ((DatumKey) key.getEntityType()).getDataCenter(); + map.put(dataCenter, datum); + } + }); + } + + } + return map; + } + + private Map> getPushSubscribers(ScopeEnum scopeEnum, + Collection subscribers) { + + Map> payload = new HashMap<>(); + + subscribers.forEach((subscriber) -> { + + if (subscriber.getScope().equals(scopeEnum)) { + InetSocketAddress address = new InetSocketAddress( + subscriber.getSourceAddress().getIpAddress(), + subscriber.getSourceAddress().getPort()); + Map map = payload.computeIfAbsent(address, k -> new HashMap<>()); + map.put(subscriber.getRegisterId(), subscriber); + payload.put(address, map); + } + }); + + return payload; + } + + private void fireUserDataPushTaskCloud(InetSocketAddress address, + Map datumMap, + Collection subscribers, + Subscriber subscriber, + TaskListenerManager taskListenerManager) { + Datum merge = null; + if (datumMap != null && !datumMap.isEmpty()) { + merge = ReceivedDataConverter.getMergeDatum(datumMap); + } + + ScopeEnum scopeEnum = subscriber.getScope(); + + if (scopeEnum == ScopeEnum.zone) { + fireUserDataElementPushTask(address, merge, subscribers, subscriber, + taskListenerManager); + } else { + fireUserDataElementMultiPushTask(address, merge, subscribers, subscriber, + taskListenerManager); + } + } + + private void fireUserDataElementPushTask(InetSocketAddress address, Datum datum, + Collection subscribers, + Subscriber subscriber, + TaskListenerManager taskListenerManager) { + datum = DatumUtils.newDatumIfNull(datum, subscriber); + TaskEvent taskEvent = new TaskEvent(TaskEvent.TaskType.USER_DATA_ELEMENT_PUSH_TASK); + + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, new URL(address)); + + int size = datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), address, datum.getDataInfoId(), datum.getDataCenter(), size, + subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataElementMultiPushTask(InetSocketAddress address, Datum datum, + Collection subscribers, + Subscriber subscriber, + TaskListenerManager taskListenerManager) { + datum = DatumUtils.newDatumIfNull(datum, subscriber); + TaskEvent taskEvent = new TaskEvent(TaskEvent.TaskType.USER_DATA_ELEMENT_MULTI_PUSH_TASK); + + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, new URL(address)); + + int size = datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={},subSize={}", + taskEvent.getTaskType(), address, datum.getDataInfoId(), datum.getDataCenter(), size, + subscribers.size()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireReceivedDataPushTaskCloud(Map datumMap, + List subscriberRegisterIdList, + Subscriber subscriber, + TaskListenerManager taskListenerManager) { + + ReceivedData receivedData; + if (datumMap != null && !datumMap.isEmpty()) { + + receivedData = ReceivedDataConverter.getReceivedDataMulti(datumMap, + subscriber.getScope(), subscriberRegisterIdList, subscriber); + + } + //no datum + else { + receivedData = ReceivedDataConverter.getReceivedDataMulti(subscriber.getDataId(), + subscriber.getGroup(), subscriber.getInstanceId(), + ValueConstants.DEFAULT_DATA_CENTER, subscriber.getScope(), + subscriberRegisterIdList, subscriber.getCell()); + + } + + //trigger push to client node + Map parameter = new HashMap<>(); + parameter.put(receivedData, subscriber.getSourceAddress()); + TaskEvent taskEvent = new TaskEvent(parameter, + TaskEvent.TaskType.RECEIVED_DATA_MULTI_PUSH_TASK); + taskLogger.info("send {} taskURL:{},taskScope:{}", taskEvent.getTaskType(), + subscriber.getSourceAddress(), subscriber.getScope()); + taskListenerManager.sendTaskEvent(taskEvent); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberRegisterFetchTaskStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberRegisterFetchTaskStrategy.java new file mode 100644 index 000000000..0c7f1ac91 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSubscriberRegisterFetchTaskStrategy.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.BaseInfo; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ReceivedData; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.converter.ReceivedDataConverter; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.server.session.scheduler.task.Constant; +import com.alipay.sofa.registry.server.session.strategy.SubscriberRegisterFetchTaskStrategy; +import com.alipay.sofa.registry.server.session.utils.DatumUtils; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultSubscriberRegisterFetchTaskStrategy implements + SubscriberRegisterFetchTaskStrategy { + private static final Logger taskLogger = LoggerFactory.getLogger( + DefaultSubscriberRegisterFetchTaskStrategy.class, + "[Task]"); + + @Override + public void doSubscriberRegisterFetchTask(SessionServerConfig sessionServerConfig, + TaskListenerManager taskListenerManager, + DataNodeService dataNodeService, + CacheService sessionCacheService, + Subscriber subscriber) { + if (subscriber == null) { + throw new IllegalArgumentException("Subscriber can not be null!"); + } + + List subscriberRegisterIdList = Collections.singletonList(subscriber + .getRegisterId()); + + boolean isOldVersion = !BaseInfo.ClientVersion.StoreData.equals(subscriber + .getClientVersion()); + + Map datumMap = dataNodeService.fetchGlobal(subscriber + .getDataInfoId()); + if (!isOldVersion) { + fireReceivedDataPushTaskCloud(datumMap, subscriberRegisterIdList, subscriber, + taskListenerManager); + } else { + fireUserDataPushTaskCloud(datumMap, subscriber, taskListenerManager); + } + } + + private void fireReceivedDataPushTaskCloud(Map datumMap, + List subscriberRegisterIdList, + Subscriber subscriber, + TaskListenerManager taskListenerManager) { + ReceivedData receivedData; + if (datumMap != null && !datumMap.isEmpty()) { + + receivedData = ReceivedDataConverter.getReceivedDataMulti(datumMap, + subscriber.getScope(), subscriberRegisterIdList, subscriber); + + } + //no datum + else { + receivedData = ReceivedDataConverter.getReceivedDataMulti(subscriber.getDataId(), + subscriber.getGroup(), subscriber.getInstanceId(), + ValueConstants.DEFAULT_DATA_CENTER, subscriber.getScope(), + subscriberRegisterIdList, subscriber.getCell()); + + } + + firePush(receivedData, subscriber, taskListenerManager); + } + + private void firePush(ReceivedData receivedData, Subscriber subscriber, + TaskListenerManager taskListenerManager) { + //trigger push to client node + Map parameter = new HashMap<>(); + parameter.put(receivedData, subscriber.getSourceAddress()); + TaskEvent taskEvent = new TaskEvent(parameter, + TaskEvent.TaskType.RECEIVED_DATA_MULTI_PUSH_TASK); + taskLogger.info("send {} taskURL:{},taskScope:{}", taskEvent.getTaskType(), + subscriber.getSourceAddress(), receivedData.getScope()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataPushTaskCloud(Map datumMap, Subscriber subscriber, + TaskListenerManager taskListenerManager) { + Datum merge = null; + if (datumMap != null && !datumMap.isEmpty()) { + merge = ReceivedDataConverter.getMergeDatum(datumMap); + } + + if (subscriber.getScope() == ScopeEnum.zone) { + fireUserDataElementPushTask(merge, subscriber, taskListenerManager); + } else { + fireUserDataElementMultiPushTask(merge, subscriber, taskListenerManager); + } + } + + private void fireUserDataElementPushTask(Datum datum, Subscriber subscriber, + TaskListenerManager taskListenerManager) { + datum = DatumUtils.newDatumIfNull(datum, subscriber); + Collection subscribers = new ArrayList<>(); + subscribers.add(subscriber); + + TaskEvent taskEvent = new TaskEvent(subscriber, + TaskEvent.TaskType.USER_DATA_ELEMENT_PUSH_TASK); + + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, subscriber.getSourceAddress()); + + int size = datum.getPubMap() != null ? datum.getPubMap().size() : 0; + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={}", + taskEvent.getTaskType(), subscriber.getSourceAddress(), datum.getDataInfoId(), + datum.getDataCenter(), size); + taskListenerManager.sendTaskEvent(taskEvent); + } + + private void fireUserDataElementMultiPushTask(Datum datum, Subscriber subscriber, + TaskListenerManager taskListenerManager) { + datum = DatumUtils.newDatumIfNull(datum, subscriber); + Collection subscribers = new ArrayList<>(); + subscribers.add(subscriber); + + TaskEvent taskEvent = new TaskEvent(subscriber, + TaskEvent.TaskType.USER_DATA_ELEMENT_MULTI_PUSH_TASK); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers); + taskEvent.setAttribute(Constant.PUSH_CLIENT_DATUM, datum); + taskEvent.setAttribute(Constant.PUSH_CLIENT_URL, subscriber.getSourceAddress()); + + int size = datum.getPubMap() != null ? datum.getPubMap().size() : 0; + + taskLogger.info("send {} taskURL:{},dataInfoId={},dataCenter={},pubSize={}", + taskEvent.getTaskType(), subscriber.getSourceAddress(), datum.getDataInfoId(), + datum.getDataCenter(), size); + taskListenerManager.sendTaskEvent(taskEvent); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSyncConfigHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSyncConfigHandlerStrategy.java new file mode 100644 index 000000000..bac43a754 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultSyncConfigHandlerStrategy.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.core.model.SyncConfigResponse; +import com.alipay.sofa.registry.server.session.strategy.SyncConfigHandlerStrategy; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultSyncConfigHandlerStrategy implements SyncConfigHandlerStrategy { + @Override + public void handleSyncConfigResponse(SyncConfigResponse syncConfigResponse) { + List list = new ArrayList<>(); + list.add(ValueConstants.DEFAULT_DATA_CENTER); + syncConfigResponse.setAvailableSegments(list); + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultWatcherHandlerStrategy.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultWatcherHandlerStrategy.java new file mode 100644 index 000000000..fb9c7ec62 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/strategy/impl/DefaultWatcherHandlerStrategy.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.strategy.impl; + +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.common.model.store.Watcher; +import com.alipay.sofa.registry.core.constants.EventTypeConstants; +import com.alipay.sofa.registry.core.model.ConfiguratorRegister; +import com.alipay.sofa.registry.core.model.RegisterResponse; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.bolt.BoltChannelUtil; +import com.alipay.sofa.registry.server.session.converter.SubscriberConverter; +import com.alipay.sofa.registry.server.session.registry.Registry; +import com.alipay.sofa.registry.server.session.strategy.WatcherHandlerStrategy; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; + +/** + * @author xuanbei + * @since 2019/2/15 + */ +public class DefaultWatcherHandlerStrategy implements WatcherHandlerStrategy { + private static final Logger LOGGER = LoggerFactory + .getLogger(DefaultWatcherHandlerStrategy.class); + + @Autowired + private Registry sessionRegistry; + + @Override + public void handleConfiguratorRegister(Channel channel, + ConfiguratorRegister configuratorRegister, + RegisterResponse registerResponse) { + try { + configuratorRegister.setIp(channel.getRemoteAddress().getAddress().getHostAddress()); + configuratorRegister.setPort(channel.getRemoteAddress().getPort()); + + if (StringUtils.isBlank(configuratorRegister.getInstanceId())) { + configuratorRegister.setInstanceId(DEFAULT_INSTANCE_ID); + } + + Watcher watcher = SubscriberConverter.convert(configuratorRegister); + watcher.setProcessId(channel.getRemoteAddress().getHostName() + ":" + + channel.getRemoteAddress().getPort()); + watcher.setSourceAddress(new URL(channel.getRemoteAddress(), BoltChannelUtil + .getBoltCustomSerializer(channel))); + + if (EventTypeConstants.REGISTER.equals(configuratorRegister.getEventType())) { + sessionRegistry.register(watcher); + } else if (EventTypeConstants.UNREGISTER.equals(configuratorRegister.getEventType())) { + sessionRegistry.unRegister(watcher); + } + registerResponse.setVersion(configuratorRegister.getVersion()); + registerResponse.setRegistId(configuratorRegister.getRegistId()); + LOGGER.info("ConfiguratorRegister register success! {}", watcher); + registerResponse.setSuccess(true); + registerResponse.setMessage("ConfiguratorRegister register success!"); + } catch (Exception e) { + LOGGER.error("ConfiguratorRegister register error!", e); + registerResponse.setSuccess(false); + registerResponse.setMessage("ConfiguratorRegister register failed!"); + } + } +} diff --git a/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/utils/DatumUtils.java b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/utils/DatumUtils.java new file mode 100644 index 000000000..e73398a75 --- /dev/null +++ b/server/server/session/src/main/java/com/alipay/sofa/registry/server/session/utils/DatumUtils.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.utils; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Subscriber; + +import java.util.HashMap; + +/** + * @author xuanbei + * @since 2019/2/12 + */ +public class DatumUtils { + /** + * create new datum when parameter is null. + * + * @param datum + * @param subscriber + * @return + */ + public static Datum newDatumIfNull(Datum datum, Subscriber subscriber) { + if (datum == null) { + datum = new Datum(); + datum.setDataId(subscriber.getDataId()); + datum.setInstanceId(subscriber.getInstanceId()); + datum.setGroup(subscriber.getGroup()); + datum.setVersion(ValueConstants.DEFAULT_NO_DATUM_VERSION); + datum.setPubMap(new HashMap<>()); + datum.setDataCenter(ValueConstants.DEFAULT_DATA_CENTER); + } + return datum; + } +} diff --git a/server/server/session/src/main/resources/application.properties b/server/server/session/src/main/resources/application.properties new file mode 100644 index 000000000..9df254384 --- /dev/null +++ b/server/server/session/src/main/resources/application.properties @@ -0,0 +1,30 @@ +spring.main.banner-mode=LOG +#nodes.metaNode=: +#nodes.localDataCenter= +#nodes.localRegion= + +#session.server.logging.level=INFO +#session.server.logging.home=/home/admin/logs/registry/session +session.server.serverPort=9600 +session.server.serverSyncPort=9601 +session.server.httpServerPort=9603 +session.server.metaServerPort=9610 +session.server.dataServerPort=9620 +session.server.serverDescription=dev session server +session.server.sessionServerRegion=DEFAULT_ZONE +session.server.sessionServerDataCenter=DefaultDataCenter +session.server.syncHeartbeat.fixedDelay=30000 +session.server.syncExceptionData.fixedDelay=30000 +session.server.printTask.fixedDelay=30000 +session.server.schedulerCheckVersionTimeout=3 +session.server.schedulerCheckVersionFirstDelay=3 +session.server.schedulerCheckVersionExpBackOffBound=10 +session.server.schedulerHeartbeatTimeout=30 +session.server.schedulerHeartbeatFirstDelay=30 +session.server.schedulerHeartbeatExpBackOffBound=10 +session.server.schedulerFetchDataTimeout=3 +session.server.schedulerFetchDataFirstDelay=3 +session.server.schedulerFetchDataExpBackOffBound=10 +#session.server.invalidForeverZones=; +#session.server.invalidIgnoreDataidRegex= +#session.server.pushEmptyDataDataIdPrefixes= \ No newline at end of file diff --git a/server/server/session/src/main/resources/banner.txt b/server/server/session/src/main/resources/banner.txt new file mode 100644 index 000000000..723c532b3 --- /dev/null +++ b/server/server/session/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + + ____ _ ____ + / ___| ___ ___ ___(_) ___ _ __ / ___| ___ _ ____ _____ _ __ + \___ \ / _ \/ __/ __| |/ _ \| '_ \ \___ \ / _ \ '__\ \ / / _ \ '__| + ___) | __/\__ \__ \ | (_) | | | | ___) | __/ | \ V / __/ | + |____/ \___||___/___/_|\___/|_| |_| |____/ \___|_| \_/ \___|_| + \ No newline at end of file diff --git a/server/server/session/src/main/resources/logback-spring.xml b/server/server/session/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..7df0a5104 --- /dev/null +++ b/server/server/session/src/main/resources/logback-spring.xml @@ -0,0 +1,301 @@ + + + + + + + + + + + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + + + + + true + + ERROR + + ${SESSION_LOG_HOME}/common-error.log + + ${SESSION_LOG_HOME}/common-error.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/common-default.log + + ${SESSION_LOG_HOME}/common-default.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-raft.log + + ${SESSION_LOG_HOME}/registry-raft.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-session.log + + ${SESSION_LOG_HOME}/registry-session.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-startup.log + + ${SESSION_LOG_HOME}/registry-startup.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-connect.log + + ${SESSION_LOG_HOME}/registry-connect.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-console.log + + ${SESSION_LOG_HOME}/registry-console.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-exchange.log + + ${SESSION_LOG_HOME}/registry-exchange.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-push.log + + ${SESSION_LOG_HOME}/registry-push.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ERROR + + ${SESSION_LOG_HOME}/common-push-error.log + + ${SESSION_LOG_HOME}/common-push-error.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${SESSION_LOG_HOME}/registry-profile-digest.log + + ${SESSION_LOG_HOME}/registry-profile-digest.log.%d{yyyy-MM-dd} + 10 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + 0 + 65536 + + + + + 0 + 65536 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/DatumUtilsTest.java b/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/DatumUtilsTest.java new file mode 100644 index 000000000..68e326fd3 --- /dev/null +++ b/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/DatumUtilsTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session; + +import com.alipay.sofa.registry.common.model.constants.ValueConstants; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.server.session.utils.DatumUtils; +import org.junit.Assert; +import org.junit.Test; + +/** + @author xuanbei + @since 2019/2/12 + */ +public class DatumUtilsTest { + @Test + public void testNewDatumIfNull() { + Datum datum = new Datum(); + datum.setVersion(19092L); + datum.setDataId("test-dataId"); + datum.setDataCenter("test-dataCenter"); + + Subscriber subscriber = new Subscriber(); + subscriber.setDataId("subscriber-dataId"); + subscriber.setGroup("DEFAULT_GROUP"); + + datum = DatumUtils.newDatumIfNull(datum, subscriber); + Assert.assertEquals(19092L, datum.getVersion()); + Assert.assertEquals("test-dataId", datum.getDataId()); + Assert.assertEquals("test-dataCenter", datum.getDataCenter()); + Assert.assertEquals(null, datum.getGroup()); + + datum = DatumUtils.newDatumIfNull(null, subscriber); + Assert.assertEquals(ValueConstants.DEFAULT_NO_DATUM_VERSION, datum.getVersion()); + Assert.assertEquals("subscriber-dataId", datum.getDataId()); + Assert.assertEquals(ValueConstants.DEFAULT_DATA_CENTER, datum.getDataCenter()); + Assert.assertEquals("DEFAULT_GROUP", datum.getGroup()); + } +} diff --git a/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/BaseTest.java b/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/BaseTest.java new file mode 100644 index 000000000..e77a07aae --- /dev/null +++ b/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/BaseTest.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import org.springframework.boot.SpringBootConfiguration; + +/** + * + * @author shangyu.wh + * @version $Id: BaseTest.java, v 0.1 2017-12-14 21:47 shangyu.wh Exp $ + */ +@SpringBootConfiguration +public class BaseTest { +} \ No newline at end of file diff --git a/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/DataCacheTest.java b/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/DataCacheTest.java new file mode 100644 index 000000000..8ca0f69d0 --- /dev/null +++ b/server/server/session/src/test/java/com/alipay/sofa/registry/server/session/store/DataCacheTest.java @@ -0,0 +1,259 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.session.store; + +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfigBean; +import com.alipay.sofa.registry.server.session.cache.CacheGenerator; +import com.alipay.sofa.registry.server.session.cache.CacheService; +import com.alipay.sofa.registry.server.session.cache.SessionCacheService; +import org.junit.Assert; +import org.junit.Test; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; + +/** + * + * @author shangyu.wh + * @version $Id: DataCacheTest.java, v 0.1 2017-12-06 19:42 shangyu.wh Exp $ + */ + +public class DataCacheTest extends BaseTest { + + private AtomicLong version = new AtomicLong(1); + + private AtomicLong registId = new AtomicLong(1000); + + @Test + public void testGetSub() { + SessionInterests sessionInterests = new SessionInterests(); + sessionInterests.setSessionServerConfig(new SessionServerConfigBean(null)); + + String dataId = "dataid"; + String connectId = "192.168.1.2:9000"; + + for (int i = 0; i < 100; i++) { + sessionInterests.add(getSub(dataId, ScopeEnum.zone, null, null)); + } + //add other ip + sessionInterests.add(getSub(dataId, ScopeEnum.zone, null, new URL("192.168.1.9", 8000))); + + Map> map = getCacheSub( + DataInfo.toDataInfoId(dataId, "instance2", "rpc"), ScopeEnum.zone, sessionInterests); + Assert.assertTrue(getCacheSub(sessionInterests, connectId)); + + sessionInterests.deleteByConnectId(connectId); + + Map> map2 = getCacheSub( + DataInfo.toDataInfoId(dataId, "instance2", "rpc"), ScopeEnum.zone, sessionInterests); + + Assert.assertFalse(getCacheSub(sessionInterests, connectId)); + + //map no change + Assert.assertEquals(2, map.size()); + + //get cache change,just remain 192.168.1.9:8000 + Assert.assertEquals(map2.keySet().size(), 1); + Assert.assertEquals(NetUtil.toAddressString(map2.keySet().iterator().next()), + "192.168.1.9:8000"); + } + + @Test + public void testDeleteSubById() { + SessionInterests sessionInterests = new SessionInterests(); + sessionInterests.setSessionServerConfig(new SessionServerConfigBean(null)); + + String dataId = "dataid"; + + for (int i = 0; i < 100; i++) { + + sessionInterests.add(getSub(dataId, ScopeEnum.zone, null, null)); + } + //add other ip + sessionInterests.add(getSub(dataId, ScopeEnum.zone, "xxregist123", new URL("192.168.1.9", + 8000))); + //sessionInterests.add(getSub(dataId,ScopeEnum.zone,"xxregist456",new URL("192.168.1.10", 7000))); + + Map> map = getCacheSub( + DataInfo.toDataInfoId(dataId, "instance2", "rpc"), ScopeEnum.zone, sessionInterests); + Assert.assertTrue(getCacheSub(sessionInterests, "192.168.1.9:8000")); + + sessionInterests.deleteById("xxregist123", + DataInfo.toDataInfoId(dataId, "instance2", "rpc")); + + Map> map2 = getCacheSub( + DataInfo.toDataInfoId(dataId, "instance2", "rpc"), ScopeEnum.zone, sessionInterests); + + Assert.assertFalse(getCacheSub(sessionInterests, "192.168.1.9:8000")); + //map no change + Assert.assertEquals(2, map.size()); + + //remain 100 + Assert.assertEquals(map2.keySet().size(), 2); + + InetSocketAddress address = new InetSocketAddress("192.168.1.2", 9000); + InetSocketAddress addressDel = new InetSocketAddress("192.168.1.9", 8000); + Assert.assertFalse(map2.get(address).isEmpty()); + + Assert.assertFalse(!map2.get(addressDel).isEmpty()); + + //Assert.assertEquals(NetUtil.toAddressString(map2.keySet().iterator().next()),"192.168.1.2:9000"); + Assert.assertEquals(map2.get(address).size(), 100); + } + + @Test + public void testGetPub() { + SessionDataStore sessionDataStore = new SessionDataStore(); + CacheService cacheService = new SessionCacheService(); + + Map cacheGenerators = new HashMap<>(); + ((SessionCacheService) cacheService).setCacheGenerators(cacheGenerators); + + String dataId = "dataid"; + String connectId = "192.168.1.2:9000"; + for (int i = 0; i < 10; i++) { + + sessionDataStore.add(getPub(dataId, null, null)); + } + + Assert.assertTrue(getCachePub(sessionDataStore, connectId)); + sessionDataStore.deleteByConnectId(connectId); + Assert.assertFalse(getCachePub(sessionDataStore, connectId)); + } + + @Test + public void testGetPubRefresh() { + SessionDataStore sessionDataStore = new SessionDataStore(); + CacheService cacheService = new SessionCacheService(); + + Map cacheGenerators = new HashMap<>(); + ((SessionCacheService) cacheService).setCacheGenerators(cacheGenerators); + + String dataId = "dataid"; + String connectId = "192.168.1.2:9000"; + int number = 1000; + ExecutorService executorService = Executors.newFixedThreadPool(number); + + for (int i = 0; i < number; i++) { + String connectIdss = "192.111.0.1:" + (8000 + i); + executorService.submit(() -> { + sessionDataStore.add(getPub(dataId, null, URL.valueOf(connectIdss))); + Assert.assertTrue(getCachePub(sessionDataStore, connectIdss)); + }); + } + + Assert.assertFalse(getCachePub(sessionDataStore, connectId)); + } + + @Test + public void testDelPubById() { + SessionDataStore sessionDataStore = new SessionDataStore(); + CacheService cacheService = new SessionCacheService(); + + Map cacheGenerators = new HashMap<>(); + ((SessionCacheService) cacheService).setCacheGenerators(cacheGenerators); + + String dataId = "dataid"; + String connectId = "192.168.1.2:9000"; + for (int i = 0; i < 10; i++) { + + sessionDataStore.add(getPub(dataId, null, null)); + } + + sessionDataStore.add(getPub(dataId, "XXXX", new URL("192.168.1.9", 8000))); + + Assert.assertTrue(getCachePub(sessionDataStore, connectId)); + Assert.assertTrue(getCachePub(sessionDataStore, "192.168.1.9:8000")); + sessionDataStore.deleteById("XXXX", DataInfo.toDataInfoId(dataId, "instance2", "rpc")); + Assert.assertTrue(getCachePub(sessionDataStore, connectId)); + Assert.assertFalse(getCachePub(sessionDataStore, "192.168.1.9:8000")); + } + + private boolean getCachePub(SessionDataStore sessionDataStore, String connectId) { + Map map = sessionDataStore.queryByConnectId(connectId); + return map != null && !map.isEmpty(); + } + + private boolean getCacheSub(SessionInterests sessionInterests, String connectId) { + Map map = sessionInterests.queryByConnectId(connectId); + return map != null && !map.isEmpty(); + } + + private Map> getCacheSub(String dataInfoId, + ScopeEnum scopeEnum, + SessionInterests sessionInterests) { + + return sessionInterests.querySubscriberIndex(dataInfoId, scopeEnum); + } + + private Subscriber getSub(String dataId, ScopeEnum scopeEnum, String registerId, URL url) { + + String processid = "4466"; + + Subscriber subscriberRegister = new Subscriber(); + subscriberRegister.setAppName("app"); + subscriberRegister.setCell("My zone"); + subscriberRegister.setClientId("clientid" + version.get()); + subscriberRegister.setDataId(dataId); + subscriberRegister.setGroup("rpc"); + subscriberRegister.setInstanceId("instance2"); + subscriberRegister.setRegisterId(registerId == null ? String.valueOf(registId + .incrementAndGet()) : registerId); + subscriberRegister.setProcessId(processid); + subscriberRegister.setVersion(version.get()); + subscriberRegister.setRegisterTimestamp(System.currentTimeMillis()); + subscriberRegister.setScope(scopeEnum); + subscriberRegister.setDataInfoId(DataInfo.toDataInfoId(dataId, "instance2", "rpc")); + + subscriberRegister.setSourceAddress(url == null ? new URL("192.168.1.2", 9000) : url); + + return subscriberRegister; + } + + private Publisher getPub(String dataId, String registerId, URL url) { + + String processid = "4466"; + + Publisher publisher = new Publisher(); + publisher.setAppName("app"); + publisher.setCell("My zone"); + publisher.setClientId("clientid" + version.get()); + publisher.setDataId(dataId); + publisher.setGroup("rpc"); + publisher.setInstanceId("instance2"); + publisher.setRegisterId(registerId == null ? String.valueOf(registId.incrementAndGet()) + : registerId); + publisher.setProcessId(processid); + publisher.setVersion(version.get()); + publisher.setRegisterTimestamp(System.currentTimeMillis()); + publisher.setDataInfoId(DataInfo.toDataInfoId(dataId, "instance2", "rpc")); + + publisher.setSourceAddress(url == null ? new URL("192.168.1.2", 9000) : url); + + return publisher; + } +} \ No newline at end of file diff --git a/server/server/session/src/test/resources/logback-test.xml b/server/server/session/src/test/resources/logback-test.xml new file mode 100644 index 000000000..5598cba71 --- /dev/null +++ b/server/server/session/src/test/resources/logback-test.xml @@ -0,0 +1,27 @@ + + + + + + \ No newline at end of file diff --git a/server/store/api/pom.xml b/server/store/api/pom.xml new file mode 100644 index 000000000..ab28b3dd8 --- /dev/null +++ b/server/store/api/pom.xml @@ -0,0 +1,26 @@ + + + + com.alipay.sofa + registry-store + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-store-api + + + ../../../ + + + + + com.alipay.sofa + registry-common-model + + + + diff --git a/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBResponse.java b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBResponse.java new file mode 100644 index 000000000..4c3bcb923 --- /dev/null +++ b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBResponse.java @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.store.api; + +import java.io.Serializable; + +/** + * DBResponse + * @author shangyu.wh + * @version $Id: DBResponse.java, v 0.1 2018-04-18 16:35 shangyu.wh Exp $ + */ +public class DBResponse implements Serializable { + + private final Object entity; + + private final OperationStatus operationStatus; + + /** + * @param entity + * @param operationStatus + */ + public DBResponse(Object entity, OperationStatus operationStatus) { + this.entity = entity; + this.operationStatus = operationStatus; + } + + /** + * generate response ok + * @return + */ + public static DBResponseBuilder ok() { + return setStatus(OperationStatus.SUCCESS); + } + + /** + * generate response ok + * @param entity + * @return + */ + public static DBResponseBuilder ok(Object entity) { + DBResponseBuilder b = ok(); + b.entity(entity); + return b; + } + + /** + * set operationStatus to NOTFOUND + * @return + */ + public static DBResponseBuilder notfound() { + return setStatus(OperationStatus.NOTFOUND); + } + + /** + * set operationStatus + * @param status + * @return + */ + protected static DBResponseBuilder setStatus(OperationStatus status) { + DBResponseBuilder b = DBResponseBuilder.getInstance(); + b.status(status); + return b; + } + + /** + * Getter method for property entity. + * + * @return property value of entity + */ + public Object getEntity() { + return entity; + } + + /** + * Getter method for property operationStatus. + * + * @return property value of operationStatus + */ + public OperationStatus getOperationStatus() { + return operationStatus; + } + + /** + * DBResponseBuilder + */ + public static class DBResponseBuilder { + private static volatile DBResponseBuilder instance; + + /** + * get DBResponseBuilder instance + * @return + */ + public static DBResponseBuilder getInstance() { + if (instance == null) { + synchronized (DBResponseBuilder.class) { + if (instance == null) { + instance = new DBResponseBuilder(); + } + } + } + return instance; + } + + private Object entity; + + private OperationStatus operationStatus; + + /** + * build func + * @return + */ + public DBResponse build() { + final DBResponse r = new DBResponse(entity, operationStatus); + reset(); + return r; + } + + private void reset() { + operationStatus = null; + entity = null; + } + + /** + * set operationStatus status + * @param status + * @return + */ + public DBResponseBuilder status(OperationStatus status) { + if (status == null) { + throw new IllegalArgumentException(); + } + this.operationStatus = status; + return this; + } + + /** + * set entity + * @param entity + * @return + */ + public DBResponseBuilder entity(Object entity) { + this.entity = entity; + return this; + } + } +} \ No newline at end of file diff --git a/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBService.java b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBService.java new file mode 100644 index 000000000..fd27efbff --- /dev/null +++ b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/DBService.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.store.api; + +import com.alipay.sofa.registry.store.api.annotation.ReadOnLeader; + +/** + * + * @author shangyu.wh + * @version $Id: DBService.java, v 0.1 2018-04-18 12:06 shangyu.wh Exp $ + */ +public interface DBService { + + /** + * open db + * @param dbName + * @param entityClass + */ + void openDB(String dbName, Class entityClass); + + /** + * add + * @param key + * @param value + * @return + * @throws Exception + */ + boolean put(String key, Object value) throws Exception; + + /** + * get + * @param key + * @return + * @throws Exception + */ + @ReadOnLeader + DBResponse get(String key) throws Exception; + + /** + * update + * @param key + * @param value + * @return + * @throws Exception + */ + boolean update(String key, Object value) throws Exception; + + /** + * delete + * @param key + * @return + * @throws Exception + */ + boolean remove(String key) throws Exception; +} \ No newline at end of file diff --git a/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/OperationStatus.java b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/OperationStatus.java new file mode 100644 index 000000000..4114059f9 --- /dev/null +++ b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/OperationStatus.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.store.api; + +/** + @author xuanbei + @since 2019/2/12 + */ +public enum OperationStatus { + /** + * The operation was successful. + */ + SUCCESS, + + /** + * The requested key/data pair was not found. + */ + NOTFOUND +} diff --git a/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftReference.java b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftReference.java new file mode 100644 index 000000000..48e0af5c9 --- /dev/null +++ b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftReference.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.store.api.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author shangyu.wh + * @version $Id: RaftReference.java, v 0.1 2018-05-22 22:37 shangyu.wh Exp $ + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface RaftReference { + + Class interfaceType() default void.class; + + String uniqueId() default ""; +} \ No newline at end of file diff --git a/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftService.java b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftService.java new file mode 100644 index 000000000..f4e3565ab --- /dev/null +++ b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/RaftService.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.store.api.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author shangyu.wh + * @version $Id: RaftService.java, v 0.1 2018-05-22 22:39 shangyu.wh Exp $ + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface RaftService { + + Class interfaceType() default void.class; + + String uniqueId() default ""; +} \ No newline at end of file diff --git a/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/ReadOnLeader.java b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/ReadOnLeader.java new file mode 100644 index 000000000..5bd53e2f8 --- /dev/null +++ b/server/store/api/src/main/java/com/alipay/sofa/registry/store/api/annotation/ReadOnLeader.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.store.api.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * + * @author shangyu.wh + * @version $Id: ReadOnLeader.java, v 0.1 2018-05-29 22:25 shangyu.wh Exp $ + */ +@Target({ ElementType.METHOD }) +@Retention(RUNTIME) +public @interface ReadOnLeader { +} \ No newline at end of file diff --git a/server/store/jraft/pom.xml b/server/store/jraft/pom.xml new file mode 100644 index 000000000..188f0d851 --- /dev/null +++ b/server/store/jraft/pom.xml @@ -0,0 +1,60 @@ + + + 4.0.0 + + com.alipay.sofa + registry-store + 5.2.0-SNAPSHOT + ../pom.xml + + + registry-store-jraft + + + ../../../ + + + + + junit + junit + test + + + ch.qos.logback + logback-classic + test + + + com.alipay.sofa + jraft-core + + + com.alipay.sofa + registry-remoting-bolt + + + com.alipay.sofa + registry-remoting-api + + + com.alipay.sofa + registry-store-api + + + org.slf4j + slf4j-api + + + commons-lang + commons-lang + + + commons-io + commons-io + + + + diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftClient.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftClient.java new file mode 100644 index 000000000..84af2be5d --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftClient.java @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.bootstrap; + +import com.alipay.remoting.ConnectionEventType; +import com.alipay.remoting.rpc.RpcClient; +import com.alipay.sofa.jraft.RouteTable; +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.jraft.conf.Configuration; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.jraft.option.CliOptions; +import com.alipay.sofa.jraft.rpc.CliClientService; +import com.alipay.sofa.jraft.rpc.impl.AbstractBoltClientService; +import com.alipay.sofa.jraft.rpc.impl.cli.BoltCliClientService; +import com.alipay.sofa.registry.jraft.command.ProcessRequest; +import com.alipay.sofa.registry.jraft.command.ProcessResponse; +import com.alipay.sofa.registry.jraft.handler.NotifyLeaderChangeHandler; +import com.alipay.sofa.registry.jraft.handler.RaftClientConnectionHandler; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.bolt.ConnectionEventAdapter; +import com.alipay.sofa.registry.remoting.bolt.SyncUserProcessorAdapter; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * + * @author shangyu.wh + * @version $Id: RaftClient.java, v 0.1 2018-05-16 11:40 shangyu.wh Exp $ + */ +public class RaftClient { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftClient.class); + + private BoltCliClientService cliClientService; + private RpcClient rpcClient; + private CliOptions cliOptions; + private String groupId; + private Configuration conf; + + private AtomicBoolean started = new AtomicBoolean(false); + + /** + * @param groupId + * @param confStr Example: 127.0.0.1:8081,127.0.0.1:8082,127.0.0.1:8083 + */ + public RaftClient(String groupId, String confStr) { + + this.groupId = groupId; + conf = new Configuration(); + if (!conf.parse(confStr)) { + throw new IllegalArgumentException("Fail to parse conf:" + confStr); + } + cliOptions = new CliOptions(); + cliClientService = new BoltCliClientService(); + } + + /** + * @param groupId + * @param confStr + * @param cliClientService + */ + public RaftClient(String groupId, String confStr, AbstractBoltClientService cliClientService) { + + this.groupId = groupId; + conf = new Configuration(); + if (!conf.parse(confStr)) { + throw new IllegalArgumentException("Fail to parse conf:" + confStr); + } + cliOptions = new CliOptions(); + this.cliClientService = (BoltCliClientService) cliClientService; + } + + /** + * raft client start + */ + public void start() { + if (started.compareAndSet(false, true)) { + + RouteTable.getInstance().updateConfiguration(groupId, conf); + + cliClientService.init(cliOptions); + + rpcClient = cliClientService.getRpcClient(); + + RaftClientConnectionHandler raftClientConnectionHandler = new RaftClientConnectionHandler( + this); + + rpcClient.addConnectionEventProcessor(ConnectionEventType.CONNECT, + new ConnectionEventAdapter(ConnectionEventType.CONNECT, + raftClientConnectionHandler, null)); + rpcClient.addConnectionEventProcessor(ConnectionEventType.CLOSE, + new ConnectionEventAdapter(ConnectionEventType.CLOSE, raftClientConnectionHandler, + null)); + rpcClient.addConnectionEventProcessor(ConnectionEventType.EXCEPTION, + new ConnectionEventAdapter(ConnectionEventType.EXCEPTION, + raftClientConnectionHandler, null)); + + //reset leader notify + NotifyLeaderChangeHandler notifyLeaderChangeHandler = new NotifyLeaderChangeHandler( + groupId, cliClientService); + rpcClient + .registerUserProcessor(new SyncUserProcessorAdapter(notifyLeaderChangeHandler)); + + } + } + + /** + * stop cliClientService + */ + public void shutdown() { + if (cliClientService != null) { + cliClientService.shutdown(); + } + } + + /** + * repick leader + * @return + */ + public PeerId refreshLeader() { + return refreshLeader(cliClientService, groupId, cliOptions.getRpcDefaultTimeout()); + } + + public static PeerId refreshLeader(CliClientService cliClientService, String groupId, + int timeout) { + try { + Status status = RouteTable.getInstance().refreshLeader(cliClientService, groupId, + timeout); + if (!status.isOk()) { + throw new IllegalStateException(String.format("Refresh leader failed,error=%s", + status.getErrorMsg())); + } + PeerId leader = RouteTable.getInstance().selectLeader(groupId); + LOGGER.info("Leader is {}", leader); + + //avoid refresh leader config ip list must be current list,list maybe change by manage + status = RouteTable.getInstance().refreshConfiguration(cliClientService, groupId, + timeout); + if (!status.isOk()) { + throw new IllegalStateException(String.format( + "Refresh configuration failed, error=%s", status.getErrorMsg())); + } + + return leader; + } catch (Exception e) { + LOGGER.error("Refresh leader failed", e); + throw new IllegalStateException("Refresh leader failed", e); + } + } + + /** + * get leader + * @return + */ + public PeerId getLeader() { + PeerId leader = RouteTable.getInstance().selectLeader(groupId); + if (leader == null) { + leader = refreshLeader(); + } + return leader; + } + + /** + * raft client send request + * @param request + * @return + */ + public Object sendRequest(ProcessRequest request) { + try { + if (!started.get()) { + LOGGER.error("Client must be started before send request!"); + throw new IllegalStateException("Client must be started before send request!"); + } + + PeerId peer = getLeader(); + LOGGER.info("Raft client send message {} to url {}", request, peer.getEndpoint() + .toString()); + Object response = this.rpcClient.invokeSync(peer.getEndpoint().toString(), request, + cliOptions.getRpcDefaultTimeout()); + if (response == null) { + LOGGER.error("Send process request has no response return!"); + throw new RuntimeException("Send process request has no response return!"); + } + ProcessResponse cmd = (ProcessResponse) response; + if (cmd.getSuccess()) { + return cmd.getEntity(); + } else { + String redirect = cmd.getRedirect(); + if (redirect != null && !redirect.isEmpty()) { + return redirectRequest(request, redirect); + } else { + throw new IllegalStateException("Server error:" + cmd.getEntity()); + } + } + } catch (Exception e) { + LOGGER.error("Send process request error!", e); + throw new RuntimeException("Send process request error!" + e.getMessage(), e); + } + } + + private Object redirectRequest(ProcessRequest request, String redirect) { + try { + PeerId redirectLead = new PeerId(); + if (!redirectLead.parse(redirect)) { + throw new IllegalArgumentException("Fail to parse serverId:" + redirect); + } + + //wait for onLeaderStart + TimeUnit.MILLISECONDS.sleep(1000); + + LOGGER.info("Redirect request send to return peer {},request {}", redirect, request); + Object response = this.rpcClient.invokeSync(redirectLead.getEndpoint().toString(), + request, cliOptions.getRpcDefaultTimeout()); + ProcessResponse cmd = (ProcessResponse) response; + if (cmd.getSuccess()) { + RouteTable.getInstance().updateLeader(groupId, redirectLead); + return cmd.getEntity(); + } else { + refreshLeader(); + throw new IllegalStateException("Redirect request server error:" + cmd.getEntity()); + } + } catch (Exception e) { + LOGGER.error("Redirect process request error!", e); + throw new RuntimeException("Redirect process request error!" + e.getMessage(), e); + } + } + + /** + * Getter method for property groupId. + * + * @return property value of groupId + */ + public String getGroupId() { + return groupId; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServer.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServer.java new file mode 100644 index 000000000..2aad27198 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServer.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.bootstrap; + +import com.alipay.remoting.rpc.RpcClient; +import com.alipay.remoting.rpc.RpcServer; +import com.alipay.sofa.jraft.Node; +import com.alipay.sofa.jraft.RaftGroupService; +import com.alipay.sofa.jraft.conf.Configuration; +import com.alipay.sofa.jraft.core.NodeImpl; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.jraft.option.NodeOptions; +import com.alipay.sofa.jraft.rpc.RaftRpcServerFactory; +import com.alipay.sofa.jraft.rpc.impl.AbstractBoltClientService; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.jraft.command.NotifyLeaderChange; +import com.alipay.sofa.registry.jraft.handler.NotifyLeaderChangeHandler; +import com.alipay.sofa.registry.jraft.handler.RaftServerConnectionHandler; +import com.alipay.sofa.registry.jraft.handler.RaftServerHandler; +import com.alipay.sofa.registry.jraft.processor.FollowerProcessListener; +import com.alipay.sofa.registry.jraft.processor.LeaderProcessListener; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.metrics.ReporterUtils; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.bolt.BoltServer; +import com.alipay.sofa.registry.remoting.bolt.SyncUserProcessorAdapter; +import com.alipay.sofa.registry.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * + * @author shangyu.wh + * @version $Id: RaftServer.java, v 0.1 2018-05-16 11:39 shangyu.wh Exp $ + */ +public class RaftServer { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftServer.class); + + private RaftGroupService raftGroupService; + private Node node; + private ServiceStateMachine fsm; + private PeerId serverId; + private Configuration initConf; + private String groupId; + private String dataPath; + private List serverHandlers = new ArrayList<>(); + + private LeaderProcessListener leaderProcessListener; + + private FollowerProcessListener followerProcessListener; + + private BoltServer boltServer; + + /** + * + * @param dataPath Example: /tmp/server1 + * @param groupId + * @param serverIdStr Example: 127.0.0.1:8081 + * @param initConfStr Example: 127.0.0.1:8081,127.0.0.1:8082,127.0.0.1:8083 + * @throws IOException + */ + public RaftServer(String dataPath, String groupId, String serverIdStr, String initConfStr) { + this.dataPath = dataPath; + this.groupId = groupId; + serverId = new PeerId(); + if (!serverId.parse(serverIdStr)) { + throw new IllegalArgumentException("Fail to parse serverId:" + serverIdStr); + } + + initConf = new Configuration(); + if (!initConf.parse(initConfStr)) { + throw new IllegalArgumentException("Fail to parse initConf:" + initConfStr); + } + } + + /** + * start raft server + * @param raftServerConfig + * @throws IOException + */ + public void start(RaftServerConfig raftServerConfig) throws IOException { + + FileUtils.forceMkdir(new File(dataPath)); + + serverHandlers.add(new RaftServerHandler(this)); + serverHandlers.add(new RaftServerConnectionHandler()); + + boltServer = new BoltServer(new URL(NetUtil.getLocalAddress().getHostAddress(), + serverId.getPort()), serverHandlers); + + boltServer.initServer(); + + RpcServer rpcServer = boltServer.getRpcServer(); + + RaftRpcServerFactory.addRaftRequestProcessors(rpcServer); + + this.fsm = ServiceStateMachine.getInstance(); + this.fsm.setLeaderProcessListener(leaderProcessListener); + this.fsm.setFollowerProcessListener(followerProcessListener); + + NodeOptions nodeOptions = initNodeOptions(raftServerConfig); + + this.raftGroupService = new RaftGroupService(groupId, serverId, nodeOptions, rpcServer); + //start + this.node = this.raftGroupService.start(); + + if (raftServerConfig.isEnableMetrics()) { + ReporterUtils.startSlf4jReporter(raftServerConfig.getEnableMetricsReporterPeriod(), + node.getNodeMetrics().getMetricRegistry(), raftServerConfig.getMetricsLogger()); + } + + RpcClient raftClient = ((AbstractBoltClientService) (((NodeImpl) node).getRpcService())) + .getRpcClient(); + + NotifyLeaderChangeHandler notifyLeaderChangeHandler = new NotifyLeaderChangeHandler( + groupId, null); + raftClient.registerUserProcessor(new SyncUserProcessorAdapter(notifyLeaderChangeHandler)); + } + + /** + * shutdown raftGroupService + */ + public void shutdown() { + if (raftGroupService != null) { + this.raftGroupService.shutdown(); + } + } + + private NodeOptions initNodeOptions(RaftServerConfig raftServerConfig) { + + NodeOptions nodeOptions = new NodeOptions(); + + nodeOptions.setElectionTimeoutMs(raftServerConfig.getElectionTimeoutMs()); + + nodeOptions.setDisableCli(false); + + nodeOptions.setSnapshotIntervalSecs(raftServerConfig.getSnapshotIntervalSecs()); + + nodeOptions.setInitialConf(initConf); + + nodeOptions.setFsm(this.fsm); + + nodeOptions.setLogUri(dataPath + File.separator + "log"); + nodeOptions.setRaftMetaUri(dataPath + File.separator + "raft_meta"); + nodeOptions.setSnapshotUri(dataPath + File.separator + "snapshot"); + + if (raftServerConfig.isEnableMetrics()) { + nodeOptions.setEnableMetrics(raftServerConfig.isEnableMetrics()); + } + + return nodeOptions; + } + + /** + * Redirect request to new leader + * @return + */ + public String redirect() { + if (node != null) { + PeerId leader = node.getLeaderId(); + if (leader != null) { + return leader.toString(); + } + } + return null; + } + + /** + * send notify + * @param leader + * @param sender + */ + public void sendNotify(PeerId leader, String sender) { + + if (boltServer == null) { + LOGGER.error("Send notify leader change error!server must be started!"); + throw new IllegalStateException("Send notify leader change error!server must be started!"); + } + NotifyLeaderChange notifyLeaderChange = new NotifyLeaderChange(leader); + notifyLeaderChange.setSender(sender); + Collection channels = boltServer.getChannels(); + + List throwables = new ArrayList<>(); + channels.forEach(channel -> { + try { + boltServer.sendSync(channel, notifyLeaderChange, + 1000); + } catch (Exception e) { + LOGGER.error("Send notify leader change error!url:{}", channel.getRemoteAddress(), e); + throwables.add(e); + } + }); + + if (!throwables.isEmpty()) { + LOGGER.error("Send notify leader change error!"); + throw new RuntimeException("Send notify leader change error!"); + } + } + + /** + * Getter method for property fsm. + * + * @return property value of fsm + */ + public ServiceStateMachine getFsm() { + return this.fsm; + } + + /** + * Getter method for property node. + * + * @return property value of node + */ + public Node getNode() { + return this.node; + } + + /** + * Setter method for property leaderProcessListener. + * + * @param leaderProcessListener value to be assigned to property leaderProcessListener + */ + public void setLeaderProcessListener(LeaderProcessListener leaderProcessListener) { + this.leaderProcessListener = leaderProcessListener; + } + + /** + * Setter method for property followerProcessListener. + * + * @param followerProcessListener value to be assigned to property followerProcessListener + */ + public void setFollowerProcessListener(FollowerProcessListener followerProcessListener) { + this.followerProcessListener = followerProcessListener; + } + +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServerConfig.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServerConfig.java new file mode 100644 index 000000000..9e68e1e66 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/RaftServerConfig.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.bootstrap; + +import com.alipay.sofa.registry.log.Logger; + +/** + * + * @author shangyu.wh + * @version $Id: RaftServerConifg.java, v 0.1 2018-08-23 13:13 shangyu.wh Exp $ + */ +public class RaftServerConfig { + + /** + * Whether to enable metrics for node. + */ + private boolean enableMetrics = false; + + /** + * Whether to enable metrics interval seconds + */ + private int enableMetricsReporterPeriod = 30; + + /** + * A follower would become a candidate if it doesn't receive any message + * from the leader in |election_timeout_ms| milliseconds + * Default: 1000 (1s) + */ + private int electionTimeoutMs = 1000; + + /** + * A snapshot saving would be triggered every |snapshot_interval_s| seconds + * if this was reset as a positive number + * If |snapshot_interval_s| <= 0, the time based snapshot would be disabled. + * Default: 3600 (1 hour) + */ + private int snapshotIntervalSecs = 3600; + + private Logger metricsLogger; + + /** + * Getter method for property enableMetrics. + * + * @return property value of enableMetrics + */ + public boolean isEnableMetrics() { + return enableMetrics; + } + + /** + * Setter method for property enableMetrics. + * + * @param enableMetrics value to be assigned to property enableMetrics + */ + public void setEnableMetrics(boolean enableMetrics) { + this.enableMetrics = enableMetrics; + } + + /** + * Getter method for property enableMetricsReporterPeriod. + * + * @return property value of enableMetricsReporterPeriod + */ + public int getEnableMetricsReporterPeriod() { + return enableMetricsReporterPeriod; + } + + /** + * Setter method for property enableMetricsReporterPeriod. + * + * @param enableMetricsReporterPeriod value to be assigned to property enableMetricsReporterPeriod + */ + public void setEnableMetricsReporterPeriod(int enableMetricsReporterPeriod) { + this.enableMetricsReporterPeriod = enableMetricsReporterPeriod; + } + + /** + * Getter method for property electionTimeoutMs. + * + * @return property value of electionTimeoutMs + */ + public int getElectionTimeoutMs() { + return electionTimeoutMs; + } + + /** + * Setter method for property electionTimeoutMs. + * + * @param electionTimeoutMs value to be assigned to property electionTimeoutMs + */ + public void setElectionTimeoutMs(int electionTimeoutMs) { + this.electionTimeoutMs = electionTimeoutMs; + } + + /** + * Getter method for property snapshotIntervalSecs. + * + * @return property value of snapshotIntervalSecs + */ + public int getSnapshotIntervalSecs() { + return snapshotIntervalSecs; + } + + /** + * Setter method for property snapshotIntervalSecs. + * + * @param snapshotIntervalSecs value to be assigned to property snapshotIntervalSecs + */ + public void setSnapshotIntervalSecs(int snapshotIntervalSecs) { + this.snapshotIntervalSecs = snapshotIntervalSecs; + } + + /** + * Getter method for property metricsLogger. + * + * @return property value of metricsLogger + */ + public Logger getMetricsLogger() { + return metricsLogger; + } + + /** + * Setter method for property metricsLogger. + * + * @param metricsLogger value to be assigned to property metricsLogger + */ + public void setMetricsLogger(Logger metricsLogger) { + this.metricsLogger = metricsLogger; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/ServiceStateMachine.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/ServiceStateMachine.java new file mode 100644 index 000000000..7f869b7b2 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/bootstrap/ServiceStateMachine.java @@ -0,0 +1,285 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.bootstrap; + +import com.alipay.sofa.jraft.Closure; +import com.alipay.sofa.jraft.Iterator; +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.jraft.core.StateMachineAdapter; +import com.alipay.sofa.jraft.entity.LeaderChangeContext; +import com.alipay.sofa.jraft.error.RaftError; +import com.alipay.sofa.jraft.storage.snapshot.SnapshotReader; +import com.alipay.sofa.jraft.storage.snapshot.SnapshotWriter; +import com.alipay.sofa.jraft.util.Utils; +import com.alipay.sofa.registry.jraft.command.ProcessRequest; +import com.alipay.sofa.registry.jraft.command.ProcessResponse; +import com.alipay.sofa.registry.jraft.processor.FollowerProcessListener; +import com.alipay.sofa.registry.jraft.processor.LeaderProcessListener; +import com.alipay.sofa.registry.jraft.processor.LeaderTaskClosure; +import com.alipay.sofa.registry.jraft.processor.Processor; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.caucho.hessian.io.Hessian2Input; +import com.caucho.hessian.io.SerializerFactory; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +/** + * + * @author shangyu.wh + * @version $Id: ServiceStateMachine.java, v 0.1 2018-05-21 15:54 shangyu.wh Exp $ + */ +public class ServiceStateMachine extends StateMachineAdapter { + + private static final Logger LOG = LoggerFactory + .getLogger(ServiceStateMachine.class); + + private LeaderProcessListener leaderProcessListener; + + private FollowerProcessListener followerProcessListener; + + private static volatile ServiceStateMachine instance; + + /** + * get instance of ServiceStateMachine + * @return + */ + public static ServiceStateMachine getInstance() { + if (instance == null) { + synchronized (ServiceStateMachine.class) { + if (instance == null) { + instance = new ServiceStateMachine(); + } + } + } + return instance; + } + + /** + * leader term + */ + private AtomicLong leaderTerm = new AtomicLong(-1); + + /** + * follower term + */ + private AtomicLong followerTerm = new AtomicLong(-1); + + /** + * verify is leader or not + * @return + */ + public boolean isLeader() { + return this.leaderTerm.get() > 0; + } + + /** + * verify is follower or not + * @return + */ + public boolean isfollower() { + return this.followerTerm.get() > 0; + } + + @Override + public void onApply(Iterator iter) { + while (iter.hasNext()) { + Closure done = iter.done(); + ByteBuffer data = iter.getData(); + ProcessRequest request; + LeaderTaskClosure closure = null; + + if (done != null) { + closure = (LeaderTaskClosure) done; + request = closure.getRequest(); + } else { + + Hessian2Input input = new Hessian2Input(new ByteArrayInputStream(data.array())); + SerializerFactory serializerFactory = new SerializerFactory(); + input.setSerializerFactory(serializerFactory); + try { + request = (ProcessRequest) input.readObject(); + input.close(); + } catch (IOException e) { + throw new RuntimeException( + "IOException occurred when Hessian serializer decode!", e); + } + } + + ProcessResponse response = Processor.getInstance().process(request); + + if (closure != null) { + closure.setResponse(response); + closure.run(Status.OK()); + } + iter.next(); + } + } + + @Override + public void onSnapshotSave(final SnapshotWriter writer, final Closure done) { + + Map workers = Processor.getInstance().getWorkers(); + Map snapshotProcessors = new HashMap<>(); + if (workers != null) { + workers.forEach((serviceId, worker) -> { + if (worker instanceof SnapshotProcess) { + SnapshotProcess snapshotProcessor = (SnapshotProcess) worker; + snapshotProcessors.put(serviceId, snapshotProcessor.copy()); + } + }); + } + Utils.runInThread(() -> { + String errors = null; + outer: + for (Map.Entry entry : snapshotProcessors.entrySet()) { + String serviceId = entry.getKey(); + SnapshotProcess snapshotProcessor = entry.getValue(); + Set fileNames = snapshotProcessor.getSnapshotFileNames(); + for (String fileName : fileNames) { + String savePath = writer.getPath() + File.separator + fileName; + LOG.info("Begin save snapshot path {}", savePath); + boolean ret = snapshotProcessor.save(savePath); + if (ret) { + if (!writer.addFile(fileName)) { + errors = String.format("Fail to add file %s to writer", fileName); + break outer; + } + } else { + errors = String.format("Fail to save service:%s snapshot %s", serviceId, savePath); + break outer; + } + } + } + if (errors != null) { + done.run(new Status(RaftError.EIO, errors)); + } else { + done.run(Status.OK()); + } + }); + + } + + @Override + public boolean onSnapshotLoad(SnapshotReader reader) { + if (isLeader()) { + LOG.warn("Leader is not supposed to load snapshot"); + return false; + } + List failServices = new ArrayList<>(); + Map workers = Processor.getInstance().getWorkers(); + if (workers != null) { + outer: for (Map.Entry entry : workers.entrySet()) { + String serviceId = entry.getKey(); + Object worker = entry.getValue(); + if (worker instanceof SnapshotProcess) { + SnapshotProcess snapshotProcess = (SnapshotProcess) worker; + Set fileNames = snapshotProcess.getSnapshotFileNames(); + + for (String fileName : fileNames) { + if (reader.getFileMeta(fileName) == null) { + LOG.error("Fail to find data file {} in {}", fileName, reader.getPath()); + failServices.add(serviceId); + break outer; + } + + String savePath = reader.getPath() + File.separator + fileName; + LOG.info("Begin load snapshot path {}", savePath); + boolean ret = snapshotProcess.load(savePath); + if (!ret) { + LOG.error("Fail to load service:{} snapshot {}", serviceId, savePath); + failServices.add(serviceId); + break outer; + } + } + } + } + } + + if (!failServices.isEmpty()) { + LOG.error("Fail to load services {} snapshot!", failServices); + return false; + } + return true; + } + + @Override + public void onLeaderStart(long term) { + this.leaderTerm.set(term); + if (leaderProcessListener != null) { + Utils.runInThread(() -> leaderProcessListener.startProcess()); + } + super.onLeaderStart(term); + } + + @Override + public void onLeaderStop(Status status) { + this.leaderTerm.set(-1); + if (leaderProcessListener != null) { + Utils.runInThread(() -> leaderProcessListener.stopProcess()); + } + super.onLeaderStop(status); + } + + @Override + public void onStopFollowing(LeaderChangeContext ctx) { + + this.followerTerm.set(-1); + if (followerProcessListener != null) { + Utils.runInThread(() -> followerProcessListener.stopProcess(ctx.getLeaderId())); + } + super.onStopFollowing(ctx); + } + + @Override + public void onStartFollowing(LeaderChangeContext ctx) { + + this.followerTerm.set(1); + if (followerProcessListener != null) { + Utils.runInThread(() -> followerProcessListener.startProcess(ctx.getLeaderId())); + } + super.onStartFollowing(ctx); + } + + /** + * Setter method for property leaderProcessListener. + * + * @param leaderProcessListener value to be assigned to property leaderProcessListener + */ + public void setLeaderProcessListener(LeaderProcessListener leaderProcessListener) { + this.leaderProcessListener = leaderProcessListener; + } + + /** + * Setter method for property followerProcessListener. + * + * @param followerProcessListener value to be assigned to property followerProcessListener + */ + public void setFollowerProcessListener(FollowerProcessListener followerProcessListener) { + this.followerProcessListener = followerProcessListener; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/CommandCodec.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/CommandCodec.java new file mode 100644 index 000000000..277e2d3e5 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/CommandCodec.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.command; + +import com.alipay.remoting.exception.CodecException; +import com.alipay.remoting.serialization.SerializerManager; + +/** + * Command codec + * @author boyan (boyan@alibaba-inc.com) + * + * 2018-Apr-25 1:30:30 PM + */ +public class CommandCodec { + /** + * encode the command,returns the byte array. + * @param obj + * @return + */ + public static byte[] encodeCommand(Object obj) { + try { + return SerializerManager.getSerializer(SerializerManager.Hessian2).serialize(obj); + } catch (CodecException e) { + throw new IllegalStateException(e); + } + } + + /** + * Decode the command object from byte array. + * @param content + * @param clazz + * @return + */ + public static T decodeCommand(byte[] content, Class clazz) { + try { + return SerializerManager.getSerializer(SerializerManager.Hessian2).deserialize(content, + clazz.getName()); + } catch (CodecException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/NotifyLeaderChange.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/NotifyLeaderChange.java new file mode 100644 index 000000000..a85efaa8c --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/NotifyLeaderChange.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.command; + +import com.alipay.sofa.jraft.entity.PeerId; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: NotifyLeaderChange.java, v 0.1 2018-06-23 14:32 shangyu.wh Exp $ + */ +public class NotifyLeaderChange implements Serializable { + + private final PeerId leader; + + private String sender; + + /** + * constructor + * @param leader + */ + public NotifyLeaderChange(PeerId leader) { + this.leader = leader; + } + + /** + * Getter method for property leader. + * + * @return property value of leader + */ + public PeerId getLeader() { + return leader; + } + + /** + * Getter method for property sender. + * + * @return property value of sender + */ + public String getSender() { + return sender; + } + + /** + * Setter method for property sender. + * + * @param sender value to be assigned to property sender + */ + public void setSender(String sender) { + this.sender = sender; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("NotifyLeaderChange{"); + sb.append("leader=").append(leader); + sb.append(", sender='").append(sender).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessRequest.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessRequest.java new file mode 100644 index 000000000..5c69aed67 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessRequest.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.command; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * + * @author shangyu.wh + * @version $Id: ProcessRequest.java, v 0.1 2018-05-21 17:36 shangyu.wh Exp $ + */ +public class ProcessRequest implements Serializable { + + /** invoke method */ + private String methodName; + + /** invoke method arguments name */ + private String[] methodArgSigs; + + /** invoke method arguments object */ + private Object[] methodArgs; + + /** traget service unique name */ + private String serviceName; + + public ProcessRequest() { + } + + /** + * Getter method for property methodName. + * + * @return property value of methodName + */ + public String getMethodName() { + return methodName; + } + + /** + * Setter method for property methodName. + * + * @param methodName value to be assigned to property methodName + */ + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + /** + * Getter method for property methodArgSigs. + * + * @return property value of methodArgSigs + */ + public String[] getMethodArgSigs() { + return methodArgSigs; + } + + /** + * Setter method for property methodArgSigs. + * + * @param methodArgSigs value to be assigned to property methodArgSigs + */ + public void setMethodArgSigs(String[] methodArgSigs) { + this.methodArgSigs = methodArgSigs; + } + + /** + * Getter method for property methodArgs. + * + * @return property value of methodArgs + */ + public Object[] getMethodArgs() { + return methodArgs; + } + + /** + * Setter method for property methodArgs. + * + * @param methodArgs value to be assigned to property methodArgs + */ + public void setMethodArgs(Object[] methodArgs) { + this.methodArgs = methodArgs; + } + + /** + * Getter method for property serviceName. + * + * @return property value of serviceName + */ + public String getServiceName() { + return serviceName; + } + + /** + * Setter method for property serviceName. + * + * @param serviceName value to be assigned to property serviceName + */ + public void setServiceName(String serviceName) { + this.serviceName = serviceName; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ProcessRequest{"); + sb.append("methodName='").append(methodName).append('\''); + sb.append(", methodArgSigs=").append(Arrays.toString(methodArgSigs)); + sb.append(", methodArgs=").append(Arrays.toString(methodArgs)); + sb.append(", serviceName='").append(serviceName).append('\''); + sb.append('}'); + return sb.toString(); + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessResponse.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessResponse.java new file mode 100644 index 000000000..4dfe59d61 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/command/ProcessResponse.java @@ -0,0 +1,171 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.command; + +import java.io.Serializable; + +/** + * + * @author shangyu.wh + * @version $Id: Response.java, v 0.1 2018-05-21 14:22 shangyu.wh Exp $ + */ +public class ProcessResponse implements Serializable { + + private final Object entity; + + private final Boolean success; + + private final String redirect; + + /** + * constructor + * @param entity + * @param success + * @param redirect + */ + public ProcessResponse(Object entity, Boolean success, String redirect) { + this.entity = entity; + this.success = success; + this.redirect = redirect; + } + + /** + * response ok + * @return + */ + public static ResponseBuilder ok() { + return setStatus(true); + } + + /** + * response ok + * @param entity + * @return + */ + public static ResponseBuilder ok(Object entity) { + ResponseBuilder b = ok(); + b.entity(entity); + return b; + } + + /** + * response fail + * @return + */ + public static ResponseBuilder fail() { + return setStatus(false); + } + + /** + * response fail + * @param errorMsg + * @return + */ + public static ResponseBuilder fail(String errorMsg) { + ResponseBuilder b = fail(); + b.entity(errorMsg); + return b; + } + + /** + * response redirect + * @param leader + * @return + */ + public static ResponseBuilder redirect(String leader) { + ResponseBuilder b = fail(); + b.entity("Not leader"); + b.redirect(leader); + return b; + } + + protected static ResponseBuilder setStatus(Boolean status) { + ResponseBuilder b = new ResponseBuilder(); + b.status(status); + return b; + } + + /** + * Getter method for property entity. + * + * @return property value of entity + */ + public Object getEntity() { + return entity; + } + + /** + * Getter method for property success. + * + * @return property value of success + */ + public Boolean getSuccess() { + return success; + } + + /** + * Getter method for property redirect. + * + * @return property value of redirect + */ + public String getRedirect() { + return redirect; + } + + /** + * ResponseBuilder + */ + public static class ResponseBuilder { + private Object entity; + + private Boolean success; + private String redirect; + + public ProcessResponse build() { + final ProcessResponse r = new ProcessResponse(entity, success, redirect); + reset(); + return r; + } + + private void reset() { + success = null; + entity = null; + redirect = null; + } + + public ResponseBuilder status(Boolean status) { + if (status == null) { + throw new IllegalArgumentException("response status can not be null!"); + } + this.success = status; + return this; + } + + public ResponseBuilder entity(Object entity) { + this.entity = entity; + return this; + } + + public ResponseBuilder redirect(String redirect) { + if (redirect == null) { + throw new IllegalArgumentException("redirect leader can not be null!"); + } + this.redirect = redirect; + return this; + } + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/NotifyLeaderChangeHandler.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/NotifyLeaderChangeHandler.java new file mode 100644 index 000000000..e2ebae18d --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/NotifyLeaderChangeHandler.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.handler; + +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.jraft.rpc.CliClientService; +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.jraft.command.NotifyLeaderChange; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +/** + * + * @author shangyu.wh + * @version $Id: NotifyLeaderChangeHandler.java, v 0.1 2018-06-23 14:37 shangyu.wh Exp $ + */ +public class NotifyLeaderChangeHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotifyLeaderChangeHandler.class); + + private String groupId; + + private CliClientService clientService; + + /** + * constructor + * @param groupId + */ + public NotifyLeaderChangeHandler(String groupId, CliClientService clientService) { + this.groupId = groupId; + this.clientService = clientService; + } + + @Override + public void connected(Channel channel) { + + } + + @Override + public void disconnected(Channel channel) { + + } + + @Override + public void received(Channel channel, Object message) { + + } + + @Override + public Object reply(Channel channel, Object message) { + + NotifyLeaderChange notifyLeaderChange = (NotifyLeaderChange) message; + LOGGER.info("Receive NotifyLeaderChange request:{},remote address:{}, localAddress:", + notifyLeaderChange, channel.getRemoteAddress(), channel.getLocalAddress()); + + //reset leader + if (clientService != null) { + PeerId peerId = RaftClient.refreshLeader(clientService, groupId, 5000); + if (peerId != null) { + LOGGER.info("Reset leader for raft group {},leader()", groupId, peerId); + } + } + + return null; + } + + @Override + public void caught(Channel channel, Object message, Throwable exception) { + + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return NotifyLeaderChange.class; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftClientConnectionHandler.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftClientConnectionHandler.java new file mode 100644 index 000000000..2a605e2fd --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftClientConnectionHandler.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.handler; + +import com.alipay.sofa.jraft.RouteTable; +import com.alipay.sofa.jraft.entity.PeerId; +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +/** + * + * @author shangyu.wh + * @version $Id: RaftClientConnectionHandler.java, v 0.1 2018-06-01 14:27 shangyu.wh Exp $ + */ +public class RaftClientConnectionHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftClientConnectionHandler.class); + + private RaftClient raftClient; + + /** + * constructor + * @param raftClient + */ + public RaftClientConnectionHandler(RaftClient raftClient) { + this.raftClient = raftClient; + } + + @Override + public void connected(Channel channel) { + if (channel != null && channel.isConnected()) { + LOGGER.info("Raft Client connected,remote address:" + channel.getRemoteAddress() + + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) { + if (channel != null && !channel.isConnected()) { + LOGGER.info("Raft Client disconnected,remote address:" + channel.getRemoteAddress() + + " localAddress:" + channel.getLocalAddress()); + } + //reset leader + if (RouteTable.getInstance().updateLeader(raftClient.getGroupId(), (PeerId) null)) { + LOGGER.info("Reset leader for raft group {}", raftClient.getGroupId()); + } + } + + @Override + public void received(Channel channel, Object message) { + + } + + @Override + public Object reply(Channel channel, Object message) { + return null; + } + + @Override + public void caught(Channel channel, Object message, Throwable exception) { + + } + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public Class interest() { + return null; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerConnectionHandler.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerConnectionHandler.java new file mode 100644 index 000000000..96c60f51d --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerConnectionHandler.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.handler; + +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; + +/** + * + * @author shangyu.wh + * @version $Id: RaftServerConnectionHandler.java, v 0.1 2018-06-01 14:27 shangyu.wh Exp $ + */ +public class RaftServerConnectionHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftServerConnectionHandler.class); + + @Override + public void connected(Channel channel) { + if (channel != null && channel.isConnected()) { + LOGGER.info("Raft Server connected,remote address:" + channel.getRemoteAddress() + + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void disconnected(Channel channel) { + if (channel != null && !channel.isConnected()) { + LOGGER.info("Raft Server disconnected,remote address:" + channel.getRemoteAddress() + + " localAddress:" + channel.getLocalAddress()); + } + } + + @Override + public void received(Channel channel, Object message) { + + } + + @Override + public Object reply(Channel channel, Object message) { + return null; + } + + @Override + public void caught(Channel channel, Object message, Throwable exception) { + + } + + @Override + public HandlerType getType() { + return HandlerType.LISENTER; + } + + @Override + public Class interest() { + return null; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerHandler.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerHandler.java new file mode 100644 index 000000000..12bbba9a6 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/handler/RaftServerHandler.java @@ -0,0 +1,162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.handler; + +import com.alipay.remoting.AsyncContext; +import com.alipay.sofa.jraft.entity.Task; +import com.alipay.sofa.registry.jraft.bootstrap.RaftServer; +import com.alipay.sofa.registry.jraft.command.ProcessRequest; +import com.alipay.sofa.registry.jraft.command.ProcessResponse; +import com.alipay.sofa.registry.jraft.processor.LeaderTaskClosure; +import com.alipay.sofa.registry.jraft.processor.Processor; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.RemotingException; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.caucho.hessian.io.Hessian2Output; +import com.caucho.hessian.io.SerializerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; + +/** + * + * @author shangyu.wh + * @version $Id: ServerHandler.java, v 0.1 2017-11-28 18:06 shangyu.wh Exp $ + */ +public class RaftServerHandler implements ChannelHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(RaftServerHandler.class); + + protected RaftServer raftServer; + + /** + * constructor + * @param raftServer + */ + public RaftServerHandler(RaftServer raftServer) { + this.raftServer = raftServer; + } + + @Override + public void connected(Channel channel) { + } + + @Override + public void disconnected(Channel channel) { + } + + @Override + public void caught(Channel channel, Object message, Throwable exception) { + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return ProcessRequest.class; + } + + @Override + public void received(Channel channel, Object message) throws RemotingException { + + if (!(channel instanceof BoltChannel)) { + LOGGER.error("Raft receive message channel error type!"); + throw new RemotingException("Raft receive message channel error type!"); + } + + if (!(message instanceof ProcessRequest)) { + LOGGER.error("Raft receive message error type!"); + throw new RemotingException("Raft receive message error type!"); + } + + BoltChannel boltChannel = (BoltChannel) channel; + AsyncContext asyncContext = boltChannel.getAsyncContext(); + + if (!raftServer.getFsm().isLeader()) { + asyncContext.sendResponse(ProcessResponse.redirect(raftServer.redirect()).build()); + return; + } + ProcessRequest processRequest = (ProcessRequest) message; + + long start = System.currentTimeMillis(); + + Method method = Processor.getInstance().getWorkMethod(processRequest); + + if (Processor.getInstance().isLeaderReadMethod(method)) { + Object obj = Processor.getInstance().process(method, processRequest); + long cost = System.currentTimeMillis() - start; + LOGGER.info("Raft server process request self cost:{},request={}", cost, processRequest); + asyncContext.sendResponse(obj); + } else { + LeaderTaskClosure closure = new LeaderTaskClosure(); + closure.setRequest(processRequest); + closure.setDone(status -> { + long cost = System.currentTimeMillis() - start; + LOGGER.info("Raft server process request by task cost:{},request={},status={}", cost, processRequest, + status); + if (status.isOk()) { + asyncContext.sendResponse(closure.getResponse()); + } else { + asyncContext.sendResponse(ProcessResponse.fail(status.getErrorMsg()).build()); + } + }); + + Task task = createTask(closure, processRequest); + + raftServer.getNode().apply(task); + } + } + + protected Task createTask(LeaderTaskClosure closure, ProcessRequest request) { + + final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + Hessian2Output hessianOutput = new Hessian2Output(byteStream); + SerializerFactory serializerFactory = new SerializerFactory(); + hessianOutput.setSerializerFactory(serializerFactory); + try { + hessianOutput.writeObject(request); + hessianOutput.close(); + } catch (IOException e) { + LOGGER.error("Raft receive message serialize error!", e); + } + + byte[] cmdBytes = byteStream.toByteArray(); + + ByteBuffer data = ByteBuffer.allocate(cmdBytes.length); + data.put(cmdBytes); + data.flip(); + return new Task(data, closure); + } + + @Override + public Object reply(Channel channel, Object message) { + return null; + } + + @Override + public InvokeType getInvokeType() { + return InvokeType.ASYNC; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/AbstractSnapshotProcess.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/AbstractSnapshotProcess.java new file mode 100644 index 000000000..1ce076dc2 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/AbstractSnapshotProcess.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +import com.alipay.sofa.registry.jraft.command.CommandCodec; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.util.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; + +/** + * + * @author shangyu.wh + * @version $Id: AbstractSnapshotProcess.java, v 0.1 2018-05-29 12:12 shangyu.wh Exp $ + */ +public abstract class AbstractSnapshotProcess implements SnapshotProcess { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSnapshotProcess.class); + + /** + * save snapshot to file + * @param path + * @param values + * @return + */ + public boolean save(String path, Object values) { + try { + FileUtils.writeByteArrayToFile(new File(path), CommandCodec.encodeCommand(values), + false); + return true; + } catch (IOException e) { + LOGGER.error("Fail to save snapshot", e); + return false; + } + } + + /** + * load snapshot from file + * @param path + * @param clazz + * @param + * @return + * @throws IOException + */ + public T load(String path, Class clazz) throws IOException { + byte[] bs = FileUtils.readFileToByteArray(new File(path)); + if (bs != null && bs.length > 0) { + return CommandCodec.decodeCommand(bs, clazz); + } + throw new IOException("Fail to load snapshot from " + path + ", content: " + + Arrays.toString(bs)); + } + +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/FollowerProcessListener.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/FollowerProcessListener.java new file mode 100644 index 000000000..3f1d0bfff --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/FollowerProcessListener.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +import com.alipay.sofa.jraft.entity.PeerId; + +/** + * + * @author shangyu.wh + * @version $Id: FollowerProcessListener.java, v 0.1 2018-06-23 15:10 shangyu.wh Exp $ + */ +public interface FollowerProcessListener { + + void startProcess(PeerId leader); + + void stopProcess(PeerId leader); +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderProcessListener.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderProcessListener.java new file mode 100644 index 000000000..b26637338 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderProcessListener.java @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +/** + * + * @author shangyu.wh + * @version $Id: LeaderProcessListener.java, v 0.1 2018-05-28 12:17 shangyu.wh Exp $ + */ +public interface LeaderProcessListener { + + void startProcess(); + + void stopProcess(); +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderTaskClosure.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderTaskClosure.java new file mode 100644 index 000000000..12d4337d5 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/LeaderTaskClosure.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +import com.alipay.sofa.jraft.Closure; +import com.alipay.sofa.jraft.Status; +import com.alipay.sofa.registry.jraft.command.ProcessRequest; + +/** + * + * @author shangyu.wh + * @version $Id: LeaderTaskClosure.java, v 0.1 2018-05-21 12:18 shangyu.wh Exp $ + */ +public class LeaderTaskClosure implements Closure { + + private ProcessRequest request; + private Closure done; + private Object response; + + @Override + public void run(Status status) { + if (this.done != null) { + done.run(status); + } + } + + /** + * Getter method for property request. + * + * @return property value of request + */ + public ProcessRequest getRequest() { + return request; + } + + /** + * Setter method for property request. + * + * @param request value to be assigned to property request + */ + public void setRequest(ProcessRequest request) { + this.request = request; + } + + /** + * Setter method for property done. + * + * @param done value to be assigned to property done + */ + public void setDone(Closure done) { + this.done = done; + } + + /** + * Getter method for property response. + * + * @return property value of response + */ + public Object getResponse() { + return response; + } + + /** + * Setter method for property response. + * + * @param response value to be assigned to property response + */ + public void setResponse(Object response) { + this.response = response; + } +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/Processor.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/Processor.java new file mode 100644 index 000000000..a395a365d --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/Processor.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +import com.alipay.sofa.registry.jraft.bootstrap.ServiceStateMachine; +import com.alipay.sofa.registry.jraft.command.ProcessRequest; +import com.alipay.sofa.registry.jraft.command.ProcessResponse; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.store.api.annotation.ReadOnLeader; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * + * @author shangyu.wh + * @version $Id: Processor.java, v 0.1 2018-05-17 19:05 shangyu.wh Exp $ + */ +public class Processor { + + private static final Logger LOG = LoggerFactory + .getLogger(Processor.class); + + private Map> workerMethods = new HashMap<>(); + + private Map workers = new HashMap<>(); + + private static volatile Processor instance; + + /** + * get processor instance + * @return + */ + public static Processor getInstance() { + if (instance == null) { + synchronized (Processor.class) { + if (instance == null) { + instance = new Processor(); + } + } + } + return instance; + } + + public void addWorker(String serviceId, Class interfaceClazz, Object target) { + if (workers.get(serviceId) != null) { + LOG.warn("Service {} has bean existed!", serviceId); + return; + } + + Map publicMethods = new HashMap(); + for (Method m : interfaceClazz.getMethods()) { + StringBuilder mSigs = new StringBuilder(); + mSigs.append(m.getName()); + for (Class paramType : m.getParameterTypes()) { + mSigs.append(paramType.getName()); + } + publicMethods.put(mSigs.toString(), m); + } + + workerMethods.put(serviceId, publicMethods); + workers.put(serviceId, target); + } + + public ProcessResponse process(ProcessRequest request) { + String methodName = request.getMethodName(); + String serviceId = request.getServiceName(); + Object target = workers.get(serviceId); + if (target == null) { + LOG.warn("Can not find service {} from process!", serviceId); + return ProcessResponse.fail( + String.format("Can not find service %s from process!", serviceId)).build(); + } + + try { + StringBuilder methodKeyBuffer = new StringBuilder(); + methodKeyBuffer.append(methodName); + String[] sig = request.getMethodArgSigs(); + for (int i = 0; i < sig.length; i++) { + methodKeyBuffer.append(sig[i]); + } + Method appServiceMethod = workerMethods.get(serviceId).get(methodKeyBuffer.toString()); + if (appServiceMethod == null) { + LOG.error("Can not find method {} from processor by serviceId {}", methodName, + serviceId); + throw new NoSuchMethodException("Can not find method from processor!"); + } + + Object[] methodArg = request.getMethodArgs(); + MethodHandle methodHandle = MethodHandles.lookup().unreflect(appServiceMethod); + Object ret = methodHandle.bindTo(target).invokeWithArguments(methodArg); + if (ret != null) { + return ProcessResponse.ok(ret).build(); + } else { + return ProcessResponse.ok().build(); + } + + } catch (Throwable e) { + LOG.error("Process service request {} error!", request, e); + return ProcessResponse.fail( + String.format("Process service %s method %s error!", serviceId, methodName)) + .build(); + } + } + + public ProcessResponse process(Method method, ProcessRequest request) { + String methodName = request.getMethodName(); + String serviceId = request.getServiceName(); + Object target = workers.get(serviceId); + if (target == null) { + LOG.warn("Can not find service {} from process!", serviceId); + return ProcessResponse.fail( + String.format("Can not find service %s from process!", serviceId)).build(); + } + + try { + Object[] methodArg = request.getMethodArgs(); + MethodHandle methodHandle = MethodHandles.lookup().unreflect(method); + Object ret = methodHandle.bindTo(target).invokeWithArguments(methodArg); + if (ret != null) { + return ProcessResponse.ok(ret).build(); + } else { + return ProcessResponse.ok().build(); + } + + } catch (Throwable e) { + LOG.error("Process service request {} error!", request, e); + return ProcessResponse.fail( + String.format("Process service %s method %s error!", serviceId, methodName)) + .build(); + } + } + + public Method getWorkMethod(ProcessRequest request) { + String methodName = request.getMethodName(); + String serviceId = request.getServiceName(); + try { + + StringBuilder methodKeyBuffer = new StringBuilder(); + methodKeyBuffer.append(methodName); + String[] sig = request.getMethodArgSigs(); + for (int i = 0; i < sig.length; i++) { + methodKeyBuffer.append(sig[i]); + } + Method appServiceMethod = workerMethods.get(serviceId).get(methodKeyBuffer.toString()); + if (appServiceMethod == null) { + LOG.error("Can not find method {} from processor by serviceId {}", methodName, + serviceId); + throw new NoSuchMethodException("Can not find method from processor!"); + } + return appServiceMethod; + } catch (Exception e) { + LOG.error("Process request {} get WorkMethod error!", request, e); + throw new RuntimeException(String.format("Process request %s get WorkMethod error!", + request)); + } + } + + public Map getWorkers() { + return workers; + } + + public boolean isLeaderReadMethod(Method method) { + if (ServiceStateMachine.getInstance().isLeader()) { + return method != null && method.isAnnotationPresent(ReadOnLeader.class); + } + return false; + } + +} diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/ProxyHandler.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/ProxyHandler.java new file mode 100644 index 000000000..f96098cf2 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/ProxyHandler.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +import com.alipay.sofa.registry.jraft.bootstrap.RaftClient; +import com.alipay.sofa.registry.jraft.command.ProcessRequest; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * + * @author shangyu.wh + * @version $Id: ProxyHandler.java, v 0.1 2018-05-23 12:19 shangyu.wh Exp $ + */ +public class ProxyHandler implements InvocationHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProxyHandler.class); + + private final Class interfaceType; + + private final String serviceId; + + private final RaftClient client; + + /** + * constructor + * @param interfaceType + * @param serviceId + * @param client + */ + public ProxyHandler(Class interfaceType, String serviceId, RaftClient client) { + this.interfaceType = interfaceType; + this.serviceId = serviceId; + this.client = client; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + try { + + ProcessRequest request = new ProcessRequest(); + request.setMethodArgSigs(createParamSignature(method.getParameterTypes())); + request.setMethodName(method.getName()); + request.setMethodArgs(args); + + request.setServiceName(serviceId); + + if (Processor.getInstance().isLeaderReadMethod(method)) { + return doInvokeMethod(request); + } + return client.sendRequest(request); + } catch (Throwable e) { + LOGGER.error("Proxy invoke interface {} method {} got error!", interfaceType.getName(), + method.getName(), e); + throw new RuntimeException(String.format( + "Proxy invoke interface %s method %s got error!", interfaceType.getName(), + method.getName()), e); + } + } + + private Object doInvokeMethod(ProcessRequest request) { + try { + + Object target = Processor.getInstance().getWorkers().get(serviceId); + if (target == null) { + LOGGER.error("Can not find service {} from process!", serviceId); + throw new RuntimeException(String.format("Can not find service %s from process!", + serviceId)); + } + + Method method = Processor.getInstance().getWorkMethod(request); + + MethodHandle methodHandle = MethodHandles.lookup().unreflect(method); + return methodHandle.bindTo(target).invokeWithArguments(request.getMethodArgs()); + } catch (Throwable e) { + LOGGER.error("Directly invoke read only service {} method {} error!", + request.getServiceName(), request.getMethodName(), e); + throw new RuntimeException(String.format( + "Directly invoke read only service %s method %s error!", request.getServiceName(), + request.getMethodName()), e); + } + } + + private String[] createParamSignature(Class[] args) { + if (args == null || args.length == 0) { + return new String[] {}; + } + String[] paramSig = new String[args.length]; + for (int x = 0; x < args.length; x++) { + paramSig[x] = args[x].getName(); + } + return paramSig; + } + +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/SnapshotProcess.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/SnapshotProcess.java new file mode 100644 index 000000000..c02f5d4d5 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/processor/SnapshotProcess.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.processor; + +import java.util.Set; + +/** + * + * @author shangyu.wh + * @version $Id: SnapshortProcess.java, v 0.1 2018-05-29 11:53 shangyu.wh Exp $ + */ +public interface SnapshotProcess { + + boolean save(String path); + + boolean load(String path); + + SnapshotProcess copy(); + + Set getSnapshotFileNames(); +} \ No newline at end of file diff --git a/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/service/PersistenceDataDBService.java b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/service/PersistenceDataDBService.java new file mode 100644 index 000000000..0cf1f9ed1 --- /dev/null +++ b/server/store/jraft/src/main/java/com/alipay/sofa/registry/jraft/service/PersistenceDataDBService.java @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.jraft.service; + +import com.alipay.sofa.registry.jraft.processor.AbstractSnapshotProcess; +import com.alipay.sofa.registry.jraft.processor.SnapshotProcess; +import com.alipay.sofa.registry.log.Logger; +import com.alipay.sofa.registry.log.LoggerFactory; +import com.alipay.sofa.registry.store.api.DBResponse; +import com.alipay.sofa.registry.store.api.DBService; +import com.alipay.sofa.registry.store.api.annotation.RaftService; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * @author shangyu.wh + * @version $Id: PersistenceDataDBService.java, v 0.1 2018-06-22 17:23 shangyu.wh Exp $ + */ +@RaftService +public class PersistenceDataDBService extends AbstractSnapshotProcess implements DBService { + + private static final Logger LOGGER = LoggerFactory + .getLogger(PersistenceDataDBService.class); + + private ConcurrentHashMap serviceMap = new ConcurrentHashMap<>(); + + private Set snapShotFileNames = new HashSet<>(); + + /** + * constructor + */ + public PersistenceDataDBService() { + } + + /** + * constructor + * @param serviceMap + */ + public PersistenceDataDBService(ConcurrentHashMap serviceMap) { + this.serviceMap = serviceMap; + } + + @Override + public SnapshotProcess copy() { + return new PersistenceDataDBService(new ConcurrentHashMap<>(serviceMap)); + } + + @Override + public void openDB(String dbName, Class entityClass) { + } + + @Override + public boolean put(String key, Object value) { + if (key == null || value == null) { + LOGGER.error("key {} or value {} can't be null", key, value); + return false; + //throw new IllegalArgumentException("key or value can't be null!"); + } + Object ret = serviceMap.put(key, value); + if (ret != null) { + LOGGER.warn("value {} with key {} will be override", ret, key); + } + return true; + } + + @Override + public DBResponse get(String key) { + if (key == null) { + LOGGER.error("key can't be null"); + throw new IllegalArgumentException("query key can't be null"); + } + Object ret = serviceMap.get(key); + return ret != null ? DBResponse.ok(ret).build() : DBResponse.notfound().build(); + } + + @Override + public boolean update(String key, Object value) { + if (key == null || value == null) { + LOGGER.error("key {} or value {} can't be null", key, value); + return false; + } + Object ret = serviceMap.put(key, value); + if (ret != null) { + LOGGER.warn("value {} with key {} will be override", ret, key); + } + return true; + } + + @Override + public boolean remove(String key) { + if (key == null) { + LOGGER.error("key can't be null"); + return false; + } + Object obj = serviceMap.remove(key); + if (obj == null) { + LOGGER.warn("remove key {} can't be found!", key); + return false; + } + return true; + } + + @Override + public boolean save(String path) { + return save(path, serviceMap); + } + + @Override + public boolean load(String path) { + try { + ConcurrentHashMap map = load(path, serviceMap.getClass()); + serviceMap.clear(); + serviceMap.putAll(map); + return true; + } catch (IOException e) { + LOGGER.error("Load serviceMap data error!", e); + return false; + } + } + + @Override + public Set getSnapshotFileNames() { + if (!snapShotFileNames.isEmpty()) { + return snapShotFileNames; + } + snapShotFileNames.add(this.getClass().getSimpleName()); + return snapShotFileNames; + } +} \ No newline at end of file diff --git a/server/store/pom.xml b/server/store/pom.xml new file mode 100644 index 000000000..0d6a266d6 --- /dev/null +++ b/server/store/pom.xml @@ -0,0 +1,25 @@ + + + + com.alipay.sofa + registry-server-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + registry-store + pom + + + ../../ + + + + api + jraft + + + + diff --git a/test/pom.xml b/test/pom.xml new file mode 100644 index 000000000..889a37b6e --- /dev/null +++ b/test/pom.xml @@ -0,0 +1,35 @@ + + + + com.alipay.sofa + registry-parent + 5.2.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + registry-test + + + ../ + + + + + com.alipay.sofa + registry-server-integration + + + org.springframework.boot + spring-boot-starter-test + test + + + com.alipay.sofa + registry-client-all + test + + + diff --git a/test/src/main/java/com/alipay/sofa/registry/server/test/TestRegistryMain.java b/test/src/main/java/com/alipay/sofa/registry/server/test/TestRegistryMain.java new file mode 100644 index 000000000..ace565efe --- /dev/null +++ b/test/src/main/java/com/alipay/sofa/registry/server/test/TestRegistryMain.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.server.test; + +import com.alipay.sofa.registry.server.integration.RegistryApplication; +import com.alipay.sofa.registry.util.FileUtils; +import org.springframework.context.ConfigurableApplicationContext; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_DATA_CENTER; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_ZONE; + +/** + @author xuanbei + @since 2019/3/9 + */ +public class TestRegistryMain { + public static final String LOCAL_ADDRESS = "127.0.0.1"; + + private Map configs = new HashMap<>(); + + public TestRegistryMain() { + configs.put("nodes.metaNode", DEFAULT_DATA_CENTER + ":" + LOCAL_ADDRESS); + configs.put("nodes.localDataCenter", DEFAULT_DATA_CENTER); + configs.put("nodes.localRegion", DEFAULT_ZONE); + } + + public void startRegistry() throws Exception { + for (Map.Entry entry : configs.entrySet()) { + System.setProperty(entry.getKey(), entry.getValue()); + } + FileUtils.forceDelete(new File(System.getProperty("user.home") + File.separator + + "raftData")); + RegistryApplication.main(new String[] {}); + Thread.sleep(3000); + } + + public void stopRegistry() throws Exception { + RegistryApplication.stop(); + } + + public void startRegistryWithConfig(Map configs) throws Exception { + this.configs.putAll(configs); + this.startRegistry(); + } + + public ConfigurableApplicationContext getMetaApplicationContext() { + return RegistryApplication.getMetaApplicationContext(); + } + + public ConfigurableApplicationContext getSessionApplicationContext() { + return RegistryApplication.getSessionApplicationContext(); + } + + public ConfigurableApplicationContext getDataApplicationContext() { + return RegistryApplication.getDataApplicationContext(); + } +} diff --git a/test/src/main/resources/application.properties b/test/src/main/resources/application.properties new file mode 100644 index 000000000..20ce078a6 --- /dev/null +++ b/test/src/main/resources/application.properties @@ -0,0 +1,43 @@ +#spring +spring.main.banner-mode=off + +## session configuration +session.server.logging.level=INFO +session.server.serverPort=9600 +session.server.httpServerPort=9603 +session.server.metaServerPort=9610 +session.server.dataServerPort=9620 +session.server.sessionServerRegion=DEFAULT_ZONE +session.server.sessionServerDataCenter=DefaultDataCenter +session.server.syncHeartbeat.fixedDelay=30000 +session.server.syncExceptionData.fixedDelay=30000 +session.server.printTask.fixedDelay=30000 +session.server.schedulerHeartbeatTimeout=30 +session.server.schedulerHeartbeatFirstDelay=30 +session.server.schedulerHeartbeatExpBackOffBound=10 +session.server.schedulerFetchDataTimeout=3 +session.server.schedulerFetchDataFirstDelay=3 +session.server.schedulerFetchDataExpBackOffBound=10 + +## data node configuration +data.server.logging.level=INFO +data.server.port=9620 +data.server.syncDataPort=9621 +data.server.httpServerPort=9622 +data.server.queueCount=4 +data.server.queueSize=10240 +data.server.notifyIntervalMs=100 +data.server.rpcTimeout=3000 +data.server.metaServerPort=9611 +data.server.storeNodes=3 +data.server.numberOfReplicas=1000 + +## meta node configuration +meta.server.logging.level=INFO +meta.server.sessionServerPort=9610 +meta.server.dataServerPort=9611 +meta.server.metaServerPort=9612 +meta.server.raftServerPort=9614 +meta.server.httpServerPort=9615 +meta.server.raftGroup=MetaServerRaftGroup +meta.server.decisionMode=RUNTIME \ No newline at end of file diff --git a/test/src/main/resources/logback-spring.xml b/test/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..de377f7e5 --- /dev/null +++ b/test/src/main/resources/logback-spring.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + + + + true + + ${LOG_LEVEL} + + + ERROR + DENY + + ${LOG_HOME}/registry-test.log + + ${LOG_HOME}/registry-test.log.%d{yyyy-MM-dd} + 30 + + + [%d{ISO8601}][%p][%t][%c{0}] - %m%n + ${LOG_ENCODE} + + + + + + + + \ No newline at end of file diff --git a/test/src/test/java/com/alipay/sofa/registry/test/BaseIntegrationTest.java b/test/src/test/java/com/alipay/sofa/registry/test/BaseIntegrationTest.java new file mode 100644 index 000000000..2693e7cff --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/BaseIntegrationTest.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.client.api.ConfigDataObserver; +import com.alipay.sofa.registry.client.api.RegistryClientConfig; +import com.alipay.sofa.registry.client.api.SubscriberDataObserver; +import com.alipay.sofa.registry.client.api.model.ConfigData; +import com.alipay.sofa.registry.client.api.model.UserData; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClient; +import com.alipay.sofa.registry.client.provider.DefaultRegistryClientConfigBuilder; +import com.alipay.sofa.registry.client.remoting.Client; +import com.alipay.sofa.registry.client.remoting.ClientConnection; +import com.alipay.sofa.registry.client.task.AbstractWorkerThread; +import com.alipay.sofa.registry.client.task.WorkerThread; +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.sessionserver.CancelAddressRequest; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.remoting.jersey.JerseyClient; +import com.alipay.sofa.registry.server.test.TestRegistryMain; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.context.ConfigurableApplicationContext; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei 18/12/1 + */ +@SpringBootConfiguration +public class BaseIntegrationTest { + private static final AtomicBoolean STARTED = new AtomicBoolean(false); + + public static final String LOCAL_ADDRESS = NetUtil.getLocalAddress() + .getHostAddress(); + public static final String LOCAL_DATACENTER = "DefaultDataCenter"; + public static final String LOCAL_REGION = "DEFAULT_ZONE"; + protected static ConfigurableApplicationContext metaApplicationContext; + protected static ConfigurableApplicationContext sessionApplicationContext; + protected static ConfigurableApplicationContext dataApplicationContext; + + protected DefaultRegistryClient registryClient1; + + protected DefaultRegistryClient registryClient2; + + protected Channel sessionChannel; + + protected Channel dataChannel; + + protected Channel metaChannel; + + protected volatile String dataId; + + protected volatile UserData userData; + + protected volatile ConfigData configData; + + @Value("${session.server.httpServerPort}") + protected int sessionPort; + + @Value("${meta.server.httpServerPort}") + protected int metaPort; + + @Value("${data.server.httpServerPort}") + protected int dataPort; + + @Value("${meta.server.raftServerPort}") + protected int raftPort; + + @Value("${session.server.serverPort}") + protected int sessionServerPort; + + @Value("${data.server.syncDataPort}") + protected int syncDataPort; + + @BeforeClass + public static void beforeClass() throws Exception { + if (STARTED.compareAndSet(false, true)) { + Map configs = new HashMap<>(); + configs.put("nodes.metaNode", LOCAL_DATACENTER + ":" + LOCAL_ADDRESS); + configs.put("nodes.localDataCenter", LOCAL_DATACENTER); + configs.put("nodes.localRegion", LOCAL_REGION); + + TestRegistryMain testRegistryMain = new TestRegistryMain(); + testRegistryMain.startRegistryWithConfig(configs); + metaApplicationContext = testRegistryMain.getMetaApplicationContext(); + sessionApplicationContext = testRegistryMain.getSessionApplicationContext(); + dataApplicationContext = testRegistryMain.getDataApplicationContext(); + } + } + + @Before + public void before() throws Exception { + if (registryClient1 == null) { + RegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setAppName("testApp1").setDataCenter(LOCAL_DATACENTER).setZone(LOCAL_REGION) + .setRegistryEndpoint(LOCAL_ADDRESS).setRegistryEndpointPort(sessionPort).build(); + registryClient1 = new DefaultRegistryClient(config); + registryClient1.init(); + } + + if (registryClient2 == null) { + RegistryClientConfig config = DefaultRegistryClientConfigBuilder.start() + .setAppName("testApp2").setDataCenter(LOCAL_DATACENTER) + .setRegistryEndpoint(LOCAL_ADDRESS).setZone(LOCAL_REGION) + .setRegistryEndpointPort(sessionPort).build(); + registryClient2 = new DefaultRegistryClient(config); + registryClient2.init(); + } + + if (sessionChannel == null || dataChannel == null || metaChannel == null) { + sessionChannel = JerseyClient.getInstance() + .connect(new URL(LOCAL_ADDRESS, sessionPort)); + dataChannel = JerseyClient.getInstance().connect(new URL(LOCAL_ADDRESS, dataPort)); + metaChannel = JerseyClient.getInstance().connect(new URL(LOCAL_ADDRESS, metaPort)); + } + + dataId = null; + userData = null; + } + + @After + public void after() throws Exception { + dataId = null; + userData = null; + configData = null; + } + + public class MySubscriberDataObserver implements SubscriberDataObserver { + @Override + public void handleData(String dataId, UserData data) { + BaseIntegrationTest.this.dataId = dataId; + BaseIntegrationTest.this.userData = data; + } + } + + public class MyConfigDataObserver implements ConfigDataObserver { + @Override + public void handleData(String dataId, ConfigData configData) { + BaseIntegrationTest.this.dataId = dataId; + BaseIntegrationTest.this.configData = configData; + } + } + + protected void clientOff() throws Exception { + List connectIds = new ArrayList<>(); + connectIds.add(LOCAL_ADDRESS + ":" + getSourcePort(registryClient1)); + connectIds.add(LOCAL_ADDRESS + ":" + getSourcePort(registryClient2)); + CommonResponse response = sessionChannel + .getWebTarget() + .path("api/clients/off") + .request() + .post(Entity.entity(new CancelAddressRequest(connectIds), MediaType.APPLICATION_JSON), + CommonResponse.class); + assertTrue(response.isSuccess()); + Thread.sleep(1000); + } + + protected int getSourcePort(DefaultRegistryClient registryClient) throws Exception { + Field workerThreadField = DefaultRegistryClient.class.getDeclaredField("workerThread"); + workerThreadField.setAccessible(true); + WorkerThread workerThread = (WorkerThread) workerThreadField.get(registryClient); + + Field clientField = AbstractWorkerThread.class.getDeclaredField("client"); + clientField.setAccessible(true); + Client client = (Client) clientField.get(workerThread); + client.ensureConnected(); + + Field clientConnectionField = ClientConnection.class.getDeclaredField("clientConnection"); + clientConnectionField.setAccessible(true); + Connection clientConnection = (Connection) clientConnectionField.get(client); + return clientConnection.getLocalPort(); + } + + protected Object bytes2Object(byte[] bytes) throws IOException, ClassNotFoundException { + Object object = null; + if (bytes != null) { + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + ObjectInputStream input = null; + try { + input = new ObjectInputStream(bis); + object = input.readObject(); + } finally { + if (input != null) { + input.close(); + } + } + } + return object; + } + + protected byte[] object2bytes(Object object) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream javaos = null; + try { + javaos = new ObjectOutputStream(bos); + javaos.writeObject(object); + } finally { + try { + javaos.close(); + } catch (IOException ioe) { + //do nothing + } + } + return bos.toByteArray(); + } +} \ No newline at end of file diff --git a/test/src/test/java/com/alipay/sofa/registry/test/pubsub/PubSubTest.java b/test/src/test/java/com/alipay/sofa/registry/test/pubsub/PubSubTest.java new file mode 100644 index 000000000..162cfc3cf --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/pubsub/PubSubTest.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.pubsub; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static org.junit.Assert.assertEquals; + +/** + * @author xuanbei 18/12/2 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class PubSubTest extends BaseIntegrationTest { + /** + * Publisher test. + * + * @throws InterruptedException the interrupted exception + */ + @Test + public void publisherTest() throws InterruptedException { + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test publish"; + + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.dataCenter); + + registryClient1.register(subReg); + + Thread.sleep(1000L); + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } + + /** + * Subscriber test. + * + * @throws InterruptedException the interrupted exception + */ + @Test + public void subscriberTest() throws InterruptedException { + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test subscriber"; + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.dataCenter); + registryClient1.register(subReg); + Thread.sleep(500L); + + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(1000L); + + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } + + /** + * Multi Client test. + * + * @throws InterruptedException the interrupted exception + */ + @Test + public void multiClientTest() throws InterruptedException { + + // registryClient1 publish data, registryClient2 subscriber + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test multi client publish"; + + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.zone); + + registryClient2.register(subReg); + + Thread.sleep(1000L); + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + registryClient2.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + + // registryClient1 subscriber, registryClient2 publish data + dataId = "test-dataId-" + System.currentTimeMillis(); + value = "test multi client subscriber"; + + subReg = new SubscriberRegistration(dataId, new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.global); + registryClient1.register(subReg); + Thread.sleep(500L); + + registration = new PublisherRegistration(dataId); + registryClient2.register(registration, value); + Thread.sleep(1000L); + + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient2.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + + // registryClient1 subscriber, registryClient1 and registryClient2 both publish data + dataId = "test-dataId-" + System.currentTimeMillis(); + value = "test multi client subscriber"; + + subReg = new SubscriberRegistration(dataId, new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.zone); + registryClient1.register(subReg); + Thread.sleep(500L); + + registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + registryClient2.register(registration, value); + Thread.sleep(1000L); + + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(2, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(1)); + + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + registryClient2.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } +} \ No newline at end of file diff --git a/test/src/test/java/com/alipay/sofa/registry/test/pubsub/TempPublisherTest.java b/test/src/test/java/com/alipay/sofa/registry/test/pubsub/TempPublisherTest.java new file mode 100644 index 000000000..19628ec7f --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/pubsub/TempPublisherTest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.pubsub; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.common.model.PublishType; +import com.alipay.sofa.registry.common.model.ServerDataBox; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.server.session.node.service.DataNodeService; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static org.junit.Assert.assertEquals; + +/** + * @author xuanbei + * @since 2019/1/15 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class TempPublisherTest extends BaseIntegrationTest { + @Test + public void doTest() throws Exception { + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test publish temp data"; + + // register SubscriberRegistration + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.zone); + registryClient1.register(subReg); + Thread.sleep(1000L); + assertEquals(dataId, this.dataId); + assertEquals(0, userData.getZoneData().size()); + + // publish temp data + Publisher tempPublisher = new Publisher(); + tempPublisher.setPublishType(PublishType.TEMPORARY); + tempPublisher.setCell(LOCAL_REGION); + tempPublisher.setDataId(dataId); + tempPublisher.setGroup(DEFAULT_GROUP); + tempPublisher.setInstanceId(DEFAULT_INSTANCE_ID); + tempPublisher.setVersion(System.currentTimeMillis()); + tempPublisher.setRegisterTimestamp(System.currentTimeMillis()); + tempPublisher.setClientRegisterTimestamp(System.currentTimeMillis()); + tempPublisher.setRegisterId(UUID.randomUUID().toString()); + tempPublisher.setDataInfoId(DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, + DEFAULT_GROUP)); + List dataBoxData = new ArrayList(1); + dataBoxData.add(new ServerDataBox(object2bytes(value))); + tempPublisher.setDataList(dataBoxData); + sessionApplicationContext.getBean(DataNodeService.class).register(tempPublisher); + + // data size is 1 + Thread.sleep(1000L); + assertEquals(dataId, this.dataId); + assertEquals(1, userData.getZoneData().size()); + userData = null; + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + + // register another SubscriberRegistration, data size is 0 + subReg = new SubscriberRegistration(dataId, new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.zone); + registryClient1.register(subReg); + Thread.sleep(1000L); + assertEquals(dataId, this.dataId); + assertEquals(0, userData.getZoneData().size()); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/HealthCheckTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/HealthCheckTest.java new file mode 100644 index 000000000..d6d28b8f8 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/HealthCheckTest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource; + +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertTrue; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class HealthCheckTest extends BaseIntegrationTest { + @Test + public void metaHealthCheckTest() { + assertTrue(metaChannel.getWebTarget().path("health/check").request(APPLICATION_JSON) + .get(CommonResponse.class).isSuccess()); + } + + @Test + public void dataHealthCheckTest() { + assertTrue(dataChannel.getWebTarget().path("health/check").request(APPLICATION_JSON) + .get(CommonResponse.class).isSuccess()); + } + + @Test + public void sessionHealthCheckTest() { + assertTrue(sessionChannel.getWebTarget().path("health/check").request(APPLICATION_JSON) + .get(CommonResponse.class).isSuccess()); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/data/DataDigestResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/data/DataDigestResourceTest.java new file mode 100644 index 000000000..61ec056d1 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/data/DataDigestResourceTest.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.data; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import java.util.HashMap; +import java.util.Map; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class DataDigestResourceTest extends BaseIntegrationTest { + private volatile String dataId; + private volatile String value; + + @Before + public void before() throws Exception { + super.before(); + clientOff(); + dataId = "test-dataId-" + System.currentTimeMillis(); + value = "DataDigestResourceTest"; + + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.dataCenter); + registryClient1.register(subReg); + Thread.sleep(500L); + } + + @After + public void after() throws Exception { + super.after(); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } + + @Test + public void testGetDatumByDataInfoId() throws Exception { + Map datumMap = dataChannel.getWebTarget().path("digest/datum/query") + .queryParam("dataId", dataId).queryParam("group", DEFAULT_GROUP) + .queryParam("instanceId", DEFAULT_INSTANCE_ID) + .queryParam("dataCenter", LOCAL_DATACENTER).request(APPLICATION_JSON) + .get(new GenericType>() { + }); + assertTrue(datumMap.size() == 1); + assertEquals(dataId, datumMap.get(LOCAL_DATACENTER).getDataId()); + assertEquals(1, datumMap.get(LOCAL_DATACENTER).getPubMap().size()); + assertEquals(value, bytes2Object(datumMap.get(LOCAL_DATACENTER).getPubMap().values() + .iterator().next().getDataList().get(0).getBytes())); + } + + @Test + public void testGetPublishersByConnectId() throws Exception { + Map parameters = new HashMap<>(); + parameters.put(LOCAL_ADDRESS, String.valueOf(getSourcePort(registryClient1))); + Map> publisherMap = dataChannel + .getWebTarget() + .path("digest/connect/query") + .request(APPLICATION_JSON) + .post(Entity.entity(parameters, MediaType.APPLICATION_JSON), + new GenericType>>() { + }); + assertEquals(1, publisherMap.size()); + assertEquals(1, + publisherMap.get(LOCAL_ADDRESS + ":" + String.valueOf(getSourcePort(registryClient1))) + .size()); + assertEquals(dataId, + publisherMap.get(LOCAL_ADDRESS + ":" + String.valueOf(getSourcePort(registryClient1))) + .values().iterator().next().getDataId()); + assertEquals( + value, + bytes2Object(publisherMap + .get(LOCAL_ADDRESS + ":" + String.valueOf(getSourcePort(registryClient1))).values() + .iterator().next().getDataList().get(0).getBytes())); + } + + @Test + public void testGetDatumCount() { + String countResult = dataChannel.getWebTarget().path("digest/datum/count") + .request(APPLICATION_JSON).get(String.class); + assertTrue(countResult.contains("[Publisher] size of publisher in DefaultDataCenter is 1")); + } +} \ No newline at end of file diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaDigestResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaDigestResourceTest.java new file mode 100644 index 000000000..baea8fac0 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaDigestResourceTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.meta; + +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Map; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class MetaDigestResourceTest extends BaseIntegrationTest { + @Test + public void testGetRegisterNodeByType() { + Map map = metaChannel.getWebTarget().path("digest/data/node/query") + .request(APPLICATION_JSON).get(Map.class); + assertTrue(map.size() == 1); + assertTrue(((Map) map.get(LOCAL_DATACENTER)).containsKey(LOCAL_ADDRESS)); + + map = metaChannel.getWebTarget().path("digest/meta/node/query").request(APPLICATION_JSON) + .get(Map.class); + assertTrue(map.size() == 1); + assertTrue(((Map) map.get(LOCAL_DATACENTER)).containsKey(LOCAL_ADDRESS)); + + map = metaChannel.getWebTarget().path("digest/session/node/query") + .request(APPLICATION_JSON).get(Map.class); + assertTrue(map.size() == 1); + assertTrue(((Map) map.get(LOCAL_DATACENTER)).containsKey(LOCAL_ADDRESS)); + } + + @Test + public void testGetPushSwitch() { + Map map = metaChannel.getWebTarget().path("digest/pushSwitch").request(APPLICATION_JSON) + .get(Map.class); + assertTrue("open".equals(map.get("pushSwitch"))); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaStoreResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaStoreResourceTest.java new file mode 100644 index 000000000..29b361808 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/MetaStoreResourceTest.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.meta; + +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Form; +import javax.ws.rs.core.MediaType; +import java.util.List; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class MetaStoreResourceTest extends BaseIntegrationTest { + @Test + public void testManageMetaStoreResource() { + List list = metaChannel.getWebTarget().path("manage/queryPeer").request(APPLICATION_JSON) + .get(List.class); + assertTrue(list.size() == 1); + assertEquals(LOCAL_ADDRESS, list.get(0)); + } + + @Test + public void testChangePeer() { + Form form = new Form(); + form.param("ipAddressList", LOCAL_ADDRESS); + Result result = metaChannel.getWebTarget().path("manage/changePeer") + .request(APPLICATION_JSON) + .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), Result.class); + assertTrue(result.isSuccess()); + } + + @Test + public void resetPeer() { + Form form = new Form(); + form.param("ipAddressList", LOCAL_ADDRESS); + Result result = metaChannel.getWebTarget().path("manage/resetPeer") + .request(APPLICATION_JSON) + .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE), Result.class); + assertTrue(result.isSuccess()); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/PersistentDataResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/PersistentDataResourceTest.java new file mode 100644 index 000000000..72f91bb7d --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/PersistentDataResourceTest.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.meta; + +import com.alipay.sofa.registry.common.model.console.PersistenceData; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class PersistentDataResourceTest extends BaseIntegrationTest { + @Test + public void testPersistentDataResource() throws Exception { + PersistenceData persistenceData = new PersistenceData(); + persistenceData.setData("PersistentDataResourceTest"); + persistenceData.setVersion(1024L); + persistenceData.setDataId("PersistentDataResourceTest"); + persistenceData.setGroup(DEFAULT_GROUP); + persistenceData.setInstanceId(DEFAULT_INSTANCE_ID); + + Result response = metaChannel.getWebTarget().path("persistentData/put").request() + .post(Entity.entity(persistenceData, MediaType.APPLICATION_JSON), Result.class); + assertTrue(response.isSuccess()); + Thread.sleep(500); + + response = metaChannel.getWebTarget().path("persistentData/remove").request() + .post(Entity.entity(persistenceData, MediaType.APPLICATION_JSON), Result.class); + assertTrue(response.isSuccess()); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/StopPushDataSwitchTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/StopPushDataSwitchTest.java new file mode 100644 index 000000000..b99e650f3 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/meta/StopPushDataSwitchTest.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.meta; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.core.model.Result; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.server.session.bootstrap.SessionServerConfig; +import com.alipay.sofa.registry.server.session.scheduler.task.Constant; +import com.alipay.sofa.registry.server.session.store.Interests; +import com.alipay.sofa.registry.server.session.store.ReSubscribers; +import com.alipay.sofa.registry.task.listener.TaskEvent; +import com.alipay.sofa.registry.task.listener.TaskListenerManager; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.util.CollectionUtils; + +import java.util.Map; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class StopPushDataSwitchTest extends BaseIntegrationTest { + @Test + public void testStopPushDataSwitch() throws Exception { + // open stop push switch + assertTrue(metaChannel.getWebTarget().path("stopPushDataSwitch/open") + .request(APPLICATION_JSON).get(Result.class).isSuccess()); + + // register Publisher & Subscriber, Subscriber get no data + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test stop publish data switch"; + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.dataCenter); + registryClient1.register(subReg); + Thread.sleep(1000L); + assertNull(this.dataId); + + // close stop push switch + assertTrue(metaChannel.getWebTarget().path("stopPushDataSwitch/close") + .request(APPLICATION_JSON).get(Result.class).isSuccess()); + Thread.sleep(1000L); + + // Subscriber get data, test data + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + // unregister Publisher & Subscriber + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } + + /** + * com.alipay.sofa.registry.server.session.scheduler.task.ProvideDataChangeFetchTask#fireReSubscriber has sleep 1 minute, invoke directly to save time. + * @throws Exception + */ + @Test + public void testStopPushDataSwitchByCode() throws Exception { + // open stop push switch + assertTrue(metaChannel.getWebTarget().path("stopPushDataSwitch/open").request(APPLICATION_JSON) + .get(Result.class) + .isSuccess()); + + // register Publisher & Subscriber, Subscriber get no data + String dataId = "test-dataId-hahhahahahha-" + System.currentTimeMillis(); + String value = "test stop publish data switch by code"; + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.dataCenter); + registryClient1.register(subReg); + Thread.sleep(1000L); + assertNull(this.dataId); + + // invoke code directly + Interests sessionInterests = sessionApplicationContext.getBean(Interests.class); + TaskListenerManager taskListenerManager = sessionApplicationContext.getBean(TaskListenerManager.class); + SessionServerConfig sessionServerConfig = sessionApplicationContext.getBean(SessionServerConfig.class); + if (sessionInterests instanceof ReSubscribers) { + ReSubscribers reSubscriber = (ReSubscribers) sessionInterests; + + Map> reSubscribers = reSubscriber + .getReSubscribers(); + if (reSubscribers != null && !reSubscribers.isEmpty()) { + reSubscribers.forEach((dataInfoId, subscribers) -> { + if (!CollectionUtils.isEmpty(subscribers)) { + sessionServerConfig.setStopPushSwitch(false); + TaskEvent taskEvent = new TaskEvent(dataInfoId, TaskEvent.TaskType.SUBSCRIBER_MULTI_FETCH_TASK); + taskEvent.setAttribute(Constant.PUSH_CLIENT_SUBSCRIBERS, subscribers.values()); + taskListenerManager.sendTaskEvent(taskEvent); + } + + }); + reSubscriber.clearReSubscribers(); + } + } + Thread.sleep(1000); + + // Subscriber get data, test data + assertEquals(dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + // unregister Publisher & Subscriber, close stop push switch + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + assertTrue(metaChannel.getWebTarget().path("stopPushDataSwitch/close").request(APPLICATION_JSON) + .get(Result.class) + .isSuccess()); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/session/ClientsOpenResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/session/ClientsOpenResourceTest.java new file mode 100644 index 000000000..507612ca0 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/session/ClientsOpenResourceTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.session; + +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class ClientsOpenResourceTest extends BaseIntegrationTest { + @Test + public void testClientOff() throws Exception { + clientOff(); + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test client off"; + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(1000L); + + String countResult = dataChannel.getWebTarget().path("digest/datum/count") + .request(APPLICATION_JSON).get(String.class); + assertTrue(countResult.contains("[Publisher] size of publisher in DefaultDataCenter is 1")); + + clientOff(); + countResult = dataChannel.getWebTarget().path("digest/datum/count") + .request(APPLICATION_JSON).get(String.class); + assertTrue(countResult.contains("[Publisher] size of publisher in DefaultDataCenter is 0")); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionDigestResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionDigestResourceTest.java new file mode 100644 index 000000000..6389bb207 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionDigestResourceTest.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.session; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.Subscriber; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.junit.Assert.assertEquals; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class SessionDigestResourceTest extends BaseIntegrationTest { + + private String dataId; + private String value; + + @Before + public void before() throws Exception { + super.before(); + dataId = "test-dataId-" + System.currentTimeMillis(); + value = "SessionDigestResourceTest"; + + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + SubscriberRegistration subReg = new SubscriberRegistration(dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.dataCenter); + registryClient1.register(subReg); + Thread.sleep(500L); + } + + @After + public void after() throws Exception { + super.after(); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.SUBSCRIBER); + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } + + @Test + public void testGetSessionDataByDataInfoId() throws Exception { + Map> publisherMap = sessionChannel + .getWebTarget() + .path("digest/pub/data/query") + .queryParam("dataInfoId", + DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, DEFAULT_GROUP)) + .request(APPLICATION_JSON).get(new GenericType>>() { + }); + assertEquals(1, publisherMap.size()); + assertEquals(1, publisherMap.get("PUB").size()); + assertEquals(dataId, publisherMap.get("PUB").get(0).getDataId()); + assertEquals(value, bytes2Object(publisherMap.get("PUB").get(0).getDataList().get(0) + .getBytes())); + + Map> subscriberMap = sessionChannel + .getWebTarget() + .path("digest/sub/data/query") + .queryParam("dataInfoId", + DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, DEFAULT_GROUP)) + .request(APPLICATION_JSON).get(new GenericType>>() { + }); + assertEquals(1, subscriberMap.size()); + assertEquals(1, subscriberMap.get("SUB").size()); + assertEquals(dataId, subscriberMap.get("SUB").get(0).getDataId()); + + Map map = sessionChannel + .getWebTarget() + .path("digest/all/data/query") + .queryParam("dataInfoId", + DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, DEFAULT_GROUP)) + .request(APPLICATION_JSON).get(Map.class); + assertEquals(2, map.size()); + assertEquals(1, ((List) map.get("SUB")).size()); + assertEquals(1, ((List) map.get("PUB")).size()); + assertEquals(dataId, ((Map) ((List) map.get("SUB")).get(0)).get("dataId")); + assertEquals(dataId, ((Map) ((List) map.get("PUB")).get(0)).get("dataId")); + assertEquals(value, bytes2Object(publisherMap.get("PUB").get(0).getDataList().get(0) + .getBytes())); + } + + @Test + public void testetSessionDataByConnectId() throws Exception { + List connectIds = new ArrayList<>(); + connectIds.add(NetUtil.genHost(LOCAL_ADDRESS, getSourcePort(registryClient1))); + Map> publisherMap = sessionChannel + .getWebTarget() + .path("digest/pub/connect/query") + .request(APPLICATION_JSON) + .post(Entity.entity(connectIds, MediaType.APPLICATION_JSON), + new GenericType>>() { + }); + assertEquals(1, publisherMap.size()); + assertEquals(1, publisherMap.get("PUB").size()); + assertEquals(dataId, publisherMap.get("PUB").get(0).getDataId()); + assertEquals(value, bytes2Object(publisherMap.get("PUB").get(0).getDataList().get(0) + .getBytes())); + + Map> subscriberMap = sessionChannel + .getWebTarget() + .path("digest/sub/connect/query") + .request(APPLICATION_JSON) + .post(Entity.entity(connectIds, MediaType.APPLICATION_JSON), + new GenericType>>() { + }); + assertEquals(1, subscriberMap.size()); + assertEquals(1, subscriberMap.get("SUB").size()); + assertEquals(dataId, subscriberMap.get("SUB").get(0).getDataId()); + + Map map = sessionChannel.getWebTarget().path("digest/all/connect/query") + .request(APPLICATION_JSON) + .post(Entity.entity(connectIds, MediaType.APPLICATION_JSON), Map.class); + assertEquals(2, map.size()); + assertEquals(1, ((List) map.get("SUB")).size()); + assertEquals(1, ((List) map.get("PUB")).size()); + assertEquals(dataId, ((Map) ((List) map.get("SUB")).get(0)).get("dataId")); + assertEquals(dataId, ((Map) ((List) map.get("PUB")).get(0)).get("dataId")); + assertEquals(value, bytes2Object(publisherMap.get("PUB").get(0).getDataList().get(0) + .getBytes())); + } + + @Test + public void testGetSessionDataCount() { + String result = sessionChannel.getWebTarget().path("digest/data/count") + .request(APPLICATION_JSON).get(String.class); + assertEquals("Subscriber count: 1, Publisher count: 1, Watcher count: 0", result); + } + + @Test + public void testGetPushSwitch() { + Map result = sessionChannel.getWebTarget().path("digest/pushSwitch") + .request(APPLICATION_JSON).get(Map.class); + assertEquals(1, result.size()); + assertEquals("open", result.get("pushSwitch")); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionOpenResourceTest.java b/test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionOpenResourceTest.java new file mode 100644 index 000000000..550c1a842 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/resource/session/SessionOpenResourceTest.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.resource.session; + +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author xuanbei + * @since 2019/1/14 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class SessionOpenResourceTest extends BaseIntegrationTest { + @Test + public void testCheckAlive() { + String result = sessionChannel.getWebTarget().path("api/servers/alive").request() + .get(String.class); + assertEquals("OK", result); + } + + @Test + public void testGetSessionServerList() { + String result = sessionChannel.getWebTarget().path("api/servers/query") + .queryParam("zone", LOCAL_REGION).request().get(String.class); + assertEquals(LOCAL_ADDRESS + ":" + sessionServerPort, result); + } + + @Test + public void testGetSessionServerListJson() { + List result = sessionChannel.getWebTarget().path("api/servers/query.json") + .queryParam("zone", LOCAL_REGION).request(MediaType.APPLICATION_JSON) + .get(new GenericType>() { + }); + assertEquals(1, result.size()); + assertEquals(LOCAL_ADDRESS + ":" + sessionServerPort, result.get(0)); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/sync/DataSyncTest.java b/test/src/test/java/com/alipay/sofa/registry/test/sync/DataSyncTest.java new file mode 100644 index 000000000..90e55ff40 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/sync/DataSyncTest.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.sync; + +import com.alipay.remoting.Connection; +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.SubscriberRegistration; +import com.alipay.sofa.registry.common.model.CommonResponse; +import com.alipay.sofa.registry.common.model.dataserver.NotifyDataSyncRequest; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.core.model.ScopeEnum; +import com.alipay.sofa.registry.net.NetUtil; +import com.alipay.sofa.registry.remoting.ChannelHandler; +import com.alipay.sofa.registry.remoting.Server; +import com.alipay.sofa.registry.remoting.bolt.BoltChannel; +import com.alipay.sofa.registry.remoting.bolt.exchange.BoltExchange; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.server.data.remoting.dataserver.DataServerConnectionFactory; +import com.alipay.sofa.registry.server.data.remoting.dataserver.handler.DataSyncServerConnectionHandler; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/16 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class DataSyncTest extends BaseIntegrationTest { + private static final int TEST_SYNC_PORT = 9677; + private DataServerConnectionFactory dataServerConnectionFactory; + private Server dataSyncServer; + private String remoteIP; + + @Before + public void before() throws Exception { + super.before(); + BoltExchange boltExchange = (BoltExchange) dataApplicationContext.getBean("boltExchange"); + dataServerConnectionFactory = dataApplicationContext.getBean("dataServerConnectionFactory", + DataServerConnectionFactory.class); + DataNodeExchanger dataNodeExchanger = (DataNodeExchanger) dataApplicationContext + .getBean("dataNodeExchanger"); + + // open sync port and connect it + dataSyncServer = boltExchange.open(new URL(NetUtil.getLocalAddress().getHostAddress(), + TEST_SYNC_PORT), new ChannelHandler[] { new MockSyncDataHandler(), + dataApplicationContext.getBean(DataSyncServerConnectionHandler.class) }); + remoteIP = ((BoltChannel) dataNodeExchanger.connect(new URL(LOCAL_ADDRESS, TEST_SYNC_PORT))) + .getConnection().getLocalIP(); + Thread.sleep(500); + } + + @Test + public void doTest() throws Exception { + // post sync data request + Connection connection = dataServerConnectionFactory.getConnection(remoteIP); + NotifyDataSyncRequest request = new NotifyDataSyncRequest(DataInfo.toDataInfoId( + MockSyncDataHandler.dataId, DEFAULT_INSTANCE_ID, DEFAULT_GROUP), LOCAL_DATACENTER, + MockSyncDataHandler.version, DataSourceTypeEnum.SYNC.toString()); + CommonResponse commonResponse = (CommonResponse) dataSyncServer.sendSync( + dataSyncServer.getChannel(connection.getRemoteAddress()), request, 1000); + assertTrue(commonResponse.isSuccess()); + + // register Subscriber + SubscriberRegistration subReg = new SubscriberRegistration(MockSyncDataHandler.dataId, + new MySubscriberDataObserver()); + subReg.setScopeEnum(ScopeEnum.global); + registryClient1.register(subReg); + + // assert result + Thread.sleep(1000L); + assertEquals(MockSyncDataHandler.dataId, this.dataId); + assertEquals(LOCAL_REGION, userData.getLocalZone()); + assertEquals(1, userData.getZoneData().size()); + assertEquals(1, userData.getZoneData().values().size()); + assertEquals(true, userData.getZoneData().containsKey(LOCAL_REGION)); + assertEquals(1, userData.getZoneData().get(LOCAL_REGION).size()); + assertEquals(MockSyncDataHandler.value, userData.getZoneData().get(LOCAL_REGION).get(0)); + + registryClient1.unregister(MockSyncDataHandler.dataId, DEFAULT_GROUP, + RegistryType.SUBSCRIBER); + registryClient1.unregister(MockSyncDataHandler.dataId, DEFAULT_GROUP, + RegistryType.PUBLISHER); + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/sync/MockSyncDataHandler.java b/test/src/test/java/com/alipay/sofa/registry/test/sync/MockSyncDataHandler.java new file mode 100644 index 000000000..502fc2e30 --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/sync/MockSyncDataHandler.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.sync; + +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.Node; +import com.alipay.sofa.registry.common.model.ServerDataBox; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.common.model.store.BaseInfo; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.Publisher; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.Channel; +import com.alipay.sofa.registry.server.data.remoting.handler.AbstractServerHandler; +import com.alipay.sofa.registry.util.ParaCheckUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static com.alipay.sofa.registry.test.BaseIntegrationTest.LOCAL_ADDRESS; +import static com.alipay.sofa.registry.test.BaseIntegrationTest.LOCAL_DATACENTER; +import static com.alipay.sofa.registry.test.BaseIntegrationTest.LOCAL_REGION; + +/** + * mock SyncDataHandler, it will return fixed Datum. + * + * @author xuanbei + * @since 2019/1/16 + */ +public class MockSyncDataHandler extends AbstractServerHandler { + public static String dataId = "test-dataId-" + System.currentTimeMillis(); + public static String value = "MockSyncDataHandler"; + public static long version = System.currentTimeMillis(); + + @Override + public void checkParam(SyncDataRequest request) throws RuntimeException { + ParaCheckUtil.checkNotBlank(request.getDataInfoId(), "request.dataInfoId"); + ParaCheckUtil.checkNotBlank(request.getDataCenter(), "request.dataCenter"); + ParaCheckUtil.checkNotBlank(String.valueOf(request.getVersion()), "request.currentVersion"); + } + + @Override + public Object doHandle(Channel channel, SyncDataRequest request) { + String dataInfoId = DataInfo.toDataInfoId(MockSyncDataHandler.dataId, DEFAULT_INSTANCE_ID, + DEFAULT_GROUP); + Datum datum = new Datum(); + datum.setDataInfoId(dataInfoId); + datum.setDataId(dataId); + datum.setDataCenter(LOCAL_DATACENTER); + datum.setGroup(DEFAULT_GROUP); + datum.setInstanceId(DEFAULT_INSTANCE_ID); + datum.setVersion(version); + String registerId = UUID.randomUUID().toString(); + Publisher publisher = createPublisher(); + publisher.setRegisterId(registerId); + Map pubMap = new ConcurrentHashMap<>(); + pubMap.put(registerId, publisher); + datum.setPubMap(pubMap); + + SyncData syncData = new SyncData(dataInfoId, LOCAL_DATACENTER, true, new ArrayList<>( + Arrays.asList(datum))); + return new GenericResponse().fillSucceed(syncData); + } + + private Publisher createPublisher() { + Publisher publisher = new Publisher(); + publisher.setDataList(new ArrayList<>(Arrays.asList(new ServerDataBox(ServerDataBox + .getBytes(value))))); + publisher.setCell(LOCAL_REGION); + publisher.setAppName("testApp"); + publisher.setClientRegisterTimestamp(System.currentTimeMillis() - 100000L); + publisher.setRegisterTimestamp(System.currentTimeMillis() - 80000L); + publisher.setClientVersion(BaseInfo.ClientVersion.StoreData); + publisher.setDataId(dataId); + publisher.setGroup(DEFAULT_GROUP); + publisher.setInstanceId(DEFAULT_INSTANCE_ID); + publisher.setVersion(version); + publisher.setSourceAddress(new URL(LOCAL_ADDRESS, 65343)); + publisher.setDataInfoId(DataInfo.toDataInfoId(MockSyncDataHandler.dataId, + DEFAULT_INSTANCE_ID, DEFAULT_GROUP)); + return publisher; + } + + @Override + public GenericResponse buildFailedResponse(String msg) { + return new GenericResponse().fillFailed(msg); + } + + @Override + public HandlerType getType() { + return HandlerType.PROCESSER; + } + + @Override + public Class interest() { + return SyncDataRequest.class; + } + + @Override + protected Node.NodeType getConnectNodeType() { + return Node.NodeType.DATA; + } +} diff --git a/test/src/test/java/com/alipay/sofa/registry/test/sync/SyncDataHandlerTest.java b/test/src/test/java/com/alipay/sofa/registry/test/sync/SyncDataHandlerTest.java new file mode 100644 index 000000000..42fb5f12a --- /dev/null +++ b/test/src/test/java/com/alipay/sofa/registry/test/sync/SyncDataHandlerTest.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.registry.test.sync; + +import com.alipay.sofa.registry.client.api.model.RegistryType; +import com.alipay.sofa.registry.client.api.registration.PublisherRegistration; +import com.alipay.sofa.registry.common.model.GenericResponse; +import com.alipay.sofa.registry.common.model.dataserver.Datum; +import com.alipay.sofa.registry.common.model.dataserver.SyncData; +import com.alipay.sofa.registry.common.model.dataserver.SyncDataRequest; +import com.alipay.sofa.registry.common.model.store.DataInfo; +import com.alipay.sofa.registry.common.model.store.URL; +import com.alipay.sofa.registry.remoting.exchange.message.Request; +import com.alipay.sofa.registry.server.data.change.DataSourceTypeEnum; +import com.alipay.sofa.registry.server.data.remoting.DataNodeExchanger; +import com.alipay.sofa.registry.test.BaseIntegrationTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; + +import static com.alipay.sofa.registry.client.constants.ValueConstants.DEFAULT_GROUP; +import static com.alipay.sofa.registry.common.model.constants.ValueConstants.DEFAULT_INSTANCE_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author xuanbei + * @since 2019/1/16 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class SyncDataHandlerTest extends BaseIntegrationTest { + @Test + public void doTest() throws Exception { + // publish data + String dataId = "test-dataId-" + System.currentTimeMillis(); + String value = "test publish"; + PublisherRegistration registration = new PublisherRegistration(dataId); + registryClient1.register(registration, value); + Thread.sleep(500L); + + // request syncData + DataNodeExchanger dataNodeExchanger = dataApplicationContext.getBean("dataNodeExchanger", + DataNodeExchanger.class); + GenericResponse genericResponse = (GenericResponse) dataNodeExchanger.request( + new Request() { + @Override + public Object getRequestBody() { + return new SyncDataRequest(DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, + DEFAULT_GROUP), LOCAL_DATACENTER, System.currentTimeMillis() - 100000, + DataSourceTypeEnum.BACKUP.toString()); + } + + @Override + public URL getRequestUrl() { + return new URL(LOCAL_ADDRESS, syncDataPort); + } + }).getResult(); + + // assert result + assertTrue(genericResponse.isSuccess()); + SyncData syncData = (SyncData) genericResponse.getData(); + assertEquals(DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, DEFAULT_GROUP), + syncData.getDataInfoId()); + assertEquals(LOCAL_DATACENTER, syncData.getDataCenter()); + List datums = (List) syncData.getDatums(); + Datum datum = datums.get(0); + assertEquals(DataInfo.toDataInfoId(dataId, DEFAULT_INSTANCE_ID, DEFAULT_GROUP), + datum.getDataInfoId()); + assertEquals(LOCAL_DATACENTER, datum.getDataCenter()); + assertEquals(dataId, datum.getDataId()); + assertEquals(1, datum.getPubMap().size()); + assertEquals(LOCAL_REGION, datum.getPubMap().values().iterator().next().getCell()); + assertEquals(1, datum.getPubMap().values().iterator().next().getDataList().size()); + assertEquals(value, bytes2Object(datum.getPubMap().values().iterator().next().getDataList() + .get(0).getBytes())); + + // unregister publisher + registryClient1.unregister(dataId, DEFAULT_GROUP, RegistryType.PUBLISHER); + } +} diff --git a/tools/change_version.sh b/tools/change_version.sh new file mode 100644 index 000000000..e712e18de --- /dev/null +++ b/tools/change_version.sh @@ -0,0 +1,37 @@ +#!/bin/bash +shellDir=$(cd "$(dirname "$0")"; pwd) + +shopt -s expand_aliases +if [ ! -n "$1" ] ;then + echo "Please enter a version" + exit 1 +else + echo "The version is $1 !" +fi + +if [ `uname` == "Darwin" ] ;then + echo "This is OS X" + alias sed='sed -i ""' +else + echo "This is Linux" + alias sed='sed -i' +fi + +cd $shellDir/.. +echo "Change version in registry-parent ===>" +sed "// s/[^\$].*<\/version>/$1<\/version>/" ./pom.xml + +echo "Change version in registry-client-all ===>" +sed "/[^\$].*<\/version>/$1<\/version>/" ./client/all/pom.xml + +echo "Change version in subproject pom ===>" +for filename in `find . -name "pom.xml" -maxdepth 4`;do + if [ $filename == "./client/all/pom.xml" ]; then + continue + fi + echo "Deal with $filename" + sed "//,/<\/parent>/ s/[^\$].*<\/version>/$1<\/version>/" $filename +done + +#TODO +#echo "Change version in server shell ===>" \ No newline at end of file diff --git a/tools/check_format.sh b/tools/check_format.sh new file mode 100644 index 000000000..cd548f7aa --- /dev/null +++ b/tools/check_format.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +BASEDIR=$(dirname $0) + +cd ${BASEDIR} + +# make sure git has no un commit files +if [ -n "$(git status --untracked-files=no --porcelain)" ]; then + echo "Please commit your change before run this shell, un commit files:" + git status --untracked-files=no --porcelain + exit 1 +fi \ No newline at end of file diff --git a/tools/codestyle/HEADER b/tools/codestyle/HEADER new file mode 100644 index 000000000..0ed96c451 --- /dev/null +++ b/tools/codestyle/HEADER @@ -0,0 +1,14 @@ +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You under the Apache License, Version 2.0 +(the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/tools/codestyle/formatter.xml b/tools/codestyle/formatter.xml new file mode 100644 index 000000000..7c954cd39 --- /dev/null +++ b/tools/codestyle/formatter.xml @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file