(defpackage :fwoar.raft
(:use :cl )
(:export ))
(in-package :fwoar.raft)
(defun take-keys (h-t &rest keys)
(mapcar (lambda (key)
(gethash key h-t))
keys))
(defclass node ()
((%current-term :accessor term :initform 0 :initarg :current-term)
(%voted-for :accessor voted-for :initform nil :initarg :leader-id)
(%e-log :accessor e-log
:initform (make-array 100 :adjustable t :fill-pointer 0))
(%client-id :accessor id)
(%committed-index :accessor commit-index :initform 0)
(%last-applied :accessor last-applied :initform 0)))
(defclass leader (node)
((%next-index :accessor next-index :initform ())
(%match-index :accessor match-index :initform ())))
(defclass append-entry-arguments ()
((%term :initarg :term :reader term)
(%leader-id :initarg :leader-id :reader leader-id)
(%prev-log-index :initarg :prev-log-index :reader prev-log-index)
(%prev-log-term :initarg :prev-log-term :reader prev-log-term)
(%entries :initarg :entries :reader entries)
(%leader-commit :initarg :leader-commit :reader leader-commit)))
(defclass entry ()
((%term :initarg :term :accessor term)
(%data :initarg :data :accessor data)))
(defmethod print-object ((o entry) s)
(print-unreadable-object (o s :type t :identity t)
(format s "term: ~s data: ~s"
(term o)
(data o))))
(defun entry (term data)
(make-instance 'entry
:term term
:data data))
(defun add-log-entry (node entry)
(assert (= (term entry) (term node))
(entry node)
"term-mismatch ~s ~s"
(term entry)
(term node))
(vector-push-extend entry (e-log node)))
(defun get-log-entry (follower idx)
(elt (e-log follower)
idx))
(defgeneric append-entries (follower args)
(:method ((follower node) (args append-entry-arguments))
(with-accessors ((term term)
(leader-id leader-id)
(prev-log-index prev-log-index)
(prev-log-term prev-log-term)
(entries entries)
(leader-commit leader-commit)) args
(when (< term (term follower))
(return-from append-entries
(values term nil)))
(when (/= (term (get-log-entry follower prev-log-index))
prev-log-term)
(return-from append-entries
(values term nil)))
#|If an existing entry conflicts with a new one (same index but|#
#| different terms), delete the existing entry and all that |#
#| follow it (ยง5.3) |#
(loop for new-entries-index from (1+ prev-log-index)
for (entry . rest-entries) on entries
for existing-entry in (subseq (e-log follower) (1+ prev-log-index))
until (/= (term entry)
(term existing-entry))
finally
(when (< new-entries-index (length (e-log follower)))
(setf (fill-pointer (e-log follower)) new-entries-index))
(map nil
(lambda (el)
(vector-push-extend el (e-log follower)))
rest-entries))
(when (> leader-commit (commit-index follower))
(setf (commit-index follower)
(min leader-commit
(1- (length (e-log follower))))))
(values (term follower)
t))))
|