|
21 | 21 | import org.apache.fluss.cluster.Endpoint; |
22 | 22 | import org.apache.fluss.cluster.ServerNode; |
23 | 23 | import org.apache.fluss.cluster.ServerType; |
| 24 | +import org.apache.fluss.cluster.rebalance.ServerTag; |
24 | 25 | import org.apache.fluss.config.ConfigOptions; |
25 | 26 | import org.apache.fluss.config.Configuration; |
26 | 27 | import org.apache.fluss.exception.FencedLeaderEpochException; |
27 | 28 | import org.apache.fluss.exception.FlussRuntimeException; |
28 | 29 | import org.apache.fluss.exception.IneligibleReplicaException; |
29 | 30 | import org.apache.fluss.exception.InvalidCoordinatorException; |
30 | 31 | import org.apache.fluss.exception.InvalidUpdateVersionException; |
| 32 | +import org.apache.fluss.exception.ServerNotExistException; |
| 33 | +import org.apache.fluss.exception.ServerTagAlreadyExistException; |
| 34 | +import org.apache.fluss.exception.ServerTagNotExistException; |
31 | 35 | import org.apache.fluss.exception.TableNotExistException; |
32 | 36 | import org.apache.fluss.exception.TabletServerNotAvailableException; |
| 37 | +import org.apache.fluss.exception.UnknownServerException; |
33 | 38 | import org.apache.fluss.exception.UnknownTableOrBucketException; |
34 | 39 | import org.apache.fluss.metadata.PhysicalTablePath; |
35 | 40 | import org.apache.fluss.metadata.SchemaInfo; |
|
38 | 43 | import org.apache.fluss.metadata.TableInfo; |
39 | 44 | import org.apache.fluss.metadata.TablePartition; |
40 | 45 | import org.apache.fluss.metadata.TablePath; |
| 46 | +import org.apache.fluss.rpc.messages.AddServerTagResponse; |
41 | 47 | import org.apache.fluss.rpc.messages.AdjustIsrResponse; |
42 | 48 | import org.apache.fluss.rpc.messages.CommitKvSnapshotResponse; |
43 | 49 | import org.apache.fluss.rpc.messages.CommitLakeTableSnapshotResponse; |
44 | 50 | import org.apache.fluss.rpc.messages.CommitRemoteLogManifestResponse; |
45 | 51 | import org.apache.fluss.rpc.messages.ControlledShutdownResponse; |
46 | 52 | import org.apache.fluss.rpc.messages.PbCommitLakeTableSnapshotRespForTable; |
| 53 | +import org.apache.fluss.rpc.messages.RemoveServerTagResponse; |
47 | 54 | import org.apache.fluss.rpc.protocol.ApiError; |
48 | 55 | import org.apache.fluss.server.coordinator.event.AccessContextEvent; |
| 56 | +import org.apache.fluss.server.coordinator.event.AddServerTagEvent; |
49 | 57 | import org.apache.fluss.server.coordinator.event.AdjustIsrReceivedEvent; |
50 | 58 | import org.apache.fluss.server.coordinator.event.CommitKvSnapshotEvent; |
51 | 59 | import org.apache.fluss.server.coordinator.event.CommitLakeTableSnapshotEvent; |
|
65 | 73 | import org.apache.fluss.server.coordinator.event.NotifyKvSnapshotOffsetEvent; |
66 | 74 | import org.apache.fluss.server.coordinator.event.NotifyLakeTableOffsetEvent; |
67 | 75 | import org.apache.fluss.server.coordinator.event.NotifyLeaderAndIsrResponseReceivedEvent; |
| 76 | +import org.apache.fluss.server.coordinator.event.RemoveServerTagEvent; |
68 | 77 | import org.apache.fluss.server.coordinator.event.SchemaChangeEvent; |
69 | 78 | import org.apache.fluss.server.coordinator.event.watcher.TableChangeWatcher; |
70 | 79 | import org.apache.fluss.server.coordinator.event.watcher.TabletServerChangeWatcher; |
|
86 | 95 | import org.apache.fluss.server.zk.data.LeaderAndIsr; |
87 | 96 | import org.apache.fluss.server.zk.data.PartitionAssignment; |
88 | 97 | import org.apache.fluss.server.zk.data.RemoteLogManifestHandle; |
| 98 | +import org.apache.fluss.server.zk.data.ServerTags; |
89 | 99 | import org.apache.fluss.server.zk.data.TableAssignment; |
90 | 100 | import org.apache.fluss.server.zk.data.TabletServerRegistration; |
91 | 101 | import org.apache.fluss.server.zk.data.ZkData.PartitionIdsZNode; |
@@ -326,6 +336,11 @@ private void initCoordinatorContext() throws Exception { |
326 | 336 | // init tablet server channels |
327 | 337 | coordinatorChannelManager.startup(internalServerNodes); |
328 | 338 |
|
| 339 | + // load server tags. |
| 340 | + zooKeeperClient |
| 341 | + .getServerTags() |
| 342 | + .ifPresent(tags -> coordinatorContext.initSeverTags(tags.getServerTags())); |
| 343 | + |
329 | 344 | // load all tables |
330 | 345 | long start4loadTables = System.currentTimeMillis(); |
331 | 346 | List<TableInfo> autoPartitionTables = new ArrayList<>(); |
@@ -553,6 +568,16 @@ public void process(CoordinatorEvent event) { |
553 | 568 | completeFromCallable( |
554 | 569 | controlledShutdownEvent.getRespCallback(), |
555 | 570 | () -> tryProcessControlledShutdown(controlledShutdownEvent)); |
| 571 | + } else if (event instanceof AddServerTagEvent) { |
| 572 | + AddServerTagEvent addServerTagEvent = (AddServerTagEvent) event; |
| 573 | + completeFromCallable( |
| 574 | + addServerTagEvent.getRespCallback(), |
| 575 | + () -> processAddServerTag(addServerTagEvent)); |
| 576 | + } else if (event instanceof RemoveServerTagEvent) { |
| 577 | + RemoveServerTagEvent removeServerTagEvent = (RemoveServerTagEvent) event; |
| 578 | + completeFromCallable( |
| 579 | + removeServerTagEvent.getRespCallback(), |
| 580 | + () -> processRemoveServerTag(removeServerTagEvent)); |
556 | 581 | } else if (event instanceof AccessContextEvent) { |
557 | 582 | AccessContextEvent<?> accessContextEvent = (AccessContextEvent<?>) event; |
558 | 583 | processAccessContext(accessContextEvent); |
@@ -973,6 +998,90 @@ private void processDeadTabletServer(DeadTabletServerEvent deadTabletServerEvent |
973 | 998 | updateTabletServerMetadataCache(serverInfos, null, null, bucketsWithOfflineLeader); |
974 | 999 | } |
975 | 1000 |
|
| 1001 | + private AddServerTagResponse processAddServerTag(AddServerTagEvent event) { |
| 1002 | + AddServerTagResponse addServerTagResponse = new AddServerTagResponse(); |
| 1003 | + List<Integer> serverIds = event.getServerIds(); |
| 1004 | + ServerTag serverTag = event.getServerTag(); |
| 1005 | + |
| 1006 | + // Verify that dose serverTag exist for input serverIds. If any of them exists, throw |
| 1007 | + // an error and none of them will be written to coordinatorContext and zk. |
| 1008 | + Map<Integer, ServerInfo> liveTabletServers = coordinatorContext.getLiveTabletServers(); |
| 1009 | + for (Integer serverId : serverIds) { |
| 1010 | + if (!liveTabletServers.containsKey(serverId)) { |
| 1011 | + throw new ServerNotExistException( |
| 1012 | + String.format( |
| 1013 | + "Server %s not exists when trying to add server tag.", serverId)); |
| 1014 | + } |
| 1015 | + |
| 1016 | + if (coordinatorContext.getServerTag(serverId).isPresent()) { |
| 1017 | + throw new ServerTagAlreadyExistException( |
| 1018 | + String.format( |
| 1019 | + "Server tag %s already exists for server %s.", |
| 1020 | + serverTag, serverId)); |
| 1021 | + } |
| 1022 | + } |
| 1023 | + |
| 1024 | + // First register to zk, and then update coordinatorContext. |
| 1025 | + Map<Integer, ServerTag> serverTags = coordinatorContext.getServerTags(); |
| 1026 | + for (Integer serverId : serverIds) { |
| 1027 | + serverTags.put(serverId, serverTag); |
| 1028 | + } |
| 1029 | + |
| 1030 | + try { |
| 1031 | + zooKeeperClient.registerServerTags(new ServerTags(serverTags)); |
| 1032 | + } catch (Exception e) { |
| 1033 | + LOG.error("Error when register server tags to zookeeper.", e); |
| 1034 | + throw new UnknownServerException("Error when register server tags to zookeeper.", e); |
| 1035 | + } |
| 1036 | + |
| 1037 | + // Then update coordinatorContext. |
| 1038 | + serverIds.forEach(serverId -> coordinatorContext.putServerTag(serverId, serverTag)); |
| 1039 | + |
| 1040 | + return addServerTagResponse; |
| 1041 | + } |
| 1042 | + |
| 1043 | + private RemoveServerTagResponse processRemoveServerTag(RemoveServerTagEvent event) { |
| 1044 | + RemoveServerTagResponse removeServerTagResponse = new RemoveServerTagResponse(); |
| 1045 | + List<Integer> serverIds = event.getServerIds(); |
| 1046 | + ServerTag serverTag = event.getServerTag(); |
| 1047 | + |
| 1048 | + // Verify that dose serverTag not exist for input serverIds. If any of them not exists, |
| 1049 | + // throw an error and none of them will be removed form coordinatorContext and zk. |
| 1050 | + Map<Integer, ServerInfo> liveTabletServers = coordinatorContext.getLiveTabletServers(); |
| 1051 | + for (Integer serverId : serverIds) { |
| 1052 | + if (!liveTabletServers.containsKey(serverId)) { |
| 1053 | + throw new ServerNotExistException( |
| 1054 | + String.format( |
| 1055 | + "Server %s not exists when trying to removing server tag.", |
| 1056 | + serverId)); |
| 1057 | + } |
| 1058 | + |
| 1059 | + if (!coordinatorContext.getServerTag(serverId).isPresent()) { |
| 1060 | + throw new ServerTagNotExistException( |
| 1061 | + String.format( |
| 1062 | + "Server tag %s not exists for server %s.", serverTag, serverId)); |
| 1063 | + } |
| 1064 | + } |
| 1065 | + |
| 1066 | + // First register to zk, and then update coordinatorContext. |
| 1067 | + Map<Integer, ServerTag> serverTags = coordinatorContext.getServerTags(); |
| 1068 | + for (Integer serverId : serverIds) { |
| 1069 | + serverTags.remove(serverId); |
| 1070 | + } |
| 1071 | + |
| 1072 | + try { |
| 1073 | + zooKeeperClient.registerServerTags(new ServerTags(serverTags)); |
| 1074 | + } catch (Exception e) { |
| 1075 | + LOG.error("Error when register server tags to zookeeper.", e); |
| 1076 | + throw new UnknownServerException("Error when register server tags to zookeeper.", e); |
| 1077 | + } |
| 1078 | + |
| 1079 | + // Then update coordinatorContext. |
| 1080 | + serverIds.forEach(coordinatorContext::removeServerTag); |
| 1081 | + |
| 1082 | + return removeServerTagResponse; |
| 1083 | + } |
| 1084 | + |
976 | 1085 | private List<AdjustIsrResultForBucket> tryProcessAdjustIsr( |
977 | 1086 | Map<TableBucket, LeaderAndIsr> leaderAndIsrList) { |
978 | 1087 | // TODO verify leader epoch. |
|
0 commit comments