{"id":20321376,"url":"https://github.com/openacid/traft","last_synced_at":"2025-06-14T08:06:56.291Z","repository":{"id":97578286,"uuid":"337402623","full_name":"openacid/traft","owner":"openacid","description":"raft variant with topology order logs","archived":false,"fork":false,"pushed_at":"2021-02-28T16:25:04.000Z","size":640,"stargazers_count":27,"open_issues_count":0,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-25T15:03:39.337Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openacid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-09T12:49:18.000Z","updated_at":"2022-05-28T13:47:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"e1518059-65e5-44e6-9bc9-f36f39879f30","html_url":"https://github.com/openacid/traft","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":"openacid/gotmpl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Ftraft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Ftraft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Ftraft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openacid%2Ftraft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openacid","download_url":"https://codeload.github.com/openacid/traft/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248465344,"owners_count":21108244,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-14T19:14:46.898Z","updated_at":"2025-04-11T19:10:22.426Z","avatar_url":"https://github.com/openacid.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*\n\n- [traft](#traft)\n  - [Merge Log](#merge-log)\n    - [Definition](#definition)\n    - [Lemma-only-max-committer-logs](#lemma-only-max-committer-logs)\n- [Planned improvement to original raft](#planned-improvement-to-original-raft)\n- [Features:](#features)\n- [Progress](#progress)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n# traft\n\n## Merge Log\n\n### Definition\n\n- **Safe**: A log that is safe if it has been replicated to a quorum, no matter\n  whether or not the **committed** flag is set on any replica.\n\n---\n\nAfter a replica established leadership, it needs to merge the latest logs from a\nquorum of replicas, to ensure that the leader replica has all **safe** logs.\n\n\n### Lemma-only-max-committer-logs\n\nIn TRaft, a leader only needs to use the logs from replicas with the max **committer**(`(term, id)`).\n\nA log that does not present in any max-committer replicas a leader seen can **not**\nbe safe.\n\nProof:\n\nIf a log `A` becomes **safe**, it will be seen by the next leader `Li`.\nBecause a leader has to collect logs from a quorum and any two quorum\nintersections with each other.\n\nIf the next next leader `Lj`(`j\u003ei`) has seen `Li`, it will choose `A`.\nOtherwise, it will see a replica that has `A`.\n\n∴ Any newer leader will choose `A`.\n\n∴ TRaft only need to merge logs from replicas with the latest `Committer`.\n\nE.g.:\n\n```\nLi: indicates a replica becomes leader\nA/B: a log is written\n\nR0 L1 A\nR1    A\nR2    A\nR3      L2 B\nR4           L3\n------------------------\u003e time\n```\n\nIn this digram:\nL2 sees `A` and then updates its `Committer` to `L2`, then writes log `B` to its\nlocal log. And R3 crashed before forwarding any log out.\n\n-   If L3 established its leadership by contacting R2 and R3, it uses logs from only\n    R3(R3 has the latest committer `L2`), it will see `A`.\n\n-   If L3 established its leadership by contacting R0 and R1, it will also see `A`.\n\n\n都说deadline 是第一生产力. 放假没事, 试试看能不能7天写个raft出来, 当练手了. 2021-02-09\n装逼有风险, 万一写不出来也别笑话我.\n\n7天内直播: https://live.bilibili.com/22732677?visit_id=6eoy1n42a1w0\n\n# Planned improvement to original raft\n\n-   Leader election with less conflict.\n    Raft has the issue that in a term, if multiple candidates try to elect theirselves,\n    the conflicts are unacceptable.\n    Because in one term, A voter will only vote for at most one leader.\n\n    In our impl, `term` is less strict:\n    A voter is allowed to vote another GREATER leader.\n\n-   Out of order commit out of order apply.\n\n    We use a bitmap to describe what logs interfere each other.\n\n    \n-   Adopt a more generalized member change algo.\n\n    Get rid of single-step member change.\n    Because any of the CORRECT single-step member change algo is equivalent to joint-consensus.\n\n    But joint-consensus is a specialization of the TODO (I dont have good name for it yet).\n\n\n\n# Features:\n\n- [ ] Leader election\n- [ ] WAL log\n- [ ] snapshot: impl with https://github.com/openacid/slim , a static kv-like storage engine supporting protobuf.\n- [ ] member change with generalized joint consensus.\n- [ ] Out of order commit/apply if possible.\n\n# Progress\n\n-   2021-02-10:\n    LOC: +1008 -1\n\n    ```\n    buildMajorityQuorums()\n    import TailBitmap, add Union()\n    TailBitmap.Clone()\n    TailBitmap.Diff()\n    ```\n\n-   2021-02-11:\n    LOC: +754 -44\n\n    ```\n    refactor buildMajorityQuorums()\n    LeaderId.Cmp()\n    add NewLeaderId\n    add NewBallot()\n    fix: LeaderId.Cmp() accept nil as operand\n    Ballot.CmpLog() to compare only the log-related fields\n    rename Ballot.Accepted to Ballot.AcceptedFrom\n    TailBitmap.Len()\n    refactor design, add ReplicaStatus, remove Ballot.\n    impl Vote Handler, under dev!!!\n    use gogoproto, build clean .pb.go with less code, add serveCluster() to setup a simple cluster for test\n    add NewCmdI64()\n    add NewRecord()\n    add ClusterConfig.GetReplicaInfo()\n    NewTailBitmap() accepts extra bits to set\n    ```\n\n-   2021-02-12:\n    LOC: +2601 -70\n\n    ```\n    add LeaderId:Clone()\n    refactor TailBitmap.Clone(): use proto\n    draft test of vote\n    rename By to Author, AcceptedFrom to Committer. borrowed concepts from git:DDD\n    add test: HandleVoteReq. add ShortStr() to Cmd, LeaderI, Record and []Record\n    refactor VoteReply: do not use ReplicaStatus to describe log status\n    add readme to record progress\n    readme: impl storage with slim\n    test that voter send back nil log\n    update readme: collect git log\n    TailBitmap: accept second operand to be nil\n    ```\n\n-   2021-02-13:\n    LOC: +1309 -183\n\n    ```\n    test Replicate, under dev\n    rename Node.Log to Node.Logs\n    add Cmd.Intefering() to check if two commands not be allowed to change execution order\n    add Record.Interfering()\n    update readme\n    NewTailBitmap() support non-64-aligned offset\n    add AddLog() for leader to propose a command\n    use map to store cluster members instead of slice\n    add ClusterConfig.IsQuorum() to check if a set of members is a quorum\n    TRaft.VoteOnce() run one round voting, to establish leadership\n    TRaft actor loop and voting loop\n    ```\n\n-   2021-02-14:\n    LOC: +891 -229\n\n    ```\n    mainloop as an actor is the only one update traft data. under dev. not passed yet\n    test VoteLoop\n    granted leader merges collected logs\n    after vote, leader merge responded logs\n    add API Propose without replication\n    ```\n\n-   2021-02-15:\n    LOC: +476 -197\n\n    ```\n    add interface toCmd() to build Cmd from string\n    test Replicate()\n    add TRaft.sleep(): sleep only if it is not stopped.\n    ```\n\n-   2021-02-16:\n    LOC: +1297 -592\n\n    ```\n    refactor: rename Replicate to LogForward\n    refactor: vote_test: remove unused type, funcs\n    gruop daily log format by date\n    ```\n\n\n\n\n\u003c!--\n# Day-0 2021-02-09\n\n- [x] TailBitmap to support for describing log dependency etc. see: https://github.com/openacid/low/blob/ci/bitmap/tailbitmap.go\n\n# Day-1 2021-02-10\n\n- [x]: design t-raft protobuf\n\n# Day-2 2021-02-11\n\n- [x]: design t-raft protobuf\n- [x]: impl handle_vote\n\n# Day-3 2021-02-12\n\n- [x]: refactor concepts\n- [x]: test handle_vote\n- [ ]: impl log replication\n- [ ]: impl traft main-loop\n--\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenacid%2Ftraft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenacid%2Ftraft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenacid%2Ftraft/lists"}