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

io.journalkeeper.journalstore.JournalStoreState Maven / Gradle / Ivy

There is a newer version: 0.1.11
Show newest version
/**
 * 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.
 */
package io.journalkeeper.journalstore;

import io.journalkeeper.core.api.RaftJournal;
import io.journalkeeper.core.api.State;
import io.journalkeeper.core.api.StateResult;
import io.journalkeeper.utils.threads.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Flushable;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static io.journalkeeper.core.api.RaftJournal.RESERVED_PARTITIONS_START;
import static io.journalkeeper.journalstore.JournalStoreQuery.CMD_QUERY_ENTRIES;
import static io.journalkeeper.journalstore.JournalStoreQuery.CMD_QUERY_INDEX;
import static io.journalkeeper.journalstore.JournalStoreQuery.CMD_QUERY_PARTITIONS;

/**
 * @author LiYue
 * Date: 2019-05-09
 */
public class JournalStoreState implements State , Flushable {
    private static final Logger logger = LoggerFactory.getLogger(JournalStoreState.class);
    private final static String STATE_FILE_NAME = "applied_indices";
    private AppliedIndicesFile appliedIndices;
    private ExecutorService stateQueryExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("JournalStoreQueryThread"));
    private Path path;
    @Override
    public void recover(Path path, Properties properties) throws IOException{
        this.path = path;
        appliedIndices = recoverAppliedIndices(path.resolve(STATE_FILE_NAME));
    }

    @Override
    public void flush() {
        if(null != path) {
            flushAppliedIndices(path.resolve(STATE_FILE_NAME));
        }
    }

    private void flushAppliedIndices(Path path) {
        appliedIndices.flush();
    }

    /**
     * 从文件恢复
     */
    private AppliedIndicesFile recoverAppliedIndices(Path path) throws IOException {
        AppliedIndicesFile appliedIndicesFile = new AppliedIndicesFile(path.toFile());
        appliedIndicesFile.recover();
        return appliedIndicesFile;
    }

    @Override
    public StateResult execute(byte [] entry, int partition, long lastApplied, int batchSize, RaftJournal journal) {
        long partitionIndex = appliedIndices.getOrDefault(partition, 0L) ;
        appliedIndices.put(partition, partitionIndex + batchSize);
        long minIndex = journal.minIndex(partition);
        long maxIndex = appliedIndices.getOrDefault(partition, 0L);
        StateResult result = new StateResult<>(partitionIndex);
        Map eventData = result.getEventData();
        eventData.put("partition", String.valueOf(partition));
        eventData.put("minIndex", String.valueOf(minIndex));
        eventData.put("maxIndex", String.valueOf(maxIndex));
        return result ;
    }

    @Override
    public JournalStoreQueryResult query(JournalStoreQuery query, RaftJournal journal) {
        try {
            switch (query.getCmd()) {
                case CMD_QUERY_ENTRIES:
                    return queryEntries(query.getPartition(), query.getIndex(), query.getSize(), journal);
                case CMD_QUERY_PARTITIONS:
                    return queryPartitions(journal);
                case CMD_QUERY_INDEX:
                    return queryIndex(query.getPartition(), query.getTimestamp(), journal);
                default:
                    throw new QueryJournalStoreException(String.format("Invalid command type: %d.", query.getCmd()));

            }
        } catch (Throwable e) {
            return new JournalStoreQueryResult(e, query.getCmd());
        }
    }

    private JournalStoreQueryResult queryIndex(int partition, long timestamp, RaftJournal journal) {

        return  new JournalStoreQueryResult(journal.queryIndexByTimestamp(partition, timestamp));
    }

    private JournalStoreQueryResult queryPartitions(RaftJournal journal) {
        Set partitions = journal.getPartitions();
        partitions.removeIf(partition -> partition >= RESERVED_PARTITIONS_START);
        return
            new JournalStoreQueryResult(
                    partitions.stream()
                    .collect(Collectors.toMap(
                            Integer::intValue,
                            partition -> new JournalStoreQueryResult.Boundary(journal.minIndex(partition), appliedIndices.getOrDefault(partition, 0L))
                    )));
    }



    private JournalStoreQueryResult queryEntries(int partition, long index, int size, RaftJournal journal) {
        long maxAppliedIndex = appliedIndices.getOrDefault(partition, 0L);
        int safeSize;
        if(index > maxAppliedIndex || index > journal.maxIndex(partition)) {
            return new JournalStoreQueryResult(null, null, CMD_QUERY_ENTRIES, index, JournalStoreQueryResult.CODE_OVERFLOW);
        }

        if(index < journal.minIndex(partition)) {
            return new JournalStoreQueryResult(null, null, CMD_QUERY_ENTRIES, index, JournalStoreQueryResult.CODE_UNDERFLOW);
        }

        if(index == journal.maxIndex(partition)) {
            return new JournalStoreQueryResult(Collections.emptyList());
        }

        if(index + size >= maxAppliedIndex) {
            safeSize = (int) (maxAppliedIndex - index);
        } else {
            safeSize = size;
        }
        return new JournalStoreQueryResult(journal.batchReadByPartition(partition, index, safeSize));

    }

    @Override
    public void close() {
        if(null != appliedIndices) {
            appliedIndices.close();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy