Exemple #1
0
    def __init__(self, port, initialMembers=None):
        # persistent state
        # TODO: make persistent
        self.currentTerm = 0
        self.votedFor = None
        self.log = []

        # volatile state
        self.commitIndex = 0
        self.lastApplied = 0

        # other state
        self.role = Role.FOLLOWER
        self.port = port
        # a global lock for thread synhronization between the poll method
        # and the rpc methods
        self.lock = threading.Lock()

        # init server
        processor = Raft.Processor(self)
        transport = TSocket.TServerSocket(port=port)

        self.server = ThreadPoolThriftServer(processor, transport)

        self.initialMembers = initialMembers
Exemple #2
0
    def __init__(self,port,initialMembers=None):
        # persistent state
        # TODO: make persistent
        self.currentTerm = 0
        self.votedFor = None
        self.log = []

        # volatile state
        self.commitIndex = 0
        self.lastApplied = 0

        # other state
        self.role = Role.FOLLOWER
        self.port = port
        # a global lock for thread synhronization between the poll method
        # and the rpc methods
        self.lock = threading.Lock()

        # init server
        processor = Raft.Processor(self)
        transport = TSocket.TServerSocket(port=port)

        self.server = ThreadPoolThriftServer(processor, transport)

        self.initialMembers = initialMembers
Exemple #3
0
class RaftNode:

    def __init__(self,port,initialMembers=None):
        # persistent state
        # TODO: make persistent
        self.currentTerm = 0
        self.votedFor = None
        self.log = []

        # volatile state
        self.commitIndex = 0
        self.lastApplied = 0

        # other state
        self.role = Role.FOLLOWER
        self.port = port
        # a global lock for thread synhronization between the poll method
        # and the rpc methods
        self.lock = threading.Lock()

        # init server
        processor = Raft.Processor(self)
        transport = TSocket.TServerSocket(port=port)

        self.server = ThreadPoolThriftServer(processor, transport)

        self.initialMembers = initialMembers

    def start(self):
        # start listening thread
        self.listen_thread = threading.Thread(target=self._listen)
        #self.listen_thread.setDaemon(True)
        self.listen_thread.start()

    def _listen(self):
        print 'listening'
        try:
            self.server.serve()
        except Exception as e:
            print '_listen caught',e
        print 'done listening'

    def connect(self):
        # init other sockets to connect to other members
        if self.initialMembers != None:
            self.members = []
            for (addr,port) in self.initialMembers:
                client = connectClient(addr,port)

                self.members.append(client)

    def poll(self):
        with self.lock:
            time.sleep(1)

    def stop(self):
        try:
            self.server.stop()
            self.listen_thread.join()
        except Exception as e:
            print 'exception on stop',e

    # The rpc methods
    def ping(self):
        # doesnt actually need the lock, but for good measure
        with self.lock:
            return 'pong'

    def appendEntries(self, term, leaderId, prevLogIndex, prevLogTerm, entries, leaderCommit):
        # TODO: remove
        print 'called appendEntries'
        # TODO: figure out what to do with leaderId
        with self.lock:
            ret = AppendReturn(self.currentTerm,False)
            try:
                # Reply false if term < currentTerm
                if term < self.currentTerm:
                    # TODO: remove
                    print 'term is too old'
                    return ret

                # Reply false if log doesn't contain an entry at prevLogIndex
                # whose term matches prevLogTerm
                # case for empty log
                if ( len(self.log) > 0 or prevLogIndex >= 0 ) and \
                  (len(self.log) < prevLogIndex+1 or self.log[prevLogIndex][0] != prevLogTerm):
                    # TODO: remove
                    print 'no entry at prevLogIndex'
                    return ret

                # If an existing entry conflicts with a new one (same index
                # but different terms), delete the existing entry and all that
                # follow it
                for i in range(prevLogIndex+1,len(self.log)):
                    entryIndex = i - prevLogIndex - 1
                    if entryIndex > len(entries):
                        break
                    # TODO: should only the term match?
                    if self.log[i] != (term,entries[entryIndex]):
                        self.log = self.log[:i]
                        break

                # Append any new entries not already in the log
                insertIndex = prevLogIndex+1
                for e in entries:
                    if len(self.log) > insertIndex:
                        self.log[insertIndex] = (term,e)
                    else:
                        self.log.append((term,e))

                # If leaderCommit > commitIndex, set commitIndex =
                # min(leaderCommit, index of last new entry)
                if leaderCommit > self.commitIndex:
                    self.commitIndex = min(leaderCommit,len(self.log) - 1)

                # TODO: remove
                print 'log is now',self.log
                ret.success = True

            except Exception as err:
                print err
            return ret

    def requestVote(self, term, candidateId, lastLogIndex, lastLogTerm):
        with self.lock:
            ret = VoteReturn(self.currentTerm,False)
            if term < self.currentTerm:
                return ret
            if self.votedFor is None:
                self.votedFor = candidateId
                ret.voteGranted = True
                return ret
            # grant vote if candidate is at as up to date as this node's log
            if lastLogIndex >= len(self.log) - 1 and lastLogTerm >= self.log[-1][0]:
                self.votedFor = candidateId
                ret.voteGranted = True
                return ret
            return ret

    def installSnapshot(self, term, leaderId, lastIncludedIndex, lastIncludedTerm, offset, data, done):
        with self.lock:
            pass

    def stepState(self):
        self.applySM()

        if self.role == Role.FOLLOWER:
            pass
        elif self.role == Role.CANDIDATE:
            pass
        elif self.role == Role.LEADER:
            pass
        else:
            raise ValueError('Node found itself in an unknown state: '+self.role)

    # Apply the latest entry to the state machine if applicable
    def applySM(self):
        pass
Exemple #4
0
class RaftNode:
    def __init__(self, port, initialMembers=None):
        # persistent state
        # TODO: make persistent
        self.currentTerm = 0
        self.votedFor = None
        self.log = []

        # volatile state
        self.commitIndex = 0
        self.lastApplied = 0

        # other state
        self.role = Role.FOLLOWER
        self.port = port
        # a global lock for thread synhronization between the poll method
        # and the rpc methods
        self.lock = threading.Lock()

        # init server
        processor = Raft.Processor(self)
        transport = TSocket.TServerSocket(port=port)

        self.server = ThreadPoolThriftServer(processor, transport)

        self.initialMembers = initialMembers

    def start(self):
        # start listening thread
        self.listen_thread = threading.Thread(target=self._listen)
        #self.listen_thread.setDaemon(True)
        self.listen_thread.start()

    def _listen(self):
        print 'listening'
        try:
            self.server.serve()
        except Exception as e:
            print '_listen caught', e
        print 'done listening'

    def connect(self):
        # init other sockets to connect to other members
        if self.initialMembers != None:
            self.members = []
            for (addr, port) in self.initialMembers:
                client = connectClient(addr, port)

                self.members.append(client)

    def poll(self):
        with self.lock:
            time.sleep(1)

    def stop(self):
        try:
            self.server.stop()
            self.listen_thread.join()
        except Exception as e:
            print 'exception on stop', e

    # The rpc methods
    def ping(self):
        # doesnt actually need the lock, but for good measure
        with self.lock:
            return 'pong'

    def appendEntries(self, term, leaderId, prevLogIndex, prevLogTerm, entries,
                      leaderCommit):
        # TODO: remove
        print 'called appendEntries'
        # TODO: figure out what to do with leaderId
        with self.lock:
            ret = AppendReturn(self.currentTerm, False)
            try:
                # Reply false if term < currentTerm
                if term < self.currentTerm:
                    # TODO: remove
                    print 'term is too old'
                    return ret

                # Reply false if log doesn't contain an entry at prevLogIndex
                # whose term matches prevLogTerm
                # case for empty log
                if ( len(self.log) > 0 or prevLogIndex >= 0 ) and \
                  (len(self.log) < prevLogIndex+1 or self.log[prevLogIndex][0] != prevLogTerm):
                    # TODO: remove
                    print 'no entry at prevLogIndex'
                    return ret

                # If an existing entry conflicts with a new one (same index
                # but different terms), delete the existing entry and all that
                # follow it
                for i in range(prevLogIndex + 1, len(self.log)):
                    entryIndex = i - prevLogIndex - 1
                    if entryIndex > len(entries):
                        break
                    # TODO: should only the term match?
                    if self.log[i] != (term, entries[entryIndex]):
                        self.log = self.log[:i]
                        break

                # Append any new entries not already in the log
                insertIndex = prevLogIndex + 1
                for e in entries:
                    if len(self.log) > insertIndex:
                        self.log[insertIndex] = (term, e)
                    else:
                        self.log.append((term, e))

                # If leaderCommit > commitIndex, set commitIndex =
                # min(leaderCommit, index of last new entry)
                if leaderCommit > self.commitIndex:
                    self.commitIndex = min(leaderCommit, len(self.log) - 1)

                # TODO: remove
                print 'log is now', self.log
                ret.success = True

            except Exception as err:
                print err
            return ret

    def requestVote(self, term, candidateId, lastLogIndex, lastLogTerm):
        with self.lock:
            ret = VoteReturn(self.currentTerm, False)
            if term < self.currentTerm:
                return ret
            if self.votedFor is None:
                self.votedFor = candidateId
                ret.voteGranted = True
                return ret
            # grant vote if candidate is at as up to date as this node's log
            if lastLogIndex >= len(
                    self.log) - 1 and lastLogTerm >= self.log[-1][0]:
                self.votedFor = candidateId
                ret.voteGranted = True
                return ret
            return ret

    def installSnapshot(self, term, leaderId, lastIncludedIndex,
                        lastIncludedTerm, offset, data, done):
        with self.lock:
            pass

    def stepState(self):
        self.applySM()

        if self.role == Role.FOLLOWER:
            pass
        elif self.role == Role.CANDIDATE:
            pass
        elif self.role == Role.LEADER:
            pass
        else:
            raise ValueError('Node found itself in an unknown state: ' +
                             self.role)

    # Apply the latest entry to the state machine if applicable
    def applySM(self):
        pass