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

org.jgroups.protocols.raft.InMemoryLog Maven / Gradle / Ivy

There is a newer version: 1.0.14.Final
Show newest version
package org.jgroups.protocols.raft;

import org.jgroups.Address;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.ObjIntConsumer;

/**
 * In-memory log implementation without any persistence. Used only by unit tests. Note that synchronization is
 * half-baked.
 * @author Bela Ban
 * @since  0.2
 */
public class InMemoryLog implements Log {
    protected String       name; // the name of this log
    protected int          current_term;
    protected Address      voted_for;
    protected int          first_appended;
    protected int          last_appended;
    protected int          commit_index;
    protected LogEntry[]   entries;

    // keeps all logs, keyed by name
    public static final Map logs=new ConcurrentHashMap<>();
    protected static final int          INCR=16; // always increase entries by 16 when needed


    public InMemoryLog() {
    }

    @Override
    public void init(String log_name, Map args) throws Exception {
        name=log_name;
        InMemoryLog existing=(InMemoryLog)logs.putIfAbsent(name, this);
        if(existing != null) {
            current_term=existing.current_term;
            voted_for=existing.voted_for;
            first_appended=existing.first_appended;
            last_appended=existing.last_appended;
            commit_index=existing.commit_index;
            entries=existing.entries;
        }
        else {
            current_term=0;
            voted_for=null;
            first_appended=0;
            last_appended=0;
            commit_index=0;
            entries=new LogEntry[16];
        }
    }

    @Override
    public void close() {}

    @Override
    public void delete() {
        logs.remove(name);
    }

    @Override
    public int currentTerm() {return current_term;}

    @Override
    public synchronized Log currentTerm(int new_term) {
        current_term=new_term; return this;
    }

    @Override
    public Address votedFor() {return voted_for;}

    @Override
    public synchronized Log votedFor(Address member) {
        voted_for=member; return this;
    }

    @Override
    public int commitIndex() {return commit_index;}

    @Override
    public synchronized Log commitIndex(int new_index) {
        //if(new_index > last_appended)
          //  throw new IllegalStateException("commit_index (" + commit_index + ") cannot be set to " + new_index +
            //                                  " as last_appended is " + last_appended);
        commit_index=new_index; return this;
    }

    @Override
    public int firstAppended() {return first_appended;}

    @Override
    public int lastAppended() {return last_appended;}

    @Override
    public synchronized void append(int index, boolean overwrite, LogEntry... new_entries) {
        int space_required=new_entries != null? new_entries.length : 0;
        int available_space=this.entries.length - 1 - last_appended;
        if(space_required > available_space)
            expand(space_required - available_space +1);

        for(LogEntry entry: new_entries) {
            int idx=index- first_appended;
            if(!overwrite && this.entries[idx] != null)
                throw new IllegalStateException("Index " + index + " already contains a log entry: " + this.entries[idx]);
            this.entries[idx]=entry;
            last_appended=Math.max(last_appended, index);
            index++;
            if(entry.term > current_term)
                current_term=entry.term;
        }
    }


    @Override
    public synchronized LogEntry get(int index) {
        int real_index=index - first_appended;
        return real_index < 0 || real_index >= entries.length? null : entries[real_index];
    }

    @Override
    public synchronized void truncate(int index) {
        if(index > commit_index)
            index=commit_index;
        LogEntry[] tmp=new LogEntry[entries.length];
        int idx=index- first_appended;
        System.arraycopy(entries, idx, tmp, 0, entries.length - idx);
        entries=tmp;
        first_appended=index;
    }

    @Override
    public synchronized void deleteAllEntriesStartingFrom(int start_index) {
        int idx=start_index- first_appended;
        if(idx < 0 || idx >= entries.length)
            return;

        for(int index=idx; index <= last_appended; index++)
            entries[index]=null;

        LogEntry last=get(start_index - 1);
        current_term=last != null? last.term : 0;
        last_appended=start_index-1;
        if(commit_index > last_appended)
            commit_index=last_appended;
    }

    @Override
    public synchronized void forEach(ObjIntConsumer function, int start_index, int end_index) {
        if(start_index < first_appended)
            start_index=first_appended;
        if(end_index > last_appended)
            end_index=last_appended;

        int start=Math.max(1, start_index)- first_appended, end=end_index- first_appended;
        for(int i=start; i <= end; i++) {
            LogEntry entry=entries[i];
            function.accept(entry, start_index);
            start_index++;
        }
    }

    @Override
    public synchronized void forEach(ObjIntConsumer function) {
        forEach(function, Math.max(1, first_appended), last_appended);
    }


    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append("first_appended=").append(first_appended).append(", last_appended=").append(last_appended)
          .append(", commit_index=").append(commit_index).append(", current_term=").append(current_term);
        return sb.toString();
    }

    /** Lock must be held to call this method */
    protected void expand(int min_size_needed) {
        LogEntry[] new_entries=new LogEntry[Math.max(entries.length + INCR, entries.length + min_size_needed)];
        System.arraycopy(entries, 0, new_entries, 0, entries.length);
        entries=new_entries;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy