All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.staros.manager.StarManager Maven / Gradle / Ivy

// Copyright 2021-present StarRocks, Inc. All rights reserved.
//
// 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
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


package com.staros.manager;

import com.staros.exception.ExceptionCode;
import com.staros.exception.StarException;
import com.staros.filestore.FilePath;
import com.staros.filestore.FileStore;
import com.staros.filestore.FileStoreMgr;
import com.staros.filestore.FileStoreMgrs;
import com.staros.heartbeat.HeartbeatManager;
import com.staros.journal.DummyJournalSystem;
import com.staros.journal.Journal;
import com.staros.journal.JournalReplayer;
import com.staros.journal.JournalSystem;
import com.staros.proto.CreateMetaGroupInfo;
import com.staros.proto.CreateShardGroupInfo;
import com.staros.proto.CreateShardInfo;
import com.staros.proto.CreateShardJournalInfo;
import com.staros.proto.DeleteShardGroupInfo;
import com.staros.proto.FilePathInfo;
import com.staros.proto.FileStoreInfo;
import com.staros.proto.FileStoreType;
import com.staros.proto.MetaGroupInfo;
import com.staros.proto.MetaGroupJournalInfo;
import com.staros.proto.ReplicaInfo;
import com.staros.proto.ServiceInfo;
import com.staros.proto.ShardGroupInfo;
import com.staros.proto.ShardInfo;
import com.staros.proto.ShardInfoList;
import com.staros.proto.StarManagerFileMetaFooter;
import com.staros.proto.StarManagerFileMetaHeader;
import com.staros.proto.StarManagerFileMetaHolder;
import com.staros.proto.UpdateMetaGroupInfo;
import com.staros.proto.WorkerInfo;
import com.staros.schedule.ShardSchedulerV2;
import com.staros.service.Service;
import com.staros.service.ServiceManager;
import com.staros.service.ServiceTemplate;
import com.staros.shard.Shard;
import com.staros.shard.ShardChecker;
import com.staros.shard.ShardGroup;
import com.staros.shard.ShardManager;
import com.staros.util.Config;
import com.staros.util.IdGenerator;
import com.staros.util.LockCloseable;
import com.staros.util.LogUtils;
import com.staros.util.Text;
import com.staros.worker.Worker;
import com.staros.worker.WorkerManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

public class StarManager {
    public static final String FILE_META_RAW_HEADER = "STARMGR1";

    private static final Logger LOG = LogManager.getLogger(StarManager.class);

    private AtomicBoolean isLeader;

    private ServiceManager serviceManager;
    private WorkerManager workerManager;
    private FileStoreMgrs fsMgrs;
    private ShardSchedulerV2 shardScheduler;
    private ShardChecker shardChecker;
    private HeartbeatManager heartbeatManager;
    private JournalReplayer journalReplayer;
    private JournalSystem journalSystem;
    private IdGenerator idGenerator;

    // FOR TEST
    public StarManager() {
        this(new DummyJournalSystem());
    }

    public StarManager(JournalSystem journalSystem) {
        this.journalSystem = journalSystem;
        fsMgrs = new FileStoreMgrs();
        idGenerator = new IdGenerator(journalSystem);
        isLeader = new AtomicBoolean(false);
        serviceManager = new ServiceManager(this.journalSystem, idGenerator);
        workerManager = new WorkerManager(this.journalSystem, idGenerator);
        shardScheduler = new ShardSchedulerV2(serviceManager, workerManager);
        shardChecker = new ShardChecker(serviceManager, workerManager, shardScheduler);
        heartbeatManager = new HeartbeatManager(workerManager);
        journalReplayer = new JournalReplayer(this);
        serviceManager.setShardScheduler(shardScheduler);
    }

    // pre check, mostly used to check if we can accept non-read request
    private void checkLeader() throws StarException {
        if (!isLeader.get()) {
            throw new StarException(ExceptionCode.NOT_LEADER,
                    "request rejected, current star manager is not leader.");
        }
    }

    public void becomeLeader() {
        journalSystem.onBecomeLeader();

        isLeader.set(true);

        startBackgroundThreads();

        LOG.info("star manager background threads start, now is leader.");
    }

    public void becomeFollower() {
        journalSystem.onBecomeFollower();

        isLeader.set(false);

        stopBackgroundThreads();

        LOG.info("star manager background threads stop, now is follower.");
    }

    public void startBackgroundThreads() {
        shardScheduler.start();
        shardChecker.start();
        heartbeatManager.start();
    }

    public void stopBackgroundThreads() {
        heartbeatManager.stop();
        shardChecker.stop();
        shardScheduler.stop();
    }

    public void registerService(String serviceTemplateName, List serviceComponents) throws StarException {
        checkLeader();

        serviceManager.registerService(serviceTemplateName, serviceComponents);
    }

    public void deregisterService(String serviceTemplateName) throws StarException {
        checkLeader();

        serviceManager.deregisterService(serviceTemplateName);
    }

    public String bootstrapService(String serviceTemplateName, String serviceName) throws StarException {
        checkLeader();

        String serviceId = serviceManager.bootstrapService(serviceTemplateName, serviceName);

        workerManager.createDefaultServiceWorkerGroup(serviceId);

        return serviceId;
    }

    public void shutdownService(String serviceId) throws StarException {
        checkLeader();

        serviceManager.shutdownService(serviceId);
    }

    public ServiceInfo getServiceInfoById(String serviceId) throws StarException {
        return serviceManager.getServiceInfoById(serviceId);
    }

    public ServiceInfo getServiceInfoByName(String serviceName) throws StarException {
        return serviceManager.getServiceInfoByName(serviceName);
    }

    public long addWorker(String serviceId, long groupId, String ipPort) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            long workerId = workerManager.addWorker(serviceId, groupId, ipPort);

