package com.nosql.db.cluster;
import com.nosql.common.protocol.DBResponse;
import com.nosql.db.core.storage.LSMStore;
import com.nosql.db.core.wal.WALEntry;
import com.nosql.db.network.DBCommand;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
public class ClusterManager {
private static final int ELECTION_TIMEOUT = 3000;
private static final int HEARTBEAT_INTERVAL = 500;
private Node leader;
private final String nodeId;
private final List<Node> nodes = new CopyOnWriteArrayList<>();
private final LSMStore storage;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
public ClusterManager(String nodeId, LSMStore storage) {
this.nodeId = nodeId;
this.storage = storage;
}
// 启动集群服务
public void startCluster() {
scheduler.scheduleAtFixedRate(this::checkLeaderStatus, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.MILLISECONDS);
scheduler.scheduleAtFixedRate(this::cleanDeadNodes, 5, 5, TimeUnit.SECONDS);
}
// 处理写请求
public void handleWrite(DBCommand command) throws IOException {
// 添加幂等性检查
if (command instanceof DBCommand.putCommand) {
String docId = ((DBCommand.putCommand)command).getData().get("id").toString();
if (storage.get(docId) != null) {
return; // 已存在则不处理
}
} else if (command instanceof DBCommand.DeleteCommand) {
DBCommand.DeleteCommand delCmd = (DBCommand.DeleteCommand) command;
if (storage.get(delCmd.getId()) == null) {
return; // 文档不存在时跳过
}
}
// 新增:所有节点都要处理本地存储
processLocally(command);
if (isLeader()) {
storage.getWal().writeEntry(convertToWALEntry(command));
replicateToNodes(command);
} else {
forwardToLeader(command);
}
}
// 选举核心逻辑
private synchronized void electLeader() {
Node newLeader = nodes.stream()
.filter(Node::isAlive)
.min(Comparator.comparing(Node::getId))
.orElse(null);
if (newLeader != null && newLeader.getId().equals(nodeId)) {
becomeLeader();
} else if (newLeader != null) {
this.leader = newLeader;
}
}
// 成为Leader后的初始化
private void becomeLeader() {
leader = new Node(nodeId, "localhost", 8080, Node.Role.LEADER);
System.out.println("["+nodeId+"] 开始担任Leader,当前节点列表: "
+ nodes.stream().map(Node::getId).collect(Collectors.joining(",")));
nodes.removeIf(n -> n.getId().equals(nodeId));
nodes.add(leader);
}
// 数据复制到其他节点
private void replicateToNodes(DBCommand command) {
int successCount = 0;
for (Node node : nodes) {
if (!node.getId().equals(nodeId) && sendReplication(node, command)) {
successCount++;
}
}
if (successCount >= nodes.size() / 2) {
System.out.println("["+nodeId+"] 数据复制结果: 成功" + successCount + "/总" + nodes.size());
}
}
// 发送复制请求(简化实现)
private boolean sendReplication(Node node, DBCommand command) {
try (Socket socket = new Socket(node.getHost(), node.getPort())) {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
out.writeObject(command);
return true;
} catch (IOException e) {
System.err.println("复制到节点 " + node.getId() + " 失败");
return false;
}
}
// 其他辅助方法
private boolean isLeader() {
return leader != null && leader.getId().equals(nodeId);
}
private void checkLeaderStatus() {
if (leader == null || !leader.isAlive()) {
electLeader();
}
}
private void cleanDeadNodes() {
nodes.removeIf(node -> !node.isAlive());
}
// 转换命令到WAL日志条目
private WALEntry convertToWALEntry(DBCommand command) {
if (command instanceof DBCommand.putCommand) {
DBCommand.putCommand putCmd = (DBCommand.putCommand) command;
// 直接从命令数据中获取服务端生成的ID
String docId = (String) putCmd.getData().get("id");
return new WALEntry(
WALEntry.Operation.PUT,
docId,
putCmd.getData()
);
} else if (command instanceof DBCommand.DeleteCommand) {
DBCommand.DeleteCommand delCmd = (DBCommand.DeleteCommand) command;
return new WALEntry(WALEntry.Operation.DELETE, delCmd.getId());
}
throw new IllegalArgumentException("不支持的命令类型: " + command.getType());
}
// 转发请求到Leader节点
private void forwardToLeader(DBCommand command) throws IOException {
if (leader == null) {
throw new IOException("当前无可用Leader");
}
try (Socket socket = new Socket(leader.getHost(), leader.getPort())) {
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
out.writeObject(command);
Object response = in.readObject();
if (response instanceof Exception) {
throw new IOException("Leader处理失败", (Exception) response);
}
} catch (ClassNotFoundException e) {
throw new IOException("响应解析失败", e);
}
}
// 新增集群加入方法
// 加入集群的简化实现
public void joinCluster(List<Node> seedNodes) {
// 基础校验
if (seedNodes == null || seedNodes.isEmpty()) {
System.err.println("无效的种子节点列表");
return;
}
// 添加存活节点到集群
nodes.addAll(seedNodes.stream()
.filter(Node::isAlive)
.collect(Collectors.toList()));
// 如果当前没有Leader,立即触发选举
if (leader == null) {
electLeader();
}
System.out.println("["+nodeId+"] 成功加入集群,当前节点数: " + nodes.size());
}
// 新增本地处理方法(添加在ClusterManager类中)
private void processLocally(DBCommand command) throws IOException {
if (command instanceof DBCommand.putCommand) {
DBCommand.putCommand putCmd = (DBCommand.putCommand) command;
storage.put(putCmd.getCollection(), putCmd.getData());
} else if (command instanceof DBCommand.DeleteCommand) {
DBCommand.DeleteCommand delCmd = (DBCommand.DeleteCommand) command;
storage.delete(delCmd.getCollection(), delCmd.getId());
} else if (command instanceof DBCommand.CreateCollectionCommand) {
DBCommand.CreateCollectionCommand createCmd = (DBCommand.CreateCollectionCommand) command;
storage.createCollection(createCmd.getCollection());
}
}
}