├── report ├── report.pdf └── figure │ ├── figure.pptx │ ├── result │ ├── paxos │ │ ├── consensus.png │ │ ├── educoder.png │ │ ├── proposer0.png │ │ └── log │ │ │ ├── Proposer4 │ │ │ └── 2023-02-05.log │ │ │ ├── Paxos │ │ │ └── 2023-02-05.log │ │ │ ├── Proposer0 │ │ │ └── 2023-02-05.log │ │ │ ├── Proposer1 │ │ │ └── 2023-02-05.log │ │ │ ├── Proposer2 │ │ │ └── 2023-02-05.log │ │ │ └── Proposer3 │ │ │ └── 2023-02-05.log │ └── write_through │ │ └── educoder.png │ ├── read.svg │ ├── write_through.svg │ └── paxos.svg ├── assignment ├── image │ ├── read.png │ ├── write.png │ └── paxos_test.png ├── paxos │ ├── run.sh │ ├── Paxos │ │ ├── src │ │ │ ├── Paxos │ │ │ │ ├── PaxosData.h │ │ │ │ ├── Acceptor.h │ │ │ │ ├── Acceptor.cpp │ │ │ │ ├── Proposer.h │ │ │ │ └── Proposer.cpp │ │ │ ├── lib │ │ │ │ ├── atom.h │ │ │ │ ├── FixLengthInt.h │ │ │ │ ├── Task.cpp │ │ │ │ ├── Task.h │ │ │ │ ├── Lock.h │ │ │ │ ├── Executor.cpp │ │ │ │ ├── Executor.h │ │ │ │ ├── mapi.h │ │ │ │ ├── atom.cpp │ │ │ │ ├── Lock.cpp │ │ │ │ ├── Logger.h │ │ │ │ ├── Thread.h │ │ │ │ ├── Thread.cpp │ │ │ │ ├── mapi.cpp │ │ │ │ └── Logger.cpp │ │ │ └── Paxos.cpp │ │ └── Makefile │ └── README.md ├── write_through │ ├── README.md │ ├── sim_file.py │ ├── test_main.py │ ├── server.py │ └── cache.py └── README.md ├── Dockerfile ├── README.md └── LICENSE /report/report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/report/report.pdf -------------------------------------------------------------------------------- /assignment/image/read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/assignment/image/read.png -------------------------------------------------------------------------------- /report/figure/figure.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/report/figure/figure.pptx -------------------------------------------------------------------------------- /assignment/image/write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/assignment/image/write.png -------------------------------------------------------------------------------- /assignment/image/paxos_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/assignment/image/paxos_test.png -------------------------------------------------------------------------------- /report/figure/result/paxos/consensus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/report/figure/result/paxos/consensus.png -------------------------------------------------------------------------------- /report/figure/result/paxos/educoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/report/figure/result/paxos/educoder.png -------------------------------------------------------------------------------- /report/figure/result/paxos/proposer0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/report/figure/result/paxos/proposer0.png -------------------------------------------------------------------------------- /report/figure/result/write_through/educoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktu2/ads/HEAD/report/figure/result/write_through/educoder.png -------------------------------------------------------------------------------- /assignment/paxos/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd Paxos 4 | 5 | make clean >/dev/null 6 | make 2>&1 >/dev/null 7 | 8 | cd bin 9 | 10 | rm -rf /root/out.txt 11 | 12 | ./Paxos_Test > /root/out.txt 13 | 14 | yy=$(tail -n 2 /root/out.txt | awk '{print $7$8}') 15 | 16 | echo $yy 17 | -------------------------------------------------------------------------------- /report/figure/result/paxos/log/Proposer4/2023-02-05.log: -------------------------------------------------------------------------------- 1 | 2023-02-05 11:09:33 Tid:67 [Info] Proposer4号开始(Propose阶段):提议=[编号:5, 提议:5] 2 | 3 | 2023-02-05 11:09:36 Tid:67 [Info] Proposer4号开始(Accept阶段):提议=[编号:5, 提议:5] 4 | 5 | 2023-02-05 11:09:38 Tid:67 [Info] Proposer4号的提议被批准,用时4945MS:最终提议 = [编号:5, 提议:5] 6 | 7 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/Paxos/PaxosData.h: -------------------------------------------------------------------------------- 1 | #ifndef PAXOS_DATA_H 2 | #define PAXOS_DATA_H 3 | 4 | namespace paxos 5 | { 6 | //提议数据结构 7 | typedef struct PROPOSAL 8 | { 9 | unsigned int serialNum;//流水号,1开始递增,保证全局唯一 10 | unsigned int value;//提议内容 11 | }PROPOSAL; 12 | } 13 | 14 | #endif //PAXOS_DATA_H -------------------------------------------------------------------------------- /assignment/write_through/README.md: -------------------------------------------------------------------------------- 1 | # 写穿算法测试 2 | 3 | `python test_main.py` 4 | 5 | 进入命令行交互输入 6 | 7 | **测试输入样例:** 8 | 9 | ```shell 10 | 5 2 11 | write 0 0 10 12 | read 0 0 13 | read 1 0 14 | write 1 0 5 15 | read 0 0 16 | ``` 17 | 18 | **预期输出:** 19 | 20 | ```shell 21 | 10 22 | 10 23 | 5 24 | ``` 25 | -------------------------------------------------------------------------------- /assignment/write_through/sim_file.py: -------------------------------------------------------------------------------- 1 | class sim_file: 2 | def __init__(self,file_name, data, version = 0): 3 | self._file_name = file_name 4 | self._data = data 5 | self._version = version 6 | 7 | def write_data(self,data,version): 8 | self._data = data 9 | self._version = version 10 | 11 | def get_data(self): 12 | return self._file_name ,self._data,self._version 13 | 14 | def get_versoin(self): 15 | return self._version 16 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/Paxos/Acceptor.h: -------------------------------------------------------------------------------- 1 | #ifndef ACCTPTOR_H 2 | #define ACCTPTOR_H 3 | 4 | #include "PaxosData.h" 5 | namespace paxos 6 | { 7 | 8 | //投票者 9 | class Acceptor 10 | { 11 | public: 12 | Acceptor(void); 13 | virtual ~Acceptor(void); 14 | 15 | //同意投票 16 | bool Propose(unsigned int serialNum, PROPOSAL &lastAcceptValue); 17 | //接受提议 18 | bool Accept(PROPOSAL &value); 19 | 20 | private: 21 | PROPOSAL m_lastAcceptValue;//最后接受的提议 22 | unsigned int m_maxSerialNum;//Propose提交的最大流水号 23 | }; 24 | 25 | } 26 | 27 | #endif //ACCTPTOR_H -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Pull base image 2 | FROM ubuntu:18.04 3 | 4 | # Author 5 | LABEL author="cs.thinktu@gmail.com" 6 | 7 | # Workdir 8 | WORKDIR /root/ads 9 | 10 | # Initialize custom image 11 | RUN sed -i 's#archive.ubuntu.com#mirrors.ustc.edu.cn#g' /etc/apt/sources.list \ 12 | # Update software source 13 | && apt-get update && apt-get upgrade -y \ 14 | # Install softwares 15 | && apt-get install build-essential make python3.8 -y \ 16 | # Establish a soft connection 17 | && ln -s /usr/bin/python3.8 /usr/bin/python && ln -s /usr/bin/python3.8 /usr/bin/python3 18 | 19 | # Copy all files to root 20 | COPY ./assignment /root/ads -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/atom.h: -------------------------------------------------------------------------------- 1 | #ifndef MDK_ATOM_H 2 | #define MDK_ATOM_H 3 | 4 | #include "FixLengthInt.h" 5 | 6 | #ifdef WIN32 7 | //为了不include 8 | #endif 9 | 10 | namespace mdk 11 | { 12 | 13 | //自增,返回新值 14 | uint32 AtomSelfAdd(void * var); 15 | 16 | //自减,返回新值 17 | uint32 AtomSelfDec(void * var); 18 | 19 | //加一个值,返回旧值 20 | uint32 AtomAdd(void * var, const uint32 value); 21 | 22 | //减一个值,返回旧值 23 | uint32 AtomDec(void * var, int32 value); 24 | 25 | //赋值,windows下返回新值,linux下返回旧值 26 | uint32 AtomSet(void * var, const uint32 value); 27 | 28 | //取值 29 | uint32 AtomGet(void * var); 30 | 31 | } //namespace mdk 32 | 33 | #endif //MDK_ATOM_H 34 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/FixLengthInt.h: -------------------------------------------------------------------------------- 1 | // Copyright [2012] 2 | 3 | #ifndef MDK_FIXLENGTHINT_H 4 | #define MDK_FIXLENGTHINT_H 5 | 6 | #ifndef WIN32 7 | #include 8 | #else 9 | #pragma warning(disable:4996) 10 | #endif 11 | 12 | 13 | namespace mdk 14 | { 15 | 16 | typedef char int8; 17 | typedef unsigned char uint8; 18 | typedef short int16; 19 | typedef unsigned short uint16; 20 | typedef int int32; 21 | typedef unsigned int uint32; 22 | #ifdef WIN32 23 | typedef __int64 int64; 24 | typedef unsigned __int64 uint64; 25 | #else 26 | #include 27 | typedef int64_t int64; 28 | typedef u_int64_t uint64; 29 | #endif 30 | 31 | }//namespace mdk 32 | 33 | #endif // MDK_FIXLENGTHINT_H 34 | -------------------------------------------------------------------------------- /assignment/write_through/test_main.py: -------------------------------------------------------------------------------- 1 | # import os 2 | # import random 3 | from sim_file import sim_file 4 | from server import sim_server 5 | from cache import sim_cache 6 | 7 | 8 | if __name__ == "__main__": 9 | number = input() 10 | number = number.split() 11 | op_number = int(number[0]) 12 | client_number = int(number[1]) 13 | 14 | server = sim_server() 15 | client_list = [] 16 | for i in range(client_number): 17 | temp_cache = sim_cache(server) 18 | client_list.append(temp_cache) 19 | 20 | for i in range(op_number): 21 | op = input() 22 | op = op.split() 23 | if op[0] == 'read' : 24 | print(client_list[int(op[1])].read(op[2])) 25 | else: 26 | client_list[int(op[1])].write(op[2],op[3]) 27 | 28 | -------------------------------------------------------------------------------- /assignment/write_through/server.py: -------------------------------------------------------------------------------- 1 | from sim_file import sim_file 2 | 3 | class sim_server: 4 | def __init__(self): 5 | self._server_file = {} 6 | 7 | def _search_server(self,file_name): 8 | return file_name in self._server_file 9 | 10 | def get_version(self, file_name): 11 | _,_,version = self.read(file_name) 12 | return version 13 | 14 | def write(self,file_name,data,version): 15 | if self._search_server(file_name): 16 | self._server_file[file_name].write_data(data,version) 17 | else: 18 | self._server_file[file_name] = sim_file(file_name,data,version) 19 | 20 | def read(self,file_name): 21 | if self._search_server(file_name): 22 | return self._server_file[file_name].get_data() 23 | else: 24 | return None 25 | -------------------------------------------------------------------------------- /report/figure/result/paxos/log/Paxos/2023-02-05.log: -------------------------------------------------------------------------------- 1 | 2023-02-05 11:09:33 Tid:62 [Info] 5个Proposer, 11个Acceptor准备进行Paxos 2 | 每个Proposer独立线程, Acceptor不需要线程 3 | Proposer编号从0-10,编号为i的Proposer初始提议编号和提议值是 (i+1, i+1) 4 | Proposer每次重新提议会将提议编号增加5 5 | Proposer被批准后结束线程,其它线程继续投票最终, 全部批准相同的值, 达成一致。 6 | 7 | 2023-02-05 11:09:33 Tid:62 [Info] Paxos开始 8 | 9 | 2023-02-05 11:09:38 Tid:67 [Info] Proposer4号的提议被批准,用时4945MS:最终提议 = [编号:5, 提议:5] 10 | 11 | 2023-02-05 11:09:55 Tid:64 [Info] Proposer1号的提议被批准,用时21842MS:最终提议 = [编号:17, 提议:5] 12 | 13 | 2023-02-05 11:10:01 Tid:63 [Info] Proposer0号的提议被批准,用时27817MS:最终提议 = [编号:21, 提议:5] 14 | 15 | 2023-02-05 11:10:06 Tid:66 [Info] Proposer3号的提议被批准,用时33494MS:最终提议 = [编号:24, 提议:5] 16 | 17 | 2023-02-05 11:10:10 Tid:65 [Info] Proposer2号的提议被批准,用时37424MS:最终提议 = [编号:28, 提议:5] 18 | 19 | 2023-02-05 11:10:10 Tid:65 [Info] Paxos完成, 用时37425MS, 最终通过提议值为: 5 20 | 21 | -------------------------------------------------------------------------------- /report/figure/result/paxos/log/Proposer0/2023-02-05.log: -------------------------------------------------------------------------------- 1 | 2023-02-05 11:09:33 Tid:63 [Info] Proposer0号开始(Propose阶段):提议=[编号:1, 提议:1] 2 | 3 | 2023-02-05 11:09:37 Tid:63 [Info] Proposer0号开始(Accept阶段):提议=[编号:1, 提议:1] 4 | 5 | 2023-02-05 11:09:39 Tid:63 [Info] Proposer0号开始(Propose阶段):提议=[编号:6, 提议:1] 6 | 7 | 2023-02-05 11:09:43 Tid:63 [Info] Proposer0号开始(Propose阶段):提议=[编号:11, 提议:1] 8 | 9 | 2023-02-05 11:09:44 Tid:63 [Info] Proposer0号修改了提议:提议=[编号:11, 提议:5] 10 | 11 | 2023-02-05 11:09:44 Tid:63 [Info] Proposer0号开始(Propose阶段):提议=[编号:11, 提议:5] 12 | 13 | 2023-02-05 11:09:49 Tid:63 [Info] Proposer0号开始(Accept阶段):提议=[编号:11, 提议:5] 14 | 15 | 2023-02-05 11:09:50 Tid:63 [Info] Proposer0号开始(Propose阶段):提议=[编号:16, 提议:5] 16 | 17 | 2023-02-05 11:09:55 Tid:63 [Info] Proposer0号开始(Accept阶段):提议=[编号:16, 提议:5] 18 | 19 | 2023-02-05 11:09:56 Tid:63 [Info] Proposer0号开始(Propose阶段):提议=[编号:21, 提议:5] 20 | 21 | 2023-02-05 11:10:00 Tid:63 [Info] Proposer0号开始(Accept阶段):提议=[编号:21, 提议:5] 22 | 23 | 2023-02-05 11:10:01 Tid:63 [Info] Proposer0号的提议被批准,用时27817MS:最终提议 = [编号:21, 提议:5] 24 | 25 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Task.cpp: -------------------------------------------------------------------------------- 1 | #include "Task.h" 2 | 3 | namespace mdk 4 | { 5 | Task::Task() 6 | { 7 | m_pParam = NULL; 8 | m_method = 0; 9 | m_pObj = NULL; 10 | m_fun = NULL; 11 | } 12 | 13 | Task::Task(int i) 14 | { 15 | m_method = i; 16 | } 17 | 18 | Task::~Task() 19 | { 20 | if ( 0 != m_method ) 21 | { 22 | m_method = 0; 23 | } 24 | } 25 | 26 | //接受任务 27 | //method为声明为void* fun(void*)的成员函数 28 | void Task::Accept( MethodPointer method, void *pObj, void *pParam ) 29 | { 30 | m_pParam = pParam; 31 | m_method = method; 32 | m_pObj = pObj; 33 | m_fun = NULL; 34 | } 35 | 36 | //接受任务 37 | //method为声明为void* fun(void*)的函数 38 | void Task::Accept( FuntionPointer fun, void *pParam ) 39 | { 40 | m_pParam = pParam; 41 | m_method = 0; 42 | m_pObj = NULL; 43 | m_fun = fun; 44 | } 45 | 46 | //执行任务 47 | void* Task::Execute() 48 | { 49 | if ( NULL == m_pObj && NULL == m_fun ) return NULL; 50 | if ( NULL == m_pObj ) 51 | { 52 | return m_fun(m_pParam); 53 | } 54 | else 55 | { 56 | return Executor::CallMethod(m_method, m_pObj, m_pParam); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Task.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOL_C_TASK_H 2 | #define TOOL_C_TASK_H 3 | 4 | #include "Executor.h" 5 | 6 | /** 7 | 任务类 8 | 使用方法 9 | void* g_fun(void*) 10 | { 11 | return NULL; 12 | } 13 | class A 14 | { 15 | ... 16 | void* RemoteCall fun(void*); 17 | } 18 | A a; 19 | 20 | mdk::Task t; 21 | //linux下必须&A::fun,windows下可使用A::fun 22 | //为了移植性,建议传递&A::fun给Bind() 23 | t.Accept( mdk::Executor::Bind(&A::fun), &a, (void*)param ); 24 | t.Execute(); 25 | 26 | t.Accept( g_fun, (void*)param ); 27 | t.Execute(); 28 | */ 29 | 30 | namespace mdk 31 | { 32 | class Task 33 | { 34 | public: 35 | Task(int i); 36 | Task(); 37 | virtual ~Task(); 38 | //接受任务 39 | //method为声明为void* fun(void*)的成员函数 40 | void Accept( MethodPointer method, void *pObj, void *pParam ); 41 | //接受任务 42 | //fun为声明为void* fun(void*)的函数 43 | void Accept( FuntionPointer fun, void *pParam ); 44 | //执行任务 45 | void* Execute(); 46 | 47 | private: 48 | void *m_pParam; 49 | MethodPointer m_method; 50 | void *m_pObj; 51 | FuntionPointer m_fun; 52 | }; 53 | 54 | }//namespace mdk 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Lock.h: -------------------------------------------------------------------------------- 1 | // Lock.h: interface for the Thread class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #ifndef MDK_LOCK_H 6 | #define MDK_LOCK_H 7 | 8 | #ifdef WIN32 9 | #else 10 | #include 11 | #endif 12 | 13 | namespace mdk 14 | { 15 | 16 | #ifdef WIN32 17 | //为了不包含windows.h,定义一个绝对大于CRITICAL_SECTION的buffer 18 | typedef struct CS_BUFFER 19 | { 20 | char buffer[64]; 21 | }CS_BUFFER; 22 | #define OriginalMutex CS_BUFFER 23 | #else 24 | typedef pthread_mutex_t OriginalMutex;//互斥锁 25 | #endif 26 | 27 | //自解锁封装,推荐使用自解锁进行锁操作,避免异常,忘记解锁等不完全的锁操作发生 28 | class Mutex; 29 | class AutoLock 30 | { 31 | public: 32 | AutoLock( Mutex *pLock ); 33 | ~AutoLock(); 34 | void Unlock(); 35 | 36 | private: 37 | Mutex *m_pMutex; 38 | bool m_bLocked; 39 | }; 40 | 41 | //锁基本操作封装 42 | class Mutex 43 | { 44 | private: 45 | //互斥锁系统对象 46 | OriginalMutex m_mutex; 47 | public: 48 | Mutex(); 49 | ~Mutex(); 50 | //加锁 51 | void Lock(); 52 | //解锁 53 | void Unlock(); 54 | }; 55 | 56 | }//namespace mdk 57 | 58 | #endif//MDK_LOCK_H 59 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/Paxos/Acceptor.cpp: -------------------------------------------------------------------------------- 1 | #include "Acceptor.h" 2 | 3 | 4 | namespace paxos 5 | { 6 | 7 | 8 | Acceptor::Acceptor(void) 9 | { 10 | m_maxSerialNum = 0; 11 | m_lastAcceptValue.serialNum = 0; 12 | m_lastAcceptValue.value = 0; 13 | } 14 | 15 | Acceptor::~Acceptor(void) 16 | { 17 | } 18 | 19 | bool Acceptor::Propose(unsigned int serialNum, PROPOSAL &lastAcceptValue) 20 | { 21 | if ( 0 == serialNum ) return false; 22 | //提议不通过 23 | if ( m_maxSerialNum > serialNum ) return false; 24 | //接受提议 25 | //请完善下面逻辑 26 | 27 | /**********Begin**********/ 28 | m_maxSerialNum = serialNum; 29 | lastAcceptValue = m_lastAcceptValue; 30 | /**********End**********/ 31 | 32 | return true; 33 | } 34 | 35 | bool Acceptor::Accept(PROPOSAL &value) 36 | { 37 | if ( 0 == value.serialNum ) return false; 38 | //Acceptor又重新答应了其他提议 39 | //请完善下面逻辑 40 | /**********Begin**********/ 41 | if (m_maxSerialNum > value.serialNum) return false; 42 | /**********End**********/ 43 | 44 | 45 | //批准提议通过 46 | //请完善下面逻辑 47 | /**********Begin**********/ 48 | m_lastAcceptValue = value; 49 | /**********End**********/ 50 | 51 | return true; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 高级分布式系统线上作业题 2 | 3 | 作业在头歌([educoder](https://www.educoder.net/))平台完成, 这里是个人兴趣使然把题目扒下来, 使用 [Docker](https://docs.docker.com/engine/install/) 构建本地的运行测试环境。 4 | 5 | 本次作业一共有两个题目, 第一个是实现 **Paxos** 算法, 第二个实现分布式缓存一致性的 **写穿** 算法。 6 | 7 | ## 一些说明 8 | 9 | 1. 出于个人习惯, 对某些文件中的字符格式进行了修改, 不一定与线上测试平台匹配。提交线上作业检测时请复制 **所需的代码块**, 切勿全部复制!!! 10 | 2. 题目的描述详尽, 要求实现的代码逻辑较为简单。第一个题目在编译时存在一些 `警告`, 已在本仓库代码中进行修正, 但不影响答题的代码块; 第二个题目的设计和实现略显粗糙, 功能逻辑的实现不唯一。 11 | 3. 已更新代码和报告。 12 | 13 | ## 镜像 14 | 15 | 创建 16 | 17 | ```shell 18 | docker build -t ads:2022 . 19 | ``` 20 | 21 | `ads` 是高级分布式系统 (Advanced Distributed Systems) 的缩写, Tag 为 `2022` 年的线上作业 22 | 23 | 删除 24 | 25 | ```shell 26 | docker rmi ads:2022 27 | ``` 28 | 29 | ## 容器 30 | 31 | 启动 32 | 33 | ```shell 34 | docker run --name "ads2022" -di ads:2022 35 | ``` 36 | 37 | 连接 38 | 39 | ```shell 40 | docker exec -it ads2022 bash 41 | ``` 42 | 43 | 停止 44 | 45 | ```shell 46 | docker stop ads2022 47 | ``` 48 | 49 | 删除 50 | 51 | ```shell 52 | docker rm ads2022 53 | ``` 54 | 55 | ## 注意 56 | 57 | 工作目录为 `/root/ads` 58 | 59 | 在 `VSCode` 中, 可以使用 `Docker` 插件, 对容器进行 `Attach` 60 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/Paxos/Proposer.h: -------------------------------------------------------------------------------- 1 | #ifndef PROPOSER_H 2 | #define PROPOSER_H 3 | 4 | #include 5 | #include "PaxosData.h" 6 | 7 | namespace paxos 8 | { 9 | 10 | //提议者 11 | class Proposer 12 | { 13 | public: 14 | Proposer(); 15 | Proposer(short proposerCount, short acceptorCount); 16 | virtual ~Proposer(); 17 | //设置参与者数量 18 | void SetPlayerCount(short proposerCount, short acceptorCount); 19 | //开始Propose阶段 20 | void StartPropose(PROPOSAL &value); 21 | //取得提议 22 | PROPOSAL& GetProposal(); 23 | //提议被投票,Proposed失败则重新开始Propose阶段 24 | bool Proposed(bool ok, PROPOSAL &lastAcceptValue); 25 | //开始Accept阶段,满足条件成功开始accept阶段返回ture,不满足开始条件返回false 26 | bool StartAccept(); 27 | //提议被接受,Accepted失败则重新开始Propose阶段 28 | bool Accepted(bool ok); 29 | //提议被批准 30 | bool IsAgree(); 31 | 32 | private: 33 | short m_proposerCount;///proposer数量 34 | short m_acceptorCount;//acceptor数量 35 | PROPOSAL m_value;//预备提议 36 | bool m_proposeFinished;//完成拉票,准备开始二阶段 37 | bool m_isAgree;//m_value被批准 38 | unsigned int m_maxAcceptedSerialNum;//已被接受的提议中流水号最大的 39 | time_t m_start;//阶段开始时间,阶段一,阶段二共用 40 | short m_okCount;//投票数量,阶段一,阶段二共用 41 | short m_refuseCount;//拒绝数量,阶段一,阶段二共用 42 | }; 43 | 44 | } 45 | 46 | #endif //PROPOSER_H -------------------------------------------------------------------------------- /assignment/paxos/Paxos/Makefile: -------------------------------------------------------------------------------- 1 | DIR_SRC = ./src 2 | DIR_OBJ = ./obj 3 | DIR_BIN = ./bin 4 | 5 | SRC = $(wildcard ${DIR_SRC}/*.cpp) $(wildcard ${DIR_SRC}/lib/*.cpp) $(wildcard ${DIR_SRC}/Paxos/*.cpp) 6 | OBJ = $(patsubst %.cpp,${DIR_OBJ}/%.o,$(notdir ${SRC})) 7 | 8 | TARGET = Paxos_Test 9 | 10 | BIN_TARGET = ${DIR_BIN}/${TARGET} 11 | 12 | CC = g++ 13 | CFLAGS = -lpthread -lrt 14 | 15 | ${BIN_TARGET}:${OBJ} 16 | $(CC) $(OBJ) $(CFLAGS) -o $@ 17 | 18 | ${DIR_OBJ}/Paxos.o:${DIR_SRC}/Paxos.cpp 19 | $(CC) -c $^ -o $@ 20 | 21 | ${DIR_OBJ}/atom.o:${DIR_SRC}/lib/atom.cpp 22 | $(CC) -c $^ -o $@ 23 | ${DIR_OBJ}/Executor.o:${DIR_SRC}/lib/Executor.cpp 24 | $(CC) -c $^ -o $@ 25 | ${DIR_OBJ}/Lock.o:${DIR_SRC}/lib/Lock.cpp 26 | $(CC) -c $^ -o $@ 27 | ${DIR_OBJ}/Logger.o:${DIR_SRC}/lib/Logger.cpp 28 | $(CC) -c $^ -o $@ 29 | ${DIR_OBJ}/mapi.o:${DIR_SRC}/lib/mapi.cpp 30 | $(CC) -c $^ -o $@ 31 | ${DIR_OBJ}/Task.o:${DIR_SRC}/lib/Task.cpp 32 | $(CC) -c $^ -o $@ 33 | ${DIR_OBJ}/Thread.o:${DIR_SRC}/lib/Thread.cpp 34 | $(CC) -c $^ -o $@ 35 | 36 | ${DIR_OBJ}/Acceptor.o:${DIR_SRC}/Paxos/Acceptor.cpp 37 | $(CC) -c $^ -o $@ 38 | ${DIR_OBJ}/Proposer.o:${DIR_SRC}/Paxos/Proposer.cpp 39 | $(CC) -c $^ -o $@ 40 | 41 | .PHONY:clean 42 | clean: 43 | rm -rf ${DIR_OBJ}/*.o 44 | rm -rf ${DIR_BIN}/* 45 | -------------------------------------------------------------------------------- /report/figure/result/paxos/log/Proposer1/2023-02-05.log: -------------------------------------------------------------------------------- 1 | 2023-02-05 11:09:33 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:2, 提议:2] 2 | 3 | 2023-02-05 11:09:38 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:7, 提议:2] 4 | 5 | 2023-02-05 11:09:38 Tid:64 [Info] Proposer1号修改了提议:提议=[编号:7, 提议:5] 6 | 7 | 2023-02-05 11:09:38 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:7, 提议:5] 8 | 9 | 2023-02-05 11:09:42 Tid:64 [Info] Proposer1号开始(Accept阶段):提议=[编号:7, 提议:5] 10 | 11 | 2023-02-05 11:09:44 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:12, 提议:5] 12 | 13 | 2023-02-05 11:09:47 Tid:64 [Info] Proposer1号开始(Accept阶段):提议=[编号:12, 提议:5] 14 | 15 | 2023-02-05 11:09:48 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:12, 提议:5] 16 | 17 | 2023-02-05 11:09:48 Tid:64 [Info] Proposer1号开始(Accept阶段):提议=[编号:12, 提议:5] 18 | 19 | 2023-02-05 11:09:48 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:12, 提议:5] 20 | 21 | 2023-02-05 11:09:49 Tid:64 [Info] Proposer1号开始(Accept阶段):提议=[编号:12, 提议:5] 22 | 23 | 2023-02-05 11:09:49 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:12, 提议:5] 24 | 25 | 2023-02-05 11:09:50 Tid:64 [Info] Proposer1号开始(Accept阶段):提议=[编号:12, 提议:5] 26 | 27 | 2023-02-05 11:09:51 Tid:64 [Info] Proposer1号开始(Propose阶段):提议=[编号:17, 提议:5] 28 | 29 | 2023-02-05 11:09:53 Tid:64 [Info] Proposer1号开始(Accept阶段):提议=[编号:17, 提议:5] 30 | 31 | 2023-02-05 11:09:55 Tid:64 [Info] Proposer1号的提议被批准,用时21842MS:最终提议 = [编号:17, 提议:5] 32 | 33 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Executor.cpp: -------------------------------------------------------------------------------- 1 | // Executor.cpp: implementation of the Executor class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #include "Executor.h" 6 | 7 | namespace mdk 8 | { 9 | 10 | //__thiscall调用方式成员函数,做线程函数,指针定义 11 | typedef void* (__stdcall *ThisCallFun)(void*); 12 | //__stdcall调用方式成员函数,做线程函数,指针定义 13 | typedef void*(__stdcall *StdCallFun)(void*, void*); 14 | 15 | //执行声明为void* fun(void*)的成员函数 16 | void* WinCall( MethodPointer uMethod, void *pObj, void *pParam ) 17 | { 18 | ThisCallFun method = (ThisCallFun)uMethod; 19 | unsigned long This = (unsigned long)pObj; 20 | #ifdef WIN32 21 | __asm //准备this指针. 22 | { 23 | mov ecx, This; 24 | } 25 | #else//linux下汇编调用暂未实现 26 | return NULL; 27 | #endif 28 | return method(pParam); 29 | } 30 | 31 | //执行声明为void* _stdcall fun(void*)的成员函数 32 | void* LinuxCall( MethodPointer uMethod, void *pObj, void *pParam ) 33 | { 34 | StdCallFun method = (StdCallFun)uMethod; 35 | return method(pObj, pParam); 36 | } 37 | 38 | Executor::Executor() 39 | { 40 | } 41 | 42 | Executor::~Executor() 43 | { 44 | } 45 | 46 | //执行声明为void* fun(void*)的成员函数 47 | void* Executor::CallMethod( MethodPointer method, void *pObj, void *pParam ) 48 | { 49 | #ifdef WIN32 50 | return LinuxCall( method, pObj, pParam ); 51 | #else 52 | return LinuxCall( method, pObj, pParam ); 53 | #endif 54 | } 55 | 56 | 57 | }//namespace mdk 58 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Executor.h: -------------------------------------------------------------------------------- 1 | // Executor.h: interface for the Executor class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | /* 5 | 执行器类 6 | 用于执行对象内声明为void* RemoteCall fun(void*)的成员函数 7 | ※fun不能是虚函数 8 | 9 | 使用方法 10 | class A 11 | { 12 | ... 13 | void* RemoteCall fun(void*); 14 | } 15 | A a; 16 | //linux下必须&A::fun,windows下可使用A::fun,A类函数内部直接fun皆可 17 | //为了移植性,建议传递&A::fun给Bind() 18 | mdk::Executor::CallMethod( mdk::Executor::Bind(&A::fun), &a, (void*)param ); 19 | 20 | */ 21 | #ifndef MDK_EXECUTOR_H 22 | #define MDK_EXECUTOR_H 23 | 24 | #include "FixLengthInt.h" 25 | #ifndef NULL 26 | #define NULL 0 27 | #endif 28 | 29 | #ifndef WIN32 30 | #define __stdcall 31 | #endif 32 | #define RemoteCall __stdcall 33 | 34 | namespace mdk 35 | { 36 | typedef void* (*pfun)(void*); 37 | typedef pfun FuntionPointer; 38 | typedef uint64 MethodPointer; 39 | 40 | class Executor 41 | { 42 | public: 43 | Executor(); 44 | virtual ~Executor(); 45 | 46 | //成员函数指针地址 47 | //※f不能是虚函数 48 | template 49 | static MethodPointer Bind( FromType f ) 50 | { 51 | union 52 | { 53 | FromType _f; 54 | MethodPointer _t; 55 | }ut; 56 | 57 | ut._f = f; 58 | return ut._t; 59 | } 60 | 61 | //执行声明为void* fun(void*)的成员函数 62 | static void* CallMethod( MethodPointer method, void *pObj, void *pParam ); 63 | }; 64 | 65 | }//namespace mdk 66 | 67 | #endif // MDK_EXECUTOR_H 68 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/mapi.h: -------------------------------------------------------------------------------- 1 | // mapi.h: interface for the mapi class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #ifndef MDK_MAPI_H 6 | #define MDK_MAPI_H 7 | 8 | #include 9 | #include "FixLengthInt.h" 10 | 11 | namespace mdk 12 | { 13 | //断言 14 | void mdk_assert( bool isTrue ); 15 | //睡眠 16 | void m_sleep( long lMillSecond ); 17 | //地址保存到int64 18 | bool addrToI64(uint64 &addr64, const char* ip, int port); 19 | //int64解析出地址 20 | void i64ToAddr(char* ip, int &port, uint64 addr64); 21 | //压缩del包含的字符 22 | void TrimString( std::string &str, std::string del ); 23 | //压缩右del包含的字符 24 | void TrimStringLeft( std::string &str, std::string del ); 25 | //压缩左del包含的字符 26 | void TrimStringRight( std::string &str, std::string del ); 27 | //压缩空白字符 28 | char* Trim( char *str ); 29 | //压缩右空白字符 30 | char* TrimRight( char *str ); 31 | //压缩左空白字符 32 | char* TrimLeft( char *str ); 33 | //字节高低位顺序翻转 34 | int reversal(int i); 35 | //取得文件大小 36 | unsigned long GetFileSize(const char *filename); 37 | //获取CPU数量 38 | //maxCpu可能的最大cpu数,如果检测出cpu数量大于此值,则表示检测有误,将返回defaultCpuNumber 39 | //defaultCpuNumber默认cpu数量,当检测出错时,将认为cpu数量为此值 40 | unsigned int GetCUPNumber( int maxCpu, int defaultCpuNumber ); 41 | uint64 CurThreadId();//当前线程id 42 | time_t mdk_Date();//返回0时0分0秒的当前日期 43 | bool GetExeDir( char *exeDir, int size );//取得可执行程序位置 44 | mdk::uint64 MillTime();//毫秒级当前时间 45 | } 46 | 47 | #endif // !defined MDK_MAPI_H 48 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/atom.cpp: -------------------------------------------------------------------------------- 1 | #include "atom.h" 2 | 3 | #ifdef WIN32 4 | #include 5 | #endif 6 | 7 | namespace mdk 8 | { 9 | 10 | //自增,返回新值 11 | uint32 AtomSelfAdd(void * var) 12 | { 13 | #ifdef WIN32 14 | return InterlockedIncrement((long *)(var)); // NOLINT 15 | #else 16 | return __sync_add_and_fetch((uint32 *)(var), 1); // NOLINT 17 | #endif 18 | } 19 | 20 | //自减,返回新值 21 | uint32 AtomSelfDec(void * var) 22 | { 23 | #ifdef WIN32 24 | return InterlockedDecrement((long *)(var)); // NOLINT 25 | #else 26 | return __sync_add_and_fetch((uint32 *)(var), -1); // NOLINT 27 | #endif 28 | } 29 | 30 | //加一个值,返回旧值 31 | uint32 AtomAdd(void * var, const uint32 value) 32 | { 33 | #ifdef WIN32 34 | return InterlockedExchangeAdd((long *)(var), value); // NOLINT 35 | #else 36 | return __sync_fetch_and_add((uint32 *)(var), value); // NOLINT 37 | #endif 38 | } 39 | 40 | //减一个值,返回旧值 41 | uint32 AtomDec(void * var, int32 value) 42 | { 43 | value = value * -1; 44 | #ifdef WIN32 45 | return InterlockedExchangeAdd((long *)(var), value); // NOLINT 46 | #else 47 | return __sync_fetch_and_add((uint32 *)(var), value); // NOLINT 48 | #endif 49 | } 50 | 51 | //赋值,windows下返回新值,linux下返回旧值 52 | uint32 AtomSet(void * var, const uint32 value) 53 | { 54 | #ifdef WIN32 55 | ::InterlockedExchange((long *)(var), (long)(value)); // NOLINT 56 | #else 57 | __sync_lock_test_and_set((uint32 *)(var), value); // NOLINT 58 | #endif 59 | return value; 60 | } 61 | 62 | //取值 63 | uint32 AtomGet(void * var) 64 | { 65 | #ifdef WIN32 66 | return InterlockedExchangeAdd((long *)(var), 0); // NOLINT 67 | #else 68 | return __sync_fetch_and_add((uint32 *)(var), 0); // NOLINT 69 | #endif 70 | } 71 | 72 | } //namespace mdk 73 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Lock.cpp: -------------------------------------------------------------------------------- 1 | // Lock.cpp: implementation of the Thread class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | #include "Lock.h" 5 | #ifdef WIN32 6 | #include 7 | #endif 8 | 9 | namespace mdk 10 | { 11 | 12 | ////////////////////////////////////////////////////////////////////////// 13 | //实现 14 | AutoLock::AutoLock( Mutex *pLock ) 15 | :m_pMutex(pLock), m_bLocked(true) 16 | { 17 | m_pMutex->Lock(); 18 | } 19 | AutoLock::~AutoLock() 20 | { 21 | Unlock(); 22 | } 23 | 24 | void AutoLock::Unlock() 25 | { 26 | if ( m_bLocked ) 27 | { 28 | m_pMutex->Unlock(); 29 | m_bLocked = false; 30 | } 31 | } 32 | 33 | Mutex::Mutex() 34 | { 35 | #ifdef WIN32 36 | InitializeCriticalSection( (CRITICAL_SECTION*)&m_mutex ); 37 | #else 38 | int kind = PTHREAD_MUTEX_RECURSIVE_NP; 39 | pthread_mutexattr_t mutexattr;//互斥量属性 40 | 41 | int nError = 0; 42 | if ( 0 != (nError = pthread_mutexattr_init( &mutexattr )) ) return; 43 | if ( 0 != (nError = pthread_mutexattr_settype( &mutexattr, kind )) ) return; 44 | if ( 0 != (nError = pthread_mutex_init( &m_mutex, &mutexattr )) ) return; 45 | if ( 0 != (nError = pthread_mutexattr_destroy( &mutexattr )) ) return; 46 | #endif 47 | } 48 | 49 | Mutex::~Mutex() 50 | { 51 | #ifdef WIN32 52 | DeleteCriticalSection( (CRITICAL_SECTION*)&m_mutex ); 53 | #else 54 | pthread_mutex_destroy( &m_mutex ); 55 | #endif 56 | } 57 | 58 | void Mutex::Lock() 59 | { 60 | #ifdef WIN32 61 | EnterCriticalSection( (CRITICAL_SECTION*)&m_mutex ); 62 | #else 63 | pthread_mutex_lock( &m_mutex ); 64 | #endif 65 | } 66 | 67 | void Mutex::Unlock() 68 | { 69 | #ifdef WIN32 70 | LeaveCriticalSection( (CRITICAL_SECTION*)&m_mutex ); 71 | #else 72 | pthread_mutex_unlock( &m_mutex ); 73 | #endif 74 | } 75 | 76 | }//namespace mdk 77 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Logger.h: -------------------------------------------------------------------------------- 1 | // Logger.h: interface for the Logger class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #ifndef MDK_LOGGER_H 6 | #define MDK_LOGGER_H 7 | 8 | #include 9 | #include 10 | #include "Lock.h" 11 | 12 | namespace mdk 13 | { 14 | 15 | class Logger 16 | { 17 | public: 18 | Logger(); 19 | Logger(const char *name); 20 | virtual ~Logger(); 21 | 22 | public: 23 | //设置日志名,日志将被保存到"log/名字/"下目录下 24 | //只能设置1次,以后都将失败 25 | //如果构造函数已经传递了日志名,则此方法不能再设置 26 | bool SetLogName( const char *name ); 27 | void SetPrintLog( bool bPrint );//写日志时,是否同时打印到控制台 28 | bool Info( const char *findKey, const char *format, ... );//输出信息,输出格式为 时间+空格+(findKey)+空格+(Tid:线程ID)+空格+参数传入信息 29 | bool StreamInfo( const char *findKey, unsigned char *stream, int nLen, const char *format, ... );//输出带数据流的日至信息, stream数据将接在format信息之后输出,以stream:为标记 30 | void SetMaxLogSize( int maxLogSize );//设置单个日志文件最大尺寸,单位M 31 | void SetMaxExistDay( int maxExistDay );//设置日志文件最大保留天数,比如设置为30则,最多保存最近30天的日志 32 | //删除nDay天前的日志 33 | void DelLog( int nDay ); 34 | private: 35 | bool OpenRunLog(); 36 | bool CreateLogDir();//做初始化,只能调用1次 37 | bool CreateFreeDir(const char* dir);//创建自由(最大权限)目录 38 | void RenameMaxLog();//重名超大日志 39 | void FindDelLog(char * lpPath, int maxExistDay); 40 | 41 | private: 42 | bool m_isInit;//是否初始化 43 | bool m_bPrint;//输出日志时,是否同时打印到控制台 44 | Mutex m_writeMutex; 45 | bool m_bRLogOpened;//运行日志文件是否打开 46 | //运行日志当前日期 47 | short m_nRunLogCurYear; 48 | unsigned char m_nRunLogCurMonth; 49 | unsigned char m_nRunLogCurDay; 50 | FILE *m_fpRunLog;//日志文件指针 51 | std::string m_name;//日志名 52 | std::string m_runLogDir;//日志目录 53 | int m_maxLogSize;//日志文件最大尺寸 54 | int m_maxExistDay; 55 | int m_index;//日志编号 56 | char *m_exeDir; 57 | }; 58 | 59 | }//namespace mdk 60 | 61 | #endif // MDK_LOGGER_H 62 | -------------------------------------------------------------------------------- /report/figure/result/paxos/log/Proposer2/2023-02-05.log: -------------------------------------------------------------------------------- 1 | 2023-02-05 11:09:33 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:3, 提议:3] 2 | 3 | 2023-02-05 11:09:37 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:3, 提议:3] 4 | 5 | 2023-02-05 11:09:39 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:8, 提议:3] 6 | 7 | 2023-02-05 11:09:39 Tid:65 [Info] Proposer2号修改了提议:提议=[编号:8, 提议:5] 8 | 9 | 2023-02-05 11:09:39 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:8, 提议:5] 10 | 11 | 2023-02-05 11:09:43 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:8, 提议:5] 12 | 13 | 2023-02-05 11:09:44 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:13, 提议:5] 14 | 15 | 2023-02-05 11:09:49 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:13, 提议:5] 16 | 17 | 2023-02-05 11:09:50 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:13, 提议:5] 18 | 19 | 2023-02-05 11:09:51 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:13, 提议:5] 20 | 21 | 2023-02-05 11:09:51 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:13, 提议:5] 22 | 23 | 2023-02-05 11:09:52 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:13, 提议:5] 24 | 25 | 2023-02-05 11:09:52 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:13, 提议:5] 26 | 27 | 2023-02-05 11:09:53 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:13, 提议:5] 28 | 29 | 2023-02-05 11:09:54 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:18, 提议:5] 30 | 31 | 2023-02-05 11:09:57 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:18, 提议:5] 32 | 33 | 2023-02-05 11:09:59 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:18, 提议:5] 34 | 35 | 2023-02-05 11:09:59 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:18, 提议:5] 36 | 37 | 2023-02-05 11:10:00 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:23, 提议:5] 38 | 39 | 2023-02-05 11:10:04 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:23, 提议:5] 40 | 41 | 2023-02-05 11:10:06 Tid:65 [Info] Proposer2号开始(Propose阶段):提议=[编号:28, 提议:5] 42 | 43 | 2023-02-05 11:10:09 Tid:65 [Info] Proposer2号开始(Accept阶段):提议=[编号:28, 提议:5] 44 | 45 | 2023-02-05 11:10:10 Tid:65 [Info] Proposer2号的提议被批准,用时37424MS:最终提议 = [编号:28, 提议:5] 46 | 47 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Thread.h: -------------------------------------------------------------------------------- 1 | // Thread.h: interface for the Thread class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | /* 5 | 线程类 6 | ※fun不能是虚函数 7 | 8 | 使用方法 9 | void* g_fun(void*) 10 | { 11 | return NULL; 12 | } 13 | class A 14 | { 15 | ... 16 | void* RemoteCall fun(void*); 17 | } 18 | A a; 19 | 20 | mdk::Thread t; 21 | //linux下必须&A::fun,windows下可使用A::fun 22 | //为了移植性,建议传递&A::fun给Bind 23 | t.Run( mdk::Executor::Bind(&A::fun), &a, (void*)param ); 24 | mdk::Thread t2; 25 | t2.Run( g_fun, (void*)param ); 26 | */ 27 | #ifndef MDK_THREAD_H 28 | #define MDK_THREAD_H 29 | 30 | #include "FixLengthInt.h" 31 | #include "Task.h" 32 | 33 | #ifdef WIN32 34 | //为了不include 35 | typedef void *HANDLE; 36 | typedef unsigned long DWORD; 37 | #else 38 | #include 39 | #include 40 | #endif 41 | 42 | namespace mdk 43 | { 44 | 45 | #ifdef WIN32 46 | typedef DWORD ThreadID; 47 | #else 48 | typedef pthread_t ThreadID; 49 | #endif 50 | 51 | //简单线程类 52 | class Thread 53 | { 54 | public: 55 | Thread(); 56 | virtual ~Thread(); 57 | 58 | ////////////////////////////////////////////////////////////////////////// 59 | protected://属性 60 | ThreadID m_nID; 61 | Task m_task; 62 | bool m_bRun; 63 | 64 | //线程退出控制属性 65 | #ifdef WIN32 66 | HANDLE m_hHandle; 67 | #else 68 | pthread_cond_t m_exit; 69 | pthread_mutex_t m_exitMutex; 70 | bool m_bStop; 71 | #endif 72 | //End线程退出控制属性 73 | ////////////////////////////////////////////////////////////////////////// 74 | public://接口 75 | bool Run( MethodPointer method, void *pObj, void *pParam );//启动线程,使用类成员函数,pParam传递给线程函数的参数 76 | bool Run( FuntionPointer fun, void *pParam );//启动线程,使用全局函数,pParam传递给线程函数的参数 77 | /* 78 | 停止 79 | */ 80 | void Stop(long lMillSecond = 0); 81 | /* 82 | 等待线程停止 83 | 注:linux下一旦返回,之后再调用WaitStop()与Stop();将不再等待,直接返回 84 | 因为WaitStop();返回前会发送1次线程结束信号,通知其它可能存在等待的线程 85 | */ 86 | void WaitStop(); 87 | ThreadID GetID();//取得线程ID 88 | 89 | protected: 90 | bool Run( void *pParam );//启动线程,pParam传递给线程函数的参数 91 | static void* TMain(void*); 92 | void* Main(); 93 | }; 94 | 95 | }//namespace mdk 96 | 97 | #endif // MDK_THREAD_H 98 | -------------------------------------------------------------------------------- /assignment/paxos/README.md: -------------------------------------------------------------------------------- 1 | # Paxos 算法测试 2 | 3 | ## 编译与运行脚本 4 | 5 | ```shell 6 | bash run.sh 7 | ``` 8 | 9 | 全部输出内容在文件 `/root/out.txt` 中 10 | 11 | ## 修改 12 | 13 | 编译警告 14 | 15 | ```shell 16 | src/Paxos.cpp: In function 'void* Proposer(void*)': 17 | src/Paxos.cpp:24:43: warning: format '%d' expects argument of type 'int', but argument 3 has type 'long int' [-Wformat=] 18 | sprintf( logName, "Proposer%d", (long)id ); 19 | ~~~~~~~~ ^ 20 | src/Paxos.cpp: In function 'int main(int, char**)': 21 | src/Paxos.cpp:152:54: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 22 | for ( i = 0; i < 5; i++ ) t[i].Run(Proposer, (void*)i); 23 | ^ 24 | src/lib/Logger.cpp: In member function 'bool mdk::Logger::Info(const char*, const char*, ...)': 25 | src/lib/Logger.cpp:288:75: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'mdk::uint64 {aka long unsigned int}' [-Wformat=] 26 | fprintf(m_fpRunLog, "%s Tid:%llu [%s] ", strTime, CurThreadId(), findKey); 27 | ~~~~~~~~~~~~~ ^ 28 | src/lib/Logger.cpp:303:63: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'mdk::uint64 {aka long unsigned int}' [-Wformat=] 29 | printf("%s Tid:%llu [%s] ", strTime, CurThreadId(), findKey); 30 | ~~~~~~~~~~~~~ ^ 31 | src/lib/Logger.cpp: In member function 'bool mdk::Logger::StreamInfo(const char*, unsigned char*, int, const char*, ...)': 32 | src/lib/Logger.cpp:332:75: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 4 has type 'mdk::uint64 {aka long unsigned int}' [-Wformat=] 33 | fprintf(m_fpRunLog, "%s Tid:%llu [%s] ", strTime, CurThreadId(), findKey); 34 | ~~~~~~~~~~~~~ ^ 35 | src/lib/Logger.cpp:341:63: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 3 has type 'mdk::uint64 {aka long unsigned int}' [-Wformat=] 36 | printf("%s Tid:%llu [%s] ", strTime, CurThreadId(), findKey); 37 | ~~~~~~~~~~~~~ ^ 38 | ``` 39 | 40 | 1. `src/Paxos.cpp:24:43` 处, 将 `%d` 修改为 `%ld` 41 | 2. `src/Paxos.cpp:152:54` 处, 将 `i` 修改为 `long` 类型 42 | 3. `src/lib/Logger.cpp` 中的警告, 将 `%llu` 修改为 `%lu` 43 | -------------------------------------------------------------------------------- /report/figure/result/paxos/log/Proposer3/2023-02-05.log: -------------------------------------------------------------------------------- 1 | 2023-02-05 11:09:33 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:4, 提议:4] 2 | 3 | 2023-02-05 11:09:35 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:4, 提议:4] 4 | 5 | 2023-02-05 11:09:38 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:4] 6 | 7 | 2023-02-05 11:09:38 Tid:66 [Info] Proposer3号修改了提议:提议=[编号:9, 提议:5] 8 | 9 | 2023-02-05 11:09:38 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 10 | 11 | 2023-02-05 11:09:42 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 12 | 13 | 2023-02-05 11:09:43 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 14 | 15 | 2023-02-05 11:09:43 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 16 | 17 | 2023-02-05 11:09:44 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 18 | 19 | 2023-02-05 11:09:44 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 20 | 21 | 2023-02-05 11:09:45 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 22 | 23 | 2023-02-05 11:09:45 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 24 | 25 | 2023-02-05 11:09:45 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 26 | 27 | 2023-02-05 11:09:46 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 28 | 29 | 2023-02-05 11:09:46 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 30 | 31 | 2023-02-05 11:09:47 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 32 | 33 | 2023-02-05 11:09:47 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:9, 提议:5] 34 | 35 | 2023-02-05 11:09:47 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:9, 提议:5] 36 | 37 | 2023-02-05 11:09:48 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:14, 提议:5] 38 | 39 | 2023-02-05 11:09:51 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:14, 提议:5] 40 | 41 | 2023-02-05 11:09:52 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:14, 提议:5] 42 | 43 | 2023-02-05 11:09:53 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:14, 提议:5] 44 | 45 | 2023-02-05 11:09:53 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:14, 提议:5] 46 | 47 | 2023-02-05 11:09:54 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:14, 提议:5] 48 | 49 | 2023-02-05 11:09:54 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:14, 提议:5] 50 | 51 | 2023-02-05 11:09:55 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:14, 提议:5] 52 | 53 | 2023-02-05 11:09:56 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:19, 提议:5] 54 | 55 | 2023-02-05 11:09:59 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:19, 提议:5] 56 | 57 | 2023-02-05 11:10:02 Tid:66 [Info] Proposer3号开始(Propose阶段):提议=[编号:24, 提议:5] 58 | 59 | 2023-02-05 11:10:05 Tid:66 [Info] Proposer3号开始(Accept阶段):提议=[编号:24, 提议:5] 60 | 61 | 2023-02-05 11:10:06 Tid:66 [Info] Proposer3号的提议被批准,用时33494MS:最终提议 = [编号:24, 提议:5] 62 | 63 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/Paxos/Proposer.cpp: -------------------------------------------------------------------------------- 1 | #include "Proposer.h" 2 | 3 | namespace paxos 4 | { 5 | 6 | Proposer::Proposer() 7 | { 8 | SetPlayerCount(0, 0); 9 | } 10 | 11 | Proposer::Proposer(short proposerCount, short acceptorCount) 12 | { 13 | SetPlayerCount(proposerCount, acceptorCount); 14 | } 15 | 16 | Proposer::~Proposer() 17 | { 18 | } 19 | 20 | void Proposer::SetPlayerCount(short proposerCount, short acceptorCount) 21 | { 22 | m_proposerCount = proposerCount; 23 | m_acceptorCount = acceptorCount; 24 | 25 | return; 26 | } 27 | 28 | void Proposer::StartPropose(PROPOSAL &value) 29 | { 30 | m_value = value; 31 | m_proposeFinished = false; 32 | m_isAgree = false; 33 | m_maxAcceptedSerialNum = 0; 34 | m_okCount = 0; 35 | m_refuseCount = 0; 36 | m_start = time(NULL); 37 | 38 | return; 39 | } 40 | 41 | PROPOSAL& Proposer::GetProposal() 42 | { 43 | return m_value; 44 | } 45 | 46 | bool Proposer::Proposed(bool ok, PROPOSAL &lastAcceptValue) 47 | { 48 | if ( m_proposeFinished ) return true;//可能是一阶段迟到的回应,直接忽略消息 49 | 50 | if ( !ok ) 51 | { 52 | m_refuseCount++; 53 | //已有半数拒绝,不需要等待其它acceptor投票了,重新开始Propose阶段 54 | //使用StartPropose(m_value)重置状态 55 | 56 | //请完善下面逻辑 57 | /**********Begin**********/ 58 | if (m_refuseCount > m_acceptorCount / 2) 59 | { 60 | m_value.serialNum += m_proposerCount; 61 | StartPropose(m_value); 62 | return false; 63 | } 64 | /**********End**********/ 65 | 66 | //拒绝数不到一半 67 | return true; 68 | } 69 | 70 | m_okCount++; 71 | /* 72 | 没有必要检查分支:serialNum为null 73 | 因为serialNum>m_maxAcceptedSerialNum,与serialNum非0互为必要条件 74 | */ 75 | //如果已经有提议被接受,修改成已被接受的提议 76 | //请完善下面逻辑 77 | /**********Begin**********/ 78 | if (lastAcceptValue.serialNum > m_maxAcceptedSerialNum) 79 | { 80 | m_maxAcceptedSerialNum = lastAcceptValue.serialNum; 81 | m_value.value = lastAcceptValue.value; 82 | } 83 | /**********End**********/ 84 | 85 | //如果自己的提议被接受 86 | if ( m_okCount > m_acceptorCount / 2 ) 87 | { 88 | m_okCount = 0; 89 | m_proposeFinished = true; 90 | } 91 | return true; 92 | } 93 | 94 | bool Proposer::StartAccept() 95 | { 96 | return m_proposeFinished; 97 | } 98 | 99 | bool Proposer::Accepted(bool ok) 100 | { 101 | if ( !m_proposeFinished ) return true;//可能是上次第二阶段迟到的回应,直接忽略消息 102 | 103 | if ( !ok ) 104 | { 105 | m_refuseCount++; 106 | //已有半数拒绝,不需要等待其它acceptor投票了,重新开始Propose阶段 107 | //使用StartPropose(m_value)重置状态 108 | //请完善下面逻辑 109 | /**********Begin**********/ 110 | if (m_refuseCount > m_acceptorCount / 2) 111 | { 112 | m_value.serialNum += m_proposerCount; 113 | StartPropose(m_value); 114 | return false; 115 | } 116 | /**********End**********/ 117 | 118 | return true; 119 | } 120 | 121 | m_okCount++; 122 | if ( m_okCount > m_acceptorCount / 2 ) m_isAgree = true; 123 | 124 | return true; 125 | } 126 | 127 | bool Proposer::IsAgree() 128 | { 129 | return m_isAgree; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Thread.cpp: -------------------------------------------------------------------------------- 1 | // Thread.cpp: implementation of the Thread class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | #include "Thread.h" 5 | #include 6 | #ifdef WIN32 7 | #include 8 | #endif 9 | 10 | namespace mdk 11 | { 12 | 13 | Thread::Thread() 14 | { 15 | m_bRun = false; 16 | #ifdef WIN32 17 | m_hHandle = NULL; 18 | #else 19 | m_bStop = true; 20 | int nError = 0; 21 | pthread_mutexattr_t mutexattr; 22 | if ( 0 != (nError = pthread_mutexattr_init( &mutexattr )) ) return ; 23 | if ( 0 != (nError = pthread_mutexattr_settype( &mutexattr, PTHREAD_MUTEX_TIMED_NP )) ) return ; 24 | if ( 0 != (nError = pthread_mutex_init( &m_exitMutex, &mutexattr )) ) return; 25 | if ( 0 != (nError = pthread_mutexattr_destroy( &mutexattr )) ) return ; 26 | pthread_cond_init( &m_exit, NULL ); 27 | #endif 28 | } 29 | 30 | Thread::~Thread() 31 | { 32 | Stop(); 33 | #ifndef WIN32 34 | pthread_cond_destroy( &m_exit ); 35 | pthread_mutex_destroy( &m_exitMutex ); 36 | #endif 37 | } 38 | 39 | //启动线程,使用全局函数,pParam传递给线程函数的参数 40 | bool Thread::Run( FuntionPointer fun, void *pParam ) 41 | { 42 | if ( m_bRun ) return false; 43 | m_task.Accept(fun, pParam); 44 | m_bRun = Run(NULL); 45 | 46 | return m_bRun; 47 | } 48 | 49 | //启动线程,使用类成员函数,pParam传递给线程函数的参数 50 | bool Thread::Run( MethodPointer method, void *pObj, void *pParam ) 51 | { 52 | if ( m_bRun ) return false; 53 | m_task.Accept(method, pObj, pParam); 54 | m_bRun = Run(NULL); 55 | 56 | return m_bRun; 57 | } 58 | 59 | //启动 60 | bool Thread::Run( void *pParam ) 61 | { 62 | #ifdef WIN32 63 | m_hHandle = CreateThread( 64 | NULL, 0, 65 | (LPTHREAD_START_ROUTINE)TMain, 66 | (LPVOID)this, 0, &m_nID ); 67 | if ( NULL == m_hHandle ) return false; 68 | #else 69 | m_bStop = false; 70 | // 分离状态的线程,结束时不需要pthread_join 71 | pthread_attr_t attr; 72 | pthread_attr_init (&attr); 73 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 74 | pthread_create( &m_nID, &attr, TMain, this ); 75 | pthread_attr_destroy (&attr); 76 | #endif 77 | 78 | return true; 79 | } 80 | 81 | void* Thread::TMain(void* param) 82 | { 83 | Thread *pThis = (Thread*)param; 84 | 85 | return pThis->Main(); 86 | } 87 | 88 | void* Thread::Main() 89 | { 90 | void *ret = NULL; 91 | ret = m_task.Execute(); 92 | #ifndef WIN32 93 | m_bStop = true; 94 | pthread_cond_broadcast(&m_exit); 95 | #endif 96 | m_bRun = false; 97 | 98 | return ret; 99 | } 100 | 101 | //停止 102 | void Thread::Stop( long lMillSecond ) 103 | { 104 | #ifdef WIN32 105 | if ( NULL == m_hHandle ) return; 106 | if ( WAIT_OBJECT_0 != WaitForSingleObject( m_hHandle, lMillSecond ) ) 107 | { 108 | TerminateThread( m_hHandle, 0 ); 109 | } 110 | CloseHandle(m_hHandle); 111 | m_hHandle = NULL; 112 | #else 113 | if ( m_bStop ) 114 | { 115 | m_bRun = false; 116 | return; 117 | } 118 | if ( 0 > lMillSecond ) lMillSecond = 3; 119 | int nSecond = lMillSecond / 1000; 120 | int nNSecond = (lMillSecond - nSecond * 1000) * 1000; 121 | timespec timeout; 122 | timeout.tv_sec=time(NULL) + nSecond; 123 | timeout.tv_nsec=nNSecond; 124 | pthread_mutex_lock( &m_exitMutex ); 125 | if ( 0 != pthread_cond_timedwait(&m_exit, &m_exitMutex, &timeout) ) 126 | { 127 | pthread_kill(m_nID, 1); 128 | } 129 | pthread_mutex_unlock( &m_exitMutex ); 130 | #endif 131 | m_bRun = false; 132 | 133 | return; 134 | } 135 | 136 | //等待线程停止 137 | void Thread::WaitStop() 138 | { 139 | #ifdef WIN32 140 | WaitForSingleObject( m_hHandle, INFINITE ); 141 | #else 142 | pthread_mutex_lock( &m_exitMutex ); 143 | pthread_cond_wait(&m_exit, &m_exitMutex); 144 | pthread_mutex_unlock( &m_exitMutex ); 145 | #endif 146 | } 147 | 148 | //取得ID 149 | ThreadID Thread::GetID() 150 | { 151 | return this->m_nID; 152 | } 153 | 154 | }//namespace mdk 155 | -------------------------------------------------------------------------------- /assignment/README.md: -------------------------------------------------------------------------------- 1 | # 作业题说明 2 | 3 | 来自头歌的任务要求页面。 4 | 5 | ## 1 Paxos 6 | 7 | 相关代码和说明在文件夹 `paxos` 中。 8 | 9 | ### 1.1 任务描述 10 | 11 | 根据 Paxos 算法流程完成相关核心成员函数设计。 12 | 13 | ### 1.2 相关知识 14 | 15 | 在学习之前, 我们可以先了解一下相关概念知识。 16 | 17 | #### 1.2.1 角色 18 | 19 | 在 Paxos 算法中有以下几个角色: 20 | 21 | 提议者`(proposer)`: 进行提议的角色; 22 | 批准者`(acceptor)`: 通过提议的角色; 23 | 学习者`(learner)`: 感知`(learn)`被选中的提议。 24 | 在具体的实现中, 一个进程可能同时充当多种角色。比如一个进程可能既是 Proposer 又是 Acceptor 又是 Learner。 25 | 26 | #### 1.2.2 提案 27 | 28 | 还有一个很重要的概念叫提案 ( Proposal ) 。最终要达成一致的 value 就在提案里。 29 | Proposer 可以提出 ( propose ) 提案; Acceptor 可以接受 ( accept ) 提案; 如果某个提案被选定 ( chosen ) , 那么该提案里的 value 就被选定了。 30 | 31 | **选定提案** 32 | 在何种情况下不同的进程认为提案被选中了? 33 | 34 | 1. Proposer : 只要 Proposer 发的提案被 Acceptor 接受, Proposer 就认为该提案里的 value 被选定了。 35 | 36 | 2. Acceptor : 只要 Acceptor 接受了某个提案, Acceptor 就认为该提案里的value 被选定了。 37 | 38 | 3. Learner: Acceptor 告诉 Learner 哪个 value 被选定, Learner 就认为那个 value 被选定。 39 | 40 | ### 1.3 编程要求 41 | 42 | 根据提示, 在右侧编辑器中的 begin-end 间补充代码, 根据 Paxos 算法流程完成 Proposer.cpp 和 Acceptor.cpp 中 Proposer 和 Acceptor 类的核心成员函数设计。 43 | 44 | ### 1.4 测试说明 45 | 46 | 后台会自动检测你的输出结果, 当与预期输出一致时, 则算通关。 47 | 48 | 实验正确输出大致如下: 49 | 50 | ![output](image/paxos_test.png) 51 | 52 | 为了便于评测, 后台会对结果进行处理, 处理后的预期输出如下: 53 | 54 | ```JavaScript{.line-numbers} 55 | 最终通过提议值为: 5 56 | ``` 57 | 58 | *** 59 | 60 | 开始你的任务吧, 祝你成功! 61 | 62 | ## 2 Write through 63 | 64 | 相关代码和说明在文件夹 `write_through` 中。 65 | 66 | ### 2.1 任务描述 67 | 68 | 本关任务: 补充程序实现写穿算法 69 | 70 | ### 2.2 相关知识 71 | 72 | 为了完成本关任务, 你需要掌握: 1.分布式文件系统基础概念, 2.写穿算法。 73 | 74 | ### 2.3 分布式文件系统 75 | 76 | + 从用户的使用角度来看, 分布式文件系统是一个标准的文件系统, 提供了一系列API, 由此进行文件或目录的创建、移动、删除, 以及对文件的读写等操作 77 | 78 | + 从内部实现角度来看, 分布式文件系统还要通过网络管理存储在多个节点上的文件和目录。并且, 同一文件不只是存储在一个节点上, 而是按规则分布存储在一簇节点上, 协同提供服务 79 | 80 | ### 2.4 写穿算法 81 | 82 | 当用户在修改高速缓存项 (文件或块) 时, 新的值保存在高速缓存中, 并立即写回到服务器, 当用户读取速缓存项 (文件或块) 时, 需要先和服务端进行文件的version号比对, 如果一致, 直接从高速缓存项cache中读取文件, 如果不一致则从服务器中读取文件并将文件缓存在本地高速cache中。 83 | 84 | ### 2.5 编程提示 85 | 86 | 类与函数解释 87 | 88 | ```JavaScript{.line-numbers} 89 | sim_file 模拟文件条目类 90 | sim_file.write(data,verion) 向文件条目写入data和version 91 | sim_file.get_data() 获取文件条目数据, 返回file_name,data,version 92 | sim_file.get_version() 获取文件version 93 | server 模拟服务器类, 在cache类初始化时绑定为self._target_server, 请使用该变量调用 94 | server.write(target_file,data,version) 尝试向服务器写入目标文件, 如果目标文件已经存在, 则会覆盖写入 95 | server.read(target_file) 尝试向服务器读取目标文件, 如果服务器中存在该文件, 则会返回 file_name,data,version 96 | 如果不存在, 则会返回None 97 | server.get_version(target_file) 尝试向服务器获取目标文件version 98 | cache 模拟高速缓存类 (在实现的函数中时候self调用下列函数) 99 | cache._get_new_version() 返回一个时间戳作为version 100 | cache._read_cache(target_file) 尝试从高速缓存中读取目标文件, 101 | 如果高速缓存中存在该文件, 则会返回 file_name,data,version 102 | 如果不存在, 则会返回None 103 | cache._write_cache(target_file,data,version) 尝试向高速缓存中写入目标文件, 如果目标文件已经存在, 则会覆盖写入 104 | cache._search_cache(target_file)在高速缓存中检索文件是否已经缓存 105 | 注意: 106 | 测试数据确保不会出现读取服务器不存在的文件 107 | 测试程序不存在也不要求高速缓存换出的情况 108 | 请勿直接操作cache类和server类私有变量(除了调用_target_server外) 109 | ``` 110 | 111 | ### 2.6 编程要求 112 | 113 | 根据提示, 在右侧编辑器补充代码, 根据cache.py中的提示完成cache类的读和写程序 114 | 115 | 读函数编写 116 | 117 | ![read](image/read.png) 118 | 119 | 写函数编写 120 | 121 | ![write](image/write.png) 122 | 123 | ### 2.7 测试说明 124 | 125 | 平台会对你编写的代码进行测试: 126 | 127 | 测试输入解释: 第一行两个数字分别代表读写的操作次数m和用户数量n。接下来的m行中每一行分为读和写两种操作类型, 当操作类型是“write”时, 后面三个参数分别是用户编号、文件编号、写入的文件数据 (int类型) ; 当操作类型是“read”时, 后面两个参数分别是用户编号、文件编号。 128 | 129 | 在程序实际运行中, 你并不需要对输入进行处理, 测试程序会处理输入并按照输入调用cache类的read和write函数 130 | 131 | 测试输出解释: 每一行的数字是每个“read”操作后返回的文件数据 (int类型) 132 | 133 | **测试输入样例:** 134 | 135 | ```shell 136 | 5 2 137 | write 0 0 10 138 | read 0 0 139 | read 1 0 140 | write 1 0 5 141 | read 0 0 142 | ``` 143 | 144 | **预期输出:** 145 | 146 | ```shell 147 | 10 148 | 10 149 | 5 150 | ``` 151 | 152 | *** 153 | 154 | 开始你的任务吧, 祝你成功! 155 | -------------------------------------------------------------------------------- /assignment/write_through/cache.py: -------------------------------------------------------------------------------- 1 | import time 2 | from sim_file import sim_file 3 | from server import sim_server 4 | 5 | class sim_cache: 6 | 7 | def __init__(self,server): 8 | self._cache_file = {} 9 | self._target_server = server 10 | 11 | def _search_cache(self,target_file): 12 | # search file in the cache 13 | return target_file in self._cache_file 14 | 15 | def _read_cache(self,target_file): 16 | #read cached file 17 | if self._search_cache(target_file): 18 | return self._cache_file[target_file].get_data() 19 | else: 20 | return None 21 | 22 | def _write_cache(self,target_file,data,version): 23 | #write file to the cache 24 | if self._search_cache(target_file): 25 | self._cache_file[target_file].write_data(data,version) 26 | else: 27 | self._cache_file[target_file] = sim_file(target_file,data,version) 28 | 29 | def _invalidata_data(self,target_file): 30 | self._cache_file.pop(target_file) 31 | 32 | def _get_new_version(self): 33 | return time.time() 34 | 35 | 36 | ''' 37 | 可能用到的类与函数 38 | 39 | sim_file 模拟文件条目类 40 | sim_file.write(data,verion) 向文件条目写入data和version 41 | 42 | sim_file.get_data() 获取文件条目数据, 返回file_name,data,version 43 | 44 | sim_file.get_version() 获取文件version 45 | 46 | server 模拟服务器类, 在cache类初始化时绑定为self._target_server, 请使用该变量调用 47 | server.write(target_file,data,version) 尝试向服务器写入目标文件,如果目标文件已经存在,则会覆盖写入 48 | 49 | server.read(target_file) 尝试向服务器读取目标文件,如果服务器中存在该文件,则会返回 file_name,data,version 50 | 如果不存在, 则会返回None 51 | 52 | server.get_version(target_file) 尝试向服务器获取目标文件version 53 | 54 | cache 模拟高速缓存类(在实现的函数中时候self调用下列函数) 55 | cache._get_new_version() 返回一个时间戳作为version 56 | 57 | cache._read_cache(target_file) 尝试从高速缓存中读取目标文件, 58 | 如果高速缓存中存在该文件,则会返回 file_name,data,version 59 | 如果不存在, 则会返回None 60 | 61 | cache._write_cache(target_file,data,version) 尝试向高速缓存中写入目标文件,如果目标文件已经存在,则会覆盖写入 62 | 63 | cache._search_cache(target_file)在高速缓存中检索文件是否已经缓存 64 | 65 | ''' 66 | 67 | """ 68 | 注意: 69 | 测试数据确保不会出现读取服务器不存在的文件 70 | 测试程序不存在也不要求高速缓存换出的情况 71 | 请勿直接操作cache类和server类私有变量(除了调用_target_server外) 72 | """ 73 | 74 | 75 | def read(self,target_file): 76 | #read file from file system 77 | 78 | ####### Begin ####### 79 | 80 | #检查缓存中是否已缓存文件 81 | 82 | #向server确认version是否一致 83 | 84 | #选择从cache/server中读取文件 85 | 86 | #缓存从server中读取的文件 87 | 88 | if self._search_cache(target_file): 89 | _, cache_data, cache_version = self._read_cache(target_file) 90 | _, server_data, server_version = self._target_server.read(target_file) 91 | if cache_version == server_version: 92 | return cache_data 93 | else: 94 | self._write_cache(target_file, server_data, server_version) 95 | return server_data 96 | 97 | elif self._target_server._search_server(target_file): 98 | _, server_data, server_version = self._target_server.read(target_file) 99 | self._write_cache(target_file, server_data, server_version) 100 | return server_data 101 | 102 | ######## End ######## 103 | 104 | # there is no file in the system 105 | return 106 | 107 | def write(self,target_file,data): 108 | 109 | ####### Begin ####### 110 | 111 | #生成新version 112 | 113 | #向cache中写入数据并更新version 114 | 115 | #向server中写入数据并更新version 116 | 117 | new_version = self._get_new_version() 118 | self._write_cache(target_file, data, new_version) 119 | self._target_server.write(target_file, data, new_version) 120 | 121 | ######## End ######## 122 | 123 | return -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/Paxos.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "Paxos/Acceptor.h" 4 | #include "Paxos/Proposer.h" 5 | #include "lib/Thread.h" 6 | #include "lib/Lock.h" 7 | #include "lib/mapi.h" 8 | #include "lib/atom.h" 9 | #include "lib/Logger.h" 10 | 11 | paxos::Proposer p[5]; 12 | paxos::Acceptor a[11]; 13 | mdk::Mutex l[11]; 14 | int finishedCount = 0; 15 | int finalValue = -1; 16 | bool isFinished = false; 17 | mdk::uint64 g_start; 18 | mdk::Logger g_log; 19 | 20 | void* Proposer(void *id) 21 | { 22 | mdk::Logger log; 23 | char logName[256]; 24 | sprintf( logName, "Proposer%ld", (long)id ); 25 | log.SetLogName(logName); 26 | log.SetMaxLogSize(10); 27 | log.SetMaxExistDay(30); 28 | log.SetPrintLog(false); 29 | 30 | paxos::Proposer &proposer = p[(long)id]; 31 | paxos::PROPOSAL value = proposer.GetProposal(); 32 | paxos::PROPOSAL lastValue; 33 | 34 | 35 | int acceptorId[11]; 36 | int count = 0; 37 | 38 | mdk::uint64 start = mdk::MillTime(); 39 | while ( true ) 40 | { 41 | value = proposer.GetProposal();//拿到提议 42 | log.Info("Info", "Proposer%d号开始(Propose阶段):提议=[编号:%d, 提议:%d]\n", 43 | (long)id, value.serialNum, value.value); 44 | count = 0; 45 | int i = 0; 46 | for (i = 0; i < 11; i++ ) 47 | { 48 | /* 49 | * 发送消息到第i个acceptor 50 | * 经过一定时间达到acceptor, sleep(随机时间)模拟 51 | * acceptor处理消息, mAcceptors[i].Propose() 52 | * 回应proposer 53 | * 经过一定时间proposer收到回应, sleep(随机时间)模拟 54 | * proposer处理回应mProposer.proposed(ok, lastValue) 55 | */ 56 | mdk::m_sleep(rand()%500);//经过随机时间, 消息到达了mAcceptors[i] 57 | //处理消息 58 | l[i].Lock(); 59 | bool ok = a[i].Propose(value.serialNum, lastValue); 60 | l[i].Unlock(); 61 | mdk::m_sleep(rand()%500);//经过随机时间,消息到达Proposer 62 | //处理Propose回应 63 | if ( !proposer.Proposed(ok, lastValue) ) //重新开始Propose阶段 64 | { 65 | mdk::m_sleep(1000);//为了降低活锁, 多等一会让别的proposer有机会完成自己的2阶段批准 66 | break; 67 | } 68 | paxos::PROPOSAL curValue = proposer.GetProposal();//拿到提议 69 | if ( curValue.value != value.value )//acceptor本次回应可能推荐了一个提议 70 | { 71 | log.Info("Info", "Proposer%d号修改了提议:提议=[编号:%d, 提议:%d]\n", 72 | (long)id, curValue.serialNum, curValue.value); 73 | break; 74 | } 75 | acceptorId[count++] = i;//记录愿意投票的acceptor 76 | if ( proposer.StartAccept() ) break; 77 | } 78 | //检查有没有达到Accept开始条件, 如果没有表示要重新开始Propose阶段 79 | if ( !proposer.StartAccept() ) continue; 80 | 81 | //开始Accept阶段 82 | //发送Accept消息到所有愿意投票的acceptor 83 | value = proposer.GetProposal(); 84 | log.Info("Info", "Proposer%d号开始(Accept阶段):提议=[编号:%d, 提议:%d]\n", 85 | (long)id, value.serialNum, value.value); 86 | for (i = 0; i < count; i++ ) 87 | { 88 | //发送accept消息到acceptor 89 | //减少accept阶段等待时间, 加快收敛 90 | mdk::m_sleep(rand()%200);//经过随机时间,accept消息到达acceptor 91 | //处理accept消息 92 | l[acceptorId[i]].Lock(); 93 | bool ok = a[acceptorId[i]].Accept(value); 94 | l[acceptorId[i]].Unlock(); 95 | mdk::m_sleep(rand()%200);//经过随机时间,accept回应到达proposer 96 | //处理accept回应 97 | if ( !proposer.Accepted(ok) ) //重新开始Propose阶段 98 | { 99 | mdk::m_sleep(1000);//为了降低活锁, 多等一会让别的proposer有机会完成自己的2阶段批准 100 | break; 101 | } 102 | if ( proposer.IsAgree() )//成功批准了提议 103 | { 104 | start = mdk::MillTime() - start; 105 | log.Info("Info", "Proposer%d号的提议被批准,用时%lluMS:最终提议 = [编号:%d, 提议:%d]\n", (long)id, start, value.serialNum, value.value); 106 | g_log.Info("Info", "Proposer%d号的提议被批准,用时%lluMS:最终提议 = [编号:%d, 提议:%d]\n", (long)id, start, value.serialNum, value.value); 107 | if(finalValue == -1) finalValue = value.value; 108 | else if(finalValue != value.value) finalValue = 0; 109 | if ( 4 == mdk::AtomAdd(&finishedCount, 1) ) 110 | { 111 | isFinished = true; 112 | g_start = mdk::MillTime() - g_start; 113 | if(finalValue > 0){ 114 | g_log.Info("Info", "Paxos完成, 用时%lluMS, 最终通过提议值为: %d\n", g_start, finalValue); 115 | } 116 | else{ 117 | g_log.Info("Info", "Paxos完成, 用时%lluMS, 最终结果不一致!\n", g_start); 118 | } 119 | } 120 | return NULL; 121 | } 122 | } 123 | } 124 | return NULL; 125 | } 126 | 127 | //Paxos过程模拟演示程序 128 | int main(int argc, char* argv[]) 129 | { 130 | long i = 0; 131 | g_log.SetLogName("Paxos"); 132 | g_log.SetMaxLogSize(10); 133 | g_log.SetMaxExistDay(30); 134 | g_log.SetPrintLog(true); 135 | g_log.Info("Info", "5个Proposer, 11个Acceptor准备进行Paxos\n" 136 | "每个Proposer独立线程, Acceptor不需要线程\n" 137 | "Proposer编号从0-10,编号为i的Proposer初始提议编号和提议值是 (i+1, i+1) \n" 138 | "Proposer每次重新提议会将提议编号增加5\n" 139 | "Proposer被批准后结束线程,其它线程继续投票最终, 全部批准相同的值, 达成一致。\n"); 140 | g_start = mdk::MillTime(); 141 | g_log.Info("Info", "Paxos开始\n" ); 142 | paxos::PROPOSAL value; 143 | 144 | for ( i = 0; i < 5; i++ ) 145 | { 146 | p[i].SetPlayerCount(5, 11); 147 | value.serialNum = value.value = i + 1; 148 | p[i].StartPropose(value); 149 | } 150 | 151 | mdk::Thread t[5]; 152 | for ( i = 0; i < 5; i++ ) t[i].Run(Proposer, (void*)i); 153 | //for ( i = 0; i < 5; i++ ) t[i].WaitStop(); 154 | while(true){ 155 | if(isFinished) break; 156 | mdk::m_sleep(500); 157 | } 158 | return 0; 159 | } 160 | -------------------------------------------------------------------------------- /report/figure/read.svg: -------------------------------------------------------------------------------- 1 | 开始Cache中已缓存文件?Server中读取文件将文件内容写入Cache返回文件数据结束Cache获取文件信息Server中获取文件信息Version是否一致?YNYN -------------------------------------------------------------------------------- /report/figure/write_through.svg: -------------------------------------------------------------------------------- 1 | AClientBACacheBAServerBWriteRead1. write to cache2. write to server3. read from server4. read from cache -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/mapi.cpp: -------------------------------------------------------------------------------- 1 | // mapi.cpp: implementation of the mapi class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "mapi.h" 10 | #ifdef WIN32 11 | #include 12 | #include 13 | #else 14 | #include 15 | #include 16 | #include 17 | #endif 18 | 19 | #include 20 | 21 | ////////////////////////////////////////////////////////////////////// 22 | // Construction/Destruction 23 | ////////////////////////////////////////////////////////////////////// 24 | 25 | using namespace std; 26 | 27 | namespace mdk 28 | { 29 | 30 | void mdk_assert( bool isTrue ) 31 | { 32 | if ( isTrue ) return; 33 | char *p = NULL; 34 | *p = 1; 35 | exit(0); 36 | } 37 | 38 | void m_sleep( long lMillSecond ) 39 | { 40 | #ifndef WIN32 41 | usleep( lMillSecond * 1000 ); 42 | #else 43 | Sleep( lMillSecond ); 44 | #endif 45 | } 46 | 47 | bool addrToI64(uint64 &addr64, const char* ip, int port) 48 | { 49 | unsigned char addr[8]; 50 | int nIP[4]; 51 | sscanf(ip, "%d.%d.%d.%d", &nIP[0], &nIP[1], &nIP[2], &nIP[3]); 52 | addr[0] = nIP[0]; 53 | addr[1] = nIP[1]; 54 | addr[2] = nIP[2]; 55 | addr[3] = nIP[3]; 56 | char checkIP[25]; 57 | sprintf(checkIP, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); 58 | if ( 0 != strcmp(checkIP, ip) ) return false; 59 | memcpy( &addr[4], &port, 4); 60 | memcpy(&addr64, addr, 8); 61 | 62 | return true; 63 | } 64 | 65 | void i64ToAddr(char* ip, int &port, uint64 addr64) 66 | { 67 | unsigned char addr[8]; 68 | memcpy(addr, &addr64, 8); 69 | sprintf(ip, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); 70 | memcpy(&port, &addr[4], 4); 71 | } 72 | 73 | void TrimString( string &str, string del ) 74 | { 75 | int nPos = 0; 76 | unsigned int i = 0; 77 | for ( ; i < del.size(); i++ ) 78 | { 79 | while ( true ) 80 | { 81 | nPos = str.find( del.c_str()[i], 0 ); 82 | if ( -1 == nPos ) break; 83 | str.replace( str.begin() + nPos, str.begin() + nPos+1, "" ); 84 | } 85 | } 86 | } 87 | 88 | void TrimStringLeft( string &str, string del ) 89 | { 90 | unsigned int i = 0; 91 | bool bTrim = false; 92 | for ( ; i < str.size(); i++ ) 93 | { 94 | if ( string::npos == del.find(str.c_str()[i]) ) break; 95 | bTrim = true; 96 | } 97 | if ( !bTrim ) return; 98 | str.replace( str.begin(), str.begin() + i, "" ); 99 | } 100 | 101 | void TrimStringRight( string &str, string del ) 102 | { 103 | int i = str.size() - 1; 104 | bool bTrim = false; 105 | for ( ; i >= 0; i-- ) 106 | { 107 | if ( string::npos == del.find(str.c_str()[i]) ) break; 108 | bTrim = true; 109 | } 110 | if ( !bTrim ) return; 111 | str.replace( str.begin() + i + 1, str.end(), "" ); 112 | } 113 | 114 | //压缩空白字符 115 | char* Trim( char *str ) 116 | { 117 | if ( NULL == str || '\0' == str[0] ) return str; 118 | int i = 0; 119 | char *src = str; 120 | char strTemp[256]; 121 | for ( i = 0; '\0' != *src ; src++ ) 122 | { 123 | if ( ' ' == *src || '\t' == *src ) continue; 124 | strTemp[i++] = *src; 125 | } 126 | strTemp[i++] = '\0'; 127 | strcpy( str, strTemp ); 128 | return str; 129 | } 130 | 131 | //压缩空白字符 132 | char* TrimRight( char *str ) 133 | { 134 | if ( NULL == str || '\0' == str[0] ) return str; 135 | int i = 0; 136 | char *src = str; 137 | for ( i = 0; '\0' != *src ; src++ ) 138 | { 139 | if ( ' ' == *src || '\t' == *src ) 140 | { 141 | i++; 142 | continue; 143 | } 144 | i = 0; 145 | } 146 | str[strlen(str) - i] = 0; 147 | return str; 148 | } 149 | 150 | //压缩空白字符 151 | char* TrimLeft( char *str ) 152 | { 153 | if ( NULL == str || '\0' == str[0] ) return str; 154 | char *src = str; 155 | for ( ; '\0' != *src ; src++ ) 156 | { 157 | if ( ' ' != *src && '\t' != *src ) break; 158 | } 159 | char strTemp[256]; 160 | strcpy( strTemp, src ); 161 | strcpy( str, strTemp ); 162 | return str; 163 | } 164 | 165 | int reversal(int i) 166 | { 167 | int out = 0; 168 | out = i << 24; 169 | out += i >> 24; 170 | out += ((i >> 8) << 24) >> 8; 171 | out += ((i >> 16) << 24) >> 16; 172 | return out; 173 | } 174 | 175 | unsigned long GetFileSize(const char *filename) 176 | { 177 | unsigned long filesize = 0; 178 | struct stat statbuff; 179 | if(stat(filename, &statbuff) < 0) return filesize; 180 | else filesize = statbuff.st_size; 181 | return filesize; 182 | } 183 | 184 | unsigned int GetCUPNumber(int maxCpu, int defaultCpuNumber) 185 | { 186 | #ifdef WIN32 187 | SYSTEM_INFO sysInfo; 188 | ::GetSystemInfo(&sysInfo); 189 | int dwNumCpu = sysInfo.dwNumberOfProcessors; 190 | if ( dwNumCpu > maxCpu ) return defaultCpuNumber; 191 | return dwNumCpu; 192 | #else 193 | unsigned int dwNumCpu = sysconf(_SC_NPROCESSORS_ONLN); 194 | if ( dwNumCpu > maxCpu ) return defaultCpuNumber; 195 | return dwNumCpu; 196 | #endif 197 | } 198 | 199 | #ifndef WIN32 200 | #include 201 | #include 202 | /* 203 | syscall(__NR_gettid)或者syscall(SYS_gettid) 204 | SYS_gettid与__NR_gettid是相等的常量 205 | 在64bit=186,在32bit=224 206 | 207 | 命令行查看程序线程id方法 208 | 首先使用[pgrep 进程名]指令显示出主线程id 209 | 然后使用[ls /proc/主线程id/task/]显示所有子线程id 210 | */ 211 | #define gettid() syscall(__NR_gettid) 212 | #endif 213 | 214 | uint64 CurThreadId() 215 | { 216 | #ifdef WIN32 217 | return GetCurrentThreadId(); 218 | #else 219 | return gettid(); 220 | #endif 221 | } 222 | 223 | //返回0时0分0秒的当前日期 224 | time_t mdk_Date() 225 | { 226 | time_t curTime = time(NULL); 227 | tm *pTm = localtime(&curTime); 228 | char hour[32]; 229 | char mintue[32]; 230 | char second[32]; 231 | strftime( hour, 30, "%H", pTm ); 232 | strftime( mintue, 30, "%M", pTm ); 233 | strftime( second, 30, "%S", pTm ); 234 | int sumSecond = atoi(hour) * 3600 + atoi(mintue) * 60 + atoi(second); 235 | curTime -= sumSecond; 236 | return curTime; 237 | } 238 | 239 | bool GetExeDir( char *exeDir, int size ) 240 | { 241 | #ifdef WIN32 242 | TCHAR *pExepath = (TCHAR*)exeDir; 243 | GetModuleFileName(NULL, pExepath, size); 244 | char drive[_MAX_DRIVE]; 245 | char dir[_MAX_DIR]; 246 | char fname[_MAX_FNAME]; 247 | char ext[_MAX_EXT]; 248 | 249 | _splitpath( pExepath, drive, dir, fname, ext); 250 | _makepath( pExepath, drive, dir, NULL, NULL); 251 | return true; 252 | #else 253 | int rval; 254 | char* last_slash; 255 | 256 | //读符号链接 /proc/self/exe 的目标 257 | rval = readlink ("/proc/self/exe", exeDir, size); 258 | if (rval == -1) //readlink调用失败 259 | { 260 | strcpy( exeDir, "./" ); 261 | return false; 262 | } 263 | exeDir[rval] = '\0'; 264 | last_slash = strrchr (exeDir, '/'); 265 | if ( NULL == last_slash || exeDir == last_slash )//一些异常正在发生 266 | { 267 | strcpy( exeDir, "./" ); 268 | return false; 269 | } 270 | size = last_slash - exeDir; 271 | exeDir[size] = '\0'; 272 | #endif 273 | return true; 274 | } 275 | 276 | mdk::uint64 MillTime() 277 | { 278 | #ifdef WIN32 279 | SYSTEMTIME st; 280 | GetLocalTime(&st); 281 | 282 | FILETIME ft; 283 | SystemTimeToFileTime( &st, &ft ); 284 | LONGLONG nLL; 285 | ULARGE_INTEGER ui; 286 | ui.LowPart = ft.dwLowDateTime; 287 | ui.HighPart = ft.dwHighDateTime; 288 | nLL = (ft.dwHighDateTime << 32) + ft.dwLowDateTime; 289 | mdk::int64 mt = ((LONGLONG)(ui.QuadPart - 116444736000000000) / 10000); 290 | mt -= 3600 * 8 * 1000;//日历时间(time()返回的时间) 291 | return mt; 292 | #else 293 | struct timespec ts; 294 | 295 | clock_gettime(CLOCK_REALTIME, &ts); 296 | 297 | return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); 298 | #endif 299 | } 300 | 301 | } -------------------------------------------------------------------------------- /assignment/paxos/Paxos/src/lib/Logger.cpp: -------------------------------------------------------------------------------- 1 | // Logger.cpp: implementation of the Logger class. 2 | // 3 | ////////////////////////////////////////////////////////////////////// 4 | 5 | #include "mapi.h" 6 | #include "Logger.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef WIN32 13 | #include 14 | #include 15 | #include 16 | #else 17 | #include //chdir() 18 | #include //mkdir() 19 | #include //mkdir() 20 | #include //closedir() 21 | #endif 22 | 23 | namespace mdk 24 | { 25 | 26 | Logger::Logger() 27 | { 28 | m_isInit = false; 29 | m_index = 0; 30 | m_maxExistDay = 30; 31 | m_maxLogSize = 50; 32 | m_runLogDir = ""; 33 | m_name = ""; 34 | m_bRLogOpened = false; 35 | m_fpRunLog = NULL; 36 | 37 | m_bPrint = false; 38 | m_exeDir = new char[2048]; 39 | GetExeDir(m_exeDir, 2048); 40 | } 41 | 42 | Logger::Logger(const char *name) 43 | { 44 | m_isInit = false; 45 | m_index = 0; 46 | m_maxExistDay = 30; 47 | m_maxLogSize = 50; 48 | m_runLogDir = ""; 49 | m_name = ""; 50 | SetLogName(name); 51 | m_bRLogOpened = false; 52 | m_fpRunLog = NULL; 53 | 54 | m_bPrint = false; 55 | if (NULL != m_exeDir) 56 | { 57 | delete[]m_exeDir; 58 | } 59 | } 60 | 61 | Logger::~Logger() 62 | { 63 | if (NULL != m_fpRunLog) 64 | { 65 | fclose(m_fpRunLog); 66 | m_fpRunLog = NULL; 67 | } 68 | } 69 | 70 | bool Logger::SetLogName(const char *name) 71 | { 72 | if (m_isInit) return false; 73 | if (NULL == name) m_name = ""; 74 | else m_name = name; 75 | return CreateLogDir(); 76 | } 77 | 78 | void Logger::SetMaxLogSize(int maxLogSize) 79 | { 80 | m_maxLogSize = maxLogSize; 81 | } 82 | 83 | bool Logger::CreateFreeDir(const char* dir) 84 | { 85 | if (-1 == access(dir, 0)) 86 | { 87 | #ifdef WIN32 88 | mkdir(dir); 89 | #else 90 | umask(0); 91 | if (0 > mkdir(dir, 0777)) 92 | { 93 | printf("create %s faild\n", dir); 94 | return false; 95 | } 96 | #endif 97 | } 98 | #ifndef WIN32 99 | umask(0); 100 | chmod(dir, S_IRWXU | S_IRWXG | S_IRWXO); 101 | #endif 102 | 103 | return true; 104 | } 105 | 106 | bool Logger::CreateLogDir() 107 | { 108 | if (m_isInit) return false; 109 | m_runLogDir = m_exeDir; 110 | m_runLogDir += "/log"; 111 | CreateFreeDir(m_runLogDir.c_str()); 112 | if ("" != m_name) m_runLogDir += "/" + m_name; 113 | else m_runLogDir += "/run"; 114 | CreateFreeDir(m_runLogDir.c_str()); 115 | m_isInit = true; 116 | return true; 117 | } 118 | 119 | void Logger::RenameMaxLog() 120 | { 121 | time_t cutTime = time(NULL); 122 | tm *pCurTM = localtime(&cutTime); 123 | char log[256]; 124 | 125 | std::string fromat = m_runLogDir + "/%Y-%m-%d.log"; 126 | strftime(log, 256, fromat.c_str(), pCurTM); 127 | unsigned long lsize = GetFileSize(log); 128 | if (lsize >= (unsigned long)(1024 * 1024 * m_maxLogSize)) 129 | { 130 | if (m_bRLogOpened) 131 | { 132 | fclose(m_fpRunLog); 133 | m_bRLogOpened = false; 134 | } 135 | m_index++; 136 | char maxLog[1024]; 137 | sprintf(maxLog, "%s.%d", log, m_index); 138 | rename(log, maxLog); 139 | } 140 | } 141 | 142 | bool Logger::OpenRunLog() 143 | { 144 | time_t cutTime = time(NULL); 145 | tm *pCurTM = localtime(&cutTime); 146 | if (m_bRLogOpened) 147 | { 148 | char strTime[256]; 149 | strftime(strTime, 30, "%Y-%m-%d", pCurTM); 150 | int nY, nM, nD; 151 | sscanf(strTime, "%d-%d-%d", &nY, &nM, &nD); 152 | if (m_nRunLogCurYear == nY && 153 | m_nRunLogCurMonth == nM && 154 | m_nRunLogCurDay == nD) return true; 155 | fclose(m_fpRunLog); 156 | m_fpRunLog = NULL; 157 | m_nRunLogCurYear = nY; 158 | m_nRunLogCurMonth = nM; 159 | m_nRunLogCurDay = nD; 160 | m_bRLogOpened = false; 161 | m_index = 0; 162 | } 163 | 164 | char strRunLog[256]; 165 | std::string fromat = m_runLogDir + "/%Y-%m-%d.log"; 166 | strftime(strRunLog, 256, fromat.c_str(), pCurTM); 167 | m_fpRunLog = fopen(strRunLog, "a"); 168 | m_bRLogOpened = NULL != m_fpRunLog; 169 | 170 | return m_bRLogOpened; 171 | } 172 | 173 | #ifdef WIN32 174 | time_t SystemTimeToTimet(SYSTEMTIME st) 175 | { 176 | FILETIME ft; 177 | SystemTimeToFileTime(&st, &ft); 178 | LONGLONG nLL; 179 | ULARGE_INTEGER ui; 180 | ui.LowPart = ft.dwLowDateTime; 181 | ui.HighPart = ft.dwHighDateTime; 182 | nLL = ((mdk::uint64)ft.dwHighDateTime << 32) + ft.dwLowDateTime; 183 | time_t pt = (long)((LONGLONG)(ui.QuadPart - 116444736000000000) / 10000000); 184 | return pt; 185 | } 186 | #else 187 | #include 188 | #include 189 | 190 | #endif 191 | 192 | 193 | void Logger::FindDelLog(char * path, int maxExistDay) 194 | { 195 | maxExistDay = 5; 196 | time_t curTime = mdk_Date(); 197 | curTime -= 86400 * (maxExistDay - 1); 198 | 199 | #ifdef WIN32 200 | char szFind[MAX_PATH]; 201 | char szFile[MAX_PATH]; 202 | WIN32_FIND_DATA FindFileData; 203 | time_t ftime; 204 | 205 | strcpy(szFind, path); 206 | strcat(szFind, "//*.*"); 207 | HANDLE hFind = ::FindFirstFile(szFind, &FindFileData); 208 | if (INVALID_HANDLE_VALUE == hFind) return; 209 | 210 | do 211 | { 212 | if (FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) 213 | { 214 | if (0 == strcmp(".", FindFileData.cFileName) 215 | || 0 == strcmp("..", FindFileData.cFileName)) continue; 216 | strcpy(szFile, path); 217 | strcat(szFile, "//"); 218 | strcat(szFile, FindFileData.cFileName); 219 | FindDelLog(szFile, maxExistDay); 220 | } 221 | else 222 | { 223 | SYSTEMTIME st; 224 | FileTimeToSystemTime(&FindFileData.ftLastWriteTime, &st); 225 | ftime = SystemTimeToTimet(st); 226 | if (ftime >= curTime) continue; 227 | std::string strRunLog = m_runLogDir + "//" + FindFileData.cFileName; 228 | remove(strRunLog.c_str()); 229 | } 230 | } while (FindNextFile(hFind, &FindFileData)); 231 | FindClose(hFind); 232 | #else 233 | DIR *pDir; 234 | struct dirent *ent; 235 | char childpath[512]; 236 | pDir = opendir(path); 237 | memset(childpath, 0, sizeof(childpath)); 238 | while (NULL != (ent = readdir(pDir))) 239 | { 240 | if (ent->d_type&DT_DIR) 241 | { 242 | if (0 == strcmp(".", ent->d_name) || 0 == strcmp("..", ent->d_name)) continue; 243 | sprintf(childpath, "%s/%s", path, ent->d_name); 244 | FindDelLog(childpath, maxExistDay); 245 | } 246 | else 247 | { 248 | std::string strRunLog = m_runLogDir + "//" + ent->d_name; 249 | struct stat buf; 250 | if (-1 == stat(strRunLog.c_str(), &buf)) continue; 251 | if (buf.st_ctime >= curTime) continue; 252 | remove(strRunLog.c_str()); 253 | } 254 | } 255 | closedir(pDir); 256 | #endif 257 | 258 | } 259 | 260 | void Logger::DelLog(int nDay) 261 | { 262 | FindDelLog((char*)m_runLogDir.c_str(), m_maxExistDay); 263 | } 264 | 265 | void Logger::SetPrintLog(bool bPrint) 266 | { 267 | m_bPrint = bPrint; 268 | } 269 | 270 | bool Logger::Info(const char *findKey, const char *format, ...) 271 | { 272 | AutoLock lock(&m_writeMutex); 273 | if (!m_isInit) 274 | { 275 | if (!SetLogName(NULL)) return m_isInit; 276 | } 277 | 278 | DelLog(m_maxExistDay); 279 | RenameMaxLog(); 280 | 281 | if (!OpenRunLog()) return false; 282 | //取得时间 283 | time_t cutTime = time(NULL); 284 | tm *pCurTM = localtime(&cutTime); 285 | char strTime[32]; 286 | strftime(strTime, 30, "%Y-%m-%d %H:%M:%S", pCurTM); 287 | //写入日志内容 288 | fprintf(m_fpRunLog, "%s Tid:%lu [%s] ", strTime, CurThreadId(), findKey); 289 | va_list ap; 290 | va_start(ap, format); 291 | vfprintf(m_fpRunLog, format, ap); 292 | va_end(ap); 293 | #ifdef WIN32 294 | fprintf(m_fpRunLog, "\n"); 295 | #else 296 | fprintf(m_fpRunLog, "\r\n"); 297 | #endif 298 | fflush(m_fpRunLog); 299 | 300 | //打印日志内容 301 | if (m_bPrint) 302 | { 303 | printf("%s Tid:%lu [%s] ", strTime, CurThreadId(), findKey); 304 | va_list ap; 305 | va_start(ap, format); 306 | vprintf(format, ap); 307 | va_end(ap); 308 | printf("\n"); 309 | } 310 | 311 | return true; 312 | } 313 | 314 | bool Logger::StreamInfo(const char *findKey, unsigned char *stream, int nLen, const char *format, ...) 315 | { 316 | AutoLock lock(&m_writeMutex); 317 | if (!m_isInit) 318 | { 319 | if (!SetLogName(NULL)) return m_isInit; 320 | } 321 | 322 | DelLog(m_maxExistDay); 323 | RenameMaxLog(); 324 | 325 | if (!OpenRunLog()) return false; 326 | //取得时间 327 | time_t cutTime = time(NULL); 328 | tm *pCurTM = localtime(&cutTime); 329 | char strTime[32]; 330 | strftime(strTime, 30, "%Y-%m-%d %H:%M:%S", pCurTM); 331 | //写入日志内容 332 | fprintf(m_fpRunLog, "%s Tid:%lu [%s] ", strTime, CurThreadId(), findKey); 333 | va_list ap; 334 | va_start(ap, format); 335 | vfprintf(m_fpRunLog, format, ap); 336 | va_end(ap); 337 | 338 | //打印日志内容 339 | if (m_bPrint) 340 | { 341 | printf("%s Tid:%lu [%s] ", strTime, CurThreadId(), findKey); 342 | va_list ap; 343 | va_start(ap, format); 344 | vprintf(format, ap); 345 | va_end(ap); 346 | } 347 | 348 | //写入流 349 | fprintf(m_fpRunLog, " stream:"); 350 | if (m_bPrint) printf(" stream:"); 351 | int i = 0; 352 | for (i = 0; i < nLen - 1; i++) 353 | { 354 | fprintf(m_fpRunLog, "%x,", stream[i]); 355 | if (m_bPrint) printf("%x,", stream[i]); 356 | } 357 | #ifdef WIN32 358 | fprintf(m_fpRunLog, "%x\n", stream[i]); 359 | #else 360 | fprintf(m_fpRunLog, "%x\r\n", stream[i]); 361 | #endif 362 | if (m_bPrint) printf("%x\n", stream[i]); 363 | fflush(m_fpRunLog); 364 | 365 | 366 | return true; 367 | } 368 | 369 | void Logger::SetMaxExistDay(int maxExistDay) 370 | { 371 | m_maxExistDay = maxExistDay; 372 | } 373 | 374 | }//namespace mdk 375 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /report/figure/paxos.svg: -------------------------------------------------------------------------------- 1 | 初始化//一阶段收到的最大流水号maxSerialNum=0;//推荐提案编号acceptedSerialNum=0;//推荐提案内容acceptedValue=0;创建提案[编号Serial, 内容Value]发送给所有Acceptor发送Accept请求[编号Serial, 内容Value]到所有给自己投票的Acceptor初始化//已被接受的提议中编号最大maxAcceptedSerialNum=0;//完成拉票,准备开始二阶段proposeFinished=false;//提议被批准isAgree=false;//投票数量,两阶段共okCount=0;//拒绝数量,两阶段共refuseCount=0;if(拒绝或者超时没有得到回复)if(拒绝数量超过Acceptor的一半)增大Serial,重新开始Propose阶段;if(acceptedSerialNum>maxAcceptedSerialNum)maxAcceptedSerialNum=acceptedSerialNum;Value=acceptedValue;if(同意数量超过Acceptor的一半)proposeFinished=true; //Propose阶段结束Proposer::Proposed()if(拒绝或者超时没有得到回复)if(拒绝数量超过Acceptor的一半)增大Serial,重新开始Propose阶段;if(同意数量超过Acceptor的一半)isAgree=true; //Accept阶段结束Proposer::Accepted()if(maxSerialNum>Serial)拒绝或者不回复elsemaxSerialNum=Serial;回复: OK,(acceptedSerialNum, acceptedValue)Acceptor::Propose()if(maxSerialNum>Serial)拒绝或者不回复elseacceptedSerialNum=Serial;acceptedValue=Value;回复: OKAcceptor::Accept()投票接受ProposerAcceptor开始结束 --------------------------------------------------------------------------------