            return workerId;
        }
    }

    public void removeWorker(String serviceId, long groupId, long workerId) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            workerManager.removeWorker(serviceId, groupId, workerId);
        }
    }

    public WorkerInfo getWorkerInfo(String serviceId, long workerId) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            WorkerInfo workerInfo = workerManager.getWorkerInfo(workerId);
            if (!workerInfo.getServiceId().equals(serviceId)) {
                throw new StarException(ExceptionCode.INVALID_ARGUMENT,
                        String.format("worker %d not belong to service %s.",
                        workerId, serviceId));
            }

            return workerInfo;
        }
    }

    public WorkerInfo getWorkerInfo(String serviceId, String ipPort) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            WorkerInfo workerInfo = workerManager.getWorkerInfo(ipPort);
            if (!workerInfo.getServiceId().equals(serviceId)) {
                throw new StarException(ExceptionCode.INVALID_ARGUMENT,
                        String.format("worker %s not belong to service %s.",
                        ipPort, serviceId));
            }

            return workerInfo;
        }
    }

    public List createShard(String serviceId,
            List createShardInfos) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;

            return shardManager.createShard(createShardInfos, fsMgrs);
        }
    }

    public void deleteShard(String serviceId, List shardIds) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.deleteShard(shardIds);

            // just let shard scheduler do remove shard, do nothing here
        }
    }

    private List gatherWorkerInfoForShard(List shardInfos) throws StarException {
        List shardInfosFinal = new ArrayList<>(shardInfos.size());
        for (ShardInfo shardInfo : shardInfos) {
            ShardInfo.Builder shardInfoBuilder = ShardInfo.newBuilder().mergeFrom(shardInfo);
            shardInfoBuilder.clearReplicaInfo();
            for (ReplicaInfo replicaInfo : shardInfo.getReplicaInfoList()) {
                try {
                    WorkerInfo workerInfo = workerManager.getWorkerInfo(
                            replicaInfo.getWorkerInfo().getWorkerId());
                    ReplicaInfo replicaInfoFinal = ReplicaInfo.newBuilder()
                            .mergeFrom(replicaInfo)
                            .setWorkerInfo(workerInfo)
                            .build();
                    shardInfoBuilder.addReplicaInfo(replicaInfoFinal);
                } catch (StarException e) {
                    if (e.getExceptionCode() == ExceptionCode.NOT_EXIST) {
                        // worker might already removed, but shard has stale replica info
                    } else {
                        throw e;
                    }
                }
            }
            shardInfosFinal.add(shardInfoBuilder.build());
        }
        return shardInfosFinal;
    }

    public List getShardInfo(String serviceId, List shardIds) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            List shardInfos = gatherWorkerInfoForShard(shardManager.getShardInfo(shardIds));
            return shardInfos;
        }
    }

    public List listShardInfo(String serviceId, List groupIds) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            List> shardInfos = shardManager.listShardInfo(groupIds);

            List shardInfoLists = new ArrayList<>(shardInfos.size());
            for (List infos : shardInfos) {
                ShardInfoList shardInfoList =
                        ShardInfoList.newBuilder().addAllShardInfos(gatherWorkerInfoForShard(infos)).build();
                shardInfoLists.add(shardInfoList);
            }
            return shardInfoLists;
        }
    }

    public List createShardGroup(String serviceId,
            List createShardGroupInfos) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            return shardManager.createShardGroup(createShardGroupInfos);
        }
    }

    public void deleteShardGroup(String serviceId, List groupIds, boolean deleteShards) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.deleteShardGroup(groupIds, deleteShards);
        }
    }

    public List listShardGroupInfo(String serviceId, boolean includeAnonymousGroup) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            return shardManager.listShardGroupInfo(includeAnonymousGroup);
        }
    }

    public MetaGroupInfo createMetaGroup(String serviceId, CreateMetaGroupInfo createMetaGroupInfo) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            return shardManager.createMetaGroup(createMetaGroupInfo);
        }
    }

    public void deleteMetaGroup(String serviceId, long metaGroupId) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.deleteMetaGroup(metaGroupId);
        }
    }

    public void updateMetaGroup(String serviceId, UpdateMetaGroupInfo updateMetaGroupInfo) throws StarException {
        checkLeader();

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.updateMetaGroup(updateMetaGroupInfo);
        }
    }

    public MetaGroupInfo getMetaGroupInfo(String serviceId, long metaGroupId) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            return shardManager.getMetaGroupInfo(metaGroupId);
        }
    }

    public List listMetaGroupInfo(String serviceId) throws StarException {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            return shardManager.listMetaGroupInfo();
        }
    }

    public void processWorkerHeartbeat(String serviceId, long workerId, long startTime, Map workerProperties,
            List shardIds) {
        checkLeader();

        long currentTime = System.currentTimeMillis();
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }

            LOG.debug("process heartbeat from worker {} for service {}.", workerId, serviceId);

            boolean isRestart = workerManager.processWorkerHeartbeat(serviceId, workerId, startTime,
                    shardIds.size(), workerProperties, currentTime);

            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            if (isRestart) {
                shardManager.scheduleShardsBelongToWorker(workerId);
            }
            // validate and possibly remove invalid replicas from the worker
            shardManager.validateWorkerReportedReplicas(shardIds, workerId);
        }
    }

    public FilePathInfo allocateFilePath(String serviceId, FileStoreType fsType, String suffix) {
        checkLeader();

        FileStoreMgr fsMgr = fsMgrs.getFileStoreMgr(fsType);
        if (fsMgr == null) {
            throw new StarException(ExceptionCode.INVALID_ARGUMENT,
                    String.format("invalid file store type %s", fsType));
        }

        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                throw new StarException(ExceptionCode.NOT_EXIST,
                        String.format("service %s not exist.", serviceId));
            }
        }

        FileStore fs = fsMgr.allocFileStore();
        FilePath fp = new FilePath(fs, String.format("%s/%s", serviceId, suffix));
        return fp.toProtobuf();
    }

    public void addFileStore(FileStoreInfo fsInfo) throws StarException {
        checkLeader();

        FileStoreMgr fsMgr = fsMgrs.getFileStoreMgr(fsInfo.getFsType());
        if (fsMgr == null) {
            throw new StarException(ExceptionCode.INVALID_ARGUMENT,
                    String.format("invalid file store type %s", fsInfo.getFsType()));
        }
        FileStore fs = fsMgr.newFsFromProtobuf(fsInfo);
        fsMgr.addFileStore(fs);
    }

    public void removeFileStore(FileStoreInfo fsInfo) throws StarException {
        checkLeader();

        FileStoreMgr fsMgr = fsMgrs.getFileStoreMgr(fsInfo.getFsType());
        if (fsMgr == null) {
            throw new StarException(ExceptionCode.INVALID_ARGUMENT,
                    String.format("invalid file store type %s", fsInfo.getFsType()));
        }
        fsMgr.removeFileStore(fsInfo.getFsKey());
    }

    public List listFileStore() throws StarException {
        // TODO:(jeff.ding)
        return new ArrayList();
    }

    public void updateFileStore(FileStoreInfo fsInfo) throws StarException {
        checkLeader();

        FileStoreMgr fsMgr = fsMgrs.getFileStoreMgr(fsInfo.getFsType());
        if (fsMgr == null) {
            throw new StarException(ExceptionCode.INVALID_ARGUMENT,
                    String.format("invalid file store type %s", fsInfo.getFsType()));
        }
        FileStore fs = fsMgr.newFsFromProtobuf(fsInfo);
        fsMgr.updateFileStore(fs);
    }

    public ShardManager getShardManager(String serviceId) {
        return serviceManager.getShardManager(serviceId);
    }

    // FOR TEST
    public ServiceManager getServiceManager() {
        return serviceManager;
    }

    // FOR TEST
    public WorkerManager getWorkerManager() {
        return workerManager;
    }

    // FOR TEST
    public IdGenerator getIdGenerator() {
        return idGenerator;
    }

    public void replay(Journal journal) {
        journalReplayer.replay(journal);
    }

    public void replayRegisterService(ServiceTemplate serviceTemplate) {
        serviceManager.replayRegisterService(serviceTemplate);
    }

    public void replayDeregisterService(String serviceTemplateName) {
        serviceManager.replayDeregisterService(serviceTemplateName);
    }

    public void replayBootstrapService(Service service) {
        serviceManager.replayBootstrapService(service);
        workerManager.createDefaultServiceWorkerGroup(service.getServiceId());
    }

    public void replayShutdownService(Service service) {
        serviceManager.replayShutdownService(service);
    }

    public void replayCreateShard(String serviceId, CreateShardJournalInfo info) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay create shard, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayCreateShard(info);
        }
    }

    public void replayDeleteShard(String serviceId, List shardIds) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay delete shard, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayDeleteShard(shardIds);
        }
    }

    public void replayUpdateShard(String serviceId, List shards) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay update shard, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayUpdateShard(shards);
        }
    }

    public void replayCreateShardGroup(String serviceId, List shardGroups) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay create shard group, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayCreateShardGroup(shardGroups);
        }
    }

    public void replayDeleteShardGroup(String serviceId, DeleteShardGroupInfo info) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay delete shard group, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayDeleteShardGroup(info);
        }
    }

    public void replayCreateMetaGroup(String serviceId, MetaGroupJournalInfo info) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay create meta group, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayCreateMetaGroup(info);
        }
    }

    public void replayDeleteMetaGroup(String serviceId, MetaGroupJournalInfo info) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay delete meta group, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayDeleteMetaGroup(info);
        }
    }

    public void replayUpdateMetaGroup(String serviceId, MetaGroupJournalInfo info) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay update meta group, should not happen!", serviceId);
            }
            ShardManager shardManager = getShardManager(serviceId);
            assert shardManager != null;
            shardManager.replayUpdateMetaGroup(info);
        }
    }

    public void replayAddWorker(String serviceId, Worker worker) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay add worker, should not happen!", serviceId);
            }
            workerManager.replayAddWorker(serviceId, worker);
        }
    }

    public void replayUpdateWorker(String serviceId, List workers) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay update worker, should not happen!", serviceId);
            }
            workerManager.replayUpdateWorker(serviceId, workers);
        }
    }

    public void replayRemoveWorker(String serviceId, long groupId, long workerId) {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            if (!serviceManager.existService(serviceId)) {
                LogUtils.fatal(LOG, "service {} not exist when replay remove worker, should not happen!", serviceId);
            }
            workerManager.replayRemoveWorker(serviceId, groupId, workerId);
        }
    }

    public void replaySetId(long id) {
        idGenerator.setNextId(id);
    }

    // WARNING: BE VERY CAREFUL ABOUT THIS FUNCTION!
    // for durability purpose
    // stream like dump method to decrease memory consumption
    // NOTE: does not support strong consistency
    public void dumpMeta(DataOutputStream out) throws IOException {
        LOG.info("start dump star manager meta data to file.");
        // write raw header
        out.write(FILE_META_RAW_HEADER.getBytes(StandardCharsets.UTF_8));

        // write header
        StarManagerFileMetaHeader header = StarManagerFileMetaHeader.newBuilder()
                .setGenerateTime(System.currentTimeMillis())
                .setReplayJournalId(journalSystem.getReplayId())
                .setNextGlobalId(idGenerator.getNextPersistentId())
                .build();
        byte[] hbytes = header.toByteArray();
        Text.writeBytes(out, hbytes);

        // write each component, DO NOT changed order
        serviceManager.dumpMeta(out);
        workerManager.dumpMeta(out);

        // write holder, holder is used for compatibility, if there is any other
        // new meta, can put it in holder
        out.writeInt(0); // currently there is none
        // StarManagerFileMetaHolder holder = StarManagerFileMetaHolder.newBuilder().build();

        // write footer
        StarManagerFileMetaFooter footer = StarManagerFileMetaFooter.newBuilder().build();
        byte[] fbytes = header.toByteArray();
        Text.writeBytes(out, fbytes);

        LOG.info("end dump star manager meta data to file.");
    }

    // called by loadMeta, prepare default group for worker
    public void prepareDefaultGroup() {
        try (LockCloseable lock = new LockCloseable(serviceManager.readLock())) {
            Set serviceIds = serviceManager.getServiceIdSet();
            for (String serviceId : serviceIds) {
                workerManager.createDefaultServiceWorkerGroup(serviceId);
            }
        }
    }

    // WARNING: BE VERY CAREFUL ABOUT THIS FUNCTION!
    public void loadMeta(DataInputStream in) throws IOException {
        LOG.info("start load star manager meta data from file.");

        if (in.available() == 0) {
            LOG.warn("load star manager meta data found empty stream, do nothing.");
            return;
        }

        // read raw header
        int size = FILE_META_RAW_HEADER.getBytes(StandardCharsets.UTF_8).length;
        byte[] bytes = new byte[size];
        in.readFully(bytes, 0, size);
        String copy = new String(bytes, StandardCharsets.UTF_8);
        if (!copy.equals(FILE_META_RAW_HEADER)) {
            throw new IOException("verify star manager meta file raw header failed, meta is not valid.");
        }

        // read header
        byte[] hbytes = Text.readBytes(in);
        StarManagerFileMetaHeader header = StarManagerFileMetaHeader.parseFrom(hbytes);
        long generateTime = header.getGenerateTime();
        long replayJournalId = header.getReplayJournalId();
        long nextGlobalId = header.getNextGlobalId();

        journalSystem.setReplayId(replayJournalId);
        idGenerator.setNextId(nextGlobalId);

        // read each component, DO NOT change order
        serviceManager.loadMeta(in);
        prepareDefaultGroup();

        workerManager.loadMeta(in);

        // read holder
        int holderCount = in.readInt();
        for (int i = 0; i < holderCount; ++i) {
            byte[] b = Text.readBytes(in);
            StarManagerFileMetaHolder holder = StarManagerFileMetaHolder.parseFrom(b);
            // do nothing now
        }

        // read footer
        byte[] fbytes = Text.readBytes(in);
        StarManagerFileMetaFooter footer = StarManagerFileMetaFooter.parseFrom(fbytes);

        LOG.info("end load star manager meta data from file generated at {}, replay journal id {}.",
                new SimpleDateFormat("MM-dd HH:mm:ss").format(new Date(generateTime)), replayJournalId);
    }

    // for debug purpose, dump human readable json meta
    public String dump() throws IOException {
        String name = "star_manager_meta";
        File file = new File(name);
        DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
        serviceManager.dump(dos);
        workerManager.dump(dos);
        return Config.STARMGR_IP + ":" + file.getAbsolutePath();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy