├── Makefile ├── README.md ├── pic ├── client.jpg ├── client2.jpg └── server.jpg └── src ├── include ├── atomic.h ├── base.h ├── boundedQueue.h ├── condition.h ├── log.cc ├── log.h ├── mutex.h ├── thread.h └── threadPool.h ├── kvstore ├── kvClient.cc ├── kvClient.h ├── kvServer.cc └── kvServer.h ├── net ├── address.h ├── buffer.cc ├── buffer.h ├── callback.h ├── channel.cc ├── channel.h ├── connection.cc ├── connection.h ├── epoller.cc ├── epoller.h ├── eventLoop.cc ├── eventLoop.h ├── server.cc ├── server.h ├── sig.cc ├── sig.h ├── socket.cc ├── socket.h └── time.h ├── test ├── file │ ├── Makefile │ └── test.cc ├── kvstore │ ├── exp-client │ │ ├── Makefile │ │ └── exp-client.cc │ └── exp-server │ │ ├── Makefile │ │ └── exp-server.cc ├── threadPool │ ├── Makefile │ └── test.cc ├── timer │ ├── Makefile │ └── test.cc ├── tree │ ├── Makefile │ └── tree.cc └── web │ ├── client │ ├── Makefile │ └── webClient.cc │ └── server │ ├── Makefile │ └── webServer.cc └── tree ├── bPlusTree.cc ├── bPlusTree.h └── bPlusTreeBase.h /Makefile: -------------------------------------------------------------------------------- 1 | objects = channel.o epoller.o socket.o buffer.o log.o sig.o\ 2 | eventLoop.o connection.o server.o bPlusTree.o 3 | 4 | objects1 = exp-client.o kvClient.o $(objects) 5 | 6 | objects2 = exp-server.o kvServer.o $(objects) 7 | 8 | vpath %.cc net include tree kvstore 9 | vpath %exp-client.cc test/kvstore/exp-client 10 | vpath %exp-server.cc test/kvstore/exp-server 11 | 12 | all : exp-cli exp-srv 13 | .PHONY : all 14 | 15 | exp-cli : $(objects1) 16 | g++ $(objects1) -o exp-cli -lpthread 17 | 18 | exp-srv : $(objects2) 19 | g++ $(objects2) -o exp-srv -lpthread 20 | 21 | .PHONY : clean 22 | clean : 23 | -rm exp-cli exp-srv exp-client.o kvClient.o exp-server.o kvServer.o $(objects) 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Explorer 2 | Explorer is a key-value storage system with client and server. 3 | Explorer use B+ tree as storage engine. Client and server communicate using the TCP protocol. 4 | 5 | ## Compile 6 | make 7 | 8 | ## Example 9 | First, run the server program : 10 | ./exp-srv 11 | 12 | Then, run the client program : 13 | ./exp-cli 14 | 15 | Insert a key-value : 16 | > set  zx  1 17 | 18 | Search a key :  19 | > get  zx 20 | 21 | Update a key : 22 | > update  zx  2 23 | 24 | Delete a key : 25 | > del  zx 26 | 27 | Display the current status of the storage system : 28 | > stat 29 | 30 | Look for help : 31 | > h 32 | 33 | Quit from client : 34 | > q 35 | 36 | ## Attention 37 | By default, the key type is string and value type is int. 38 | All key-values store in one file named test.db, you can change the file name or file position in source file test/kvstore/exp-server/exp-server.cc. 39 | 40 | -------------------------------------------------------------------------------- /pic/client.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinx2016/Explorer/e5e2b67b87cfae7cbf483f4535eef8b6f5cca7b6/pic/client.jpg -------------------------------------------------------------------------------- /pic/client2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinx2016/Explorer/e5e2b67b87cfae7cbf483f4535eef8b6f5cca7b6/pic/client2.jpg -------------------------------------------------------------------------------- /pic/server.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zinx2016/Explorer/e5e2b67b87cfae7cbf483f4535eef8b6f5cca7b6/pic/server.jpg -------------------------------------------------------------------------------- /src/include/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_ATOMIC_H_ 2 | #define _EXPLORER_ATOMIC_H_ 3 | 4 | #include 5 | 6 | namespace Explorer { 7 | 8 | template 9 | class Atomic 10 | { 11 | public: 12 | Atomic() : val_(0) {} 13 | 14 | Atomic(const T& val) : val_(val) {} 15 | 16 | Atomic(const Atomic& x) 17 | { 18 | __sync_val_compare_and_swap(&val_, val_, x.val_); 19 | } 20 | 21 | T Get() 22 | { 23 | return __sync_val_compare_and_swap(&val_, 0, 0); 24 | } 25 | 26 | T GetAndAdd(T x) 27 | { 28 | return __sync_fetch_and_add(&val_, x); 29 | } 30 | 31 | T AddAndGet(T x) 32 | { 33 | return __sync_add_and_fetch(&val_, x); 34 | } 35 | 36 | T GetAndSub(T x) 37 | { 38 | return __sync_fetch_and_sub(&val_, x); 39 | } 40 | 41 | T SubAndGet(T x) 42 | { 43 | return __sync_sub_and_fetch(&val_, x); 44 | } 45 | 46 | T operator++(int) 47 | { 48 | return GetAndAdd(1); 49 | } 50 | 51 | T operator++() 52 | { 53 | return AddAndGet(1); 54 | } 55 | 56 | T operator--(int) 57 | { 58 | return GetAndSub(1); 59 | } 60 | 61 | T operator--() 62 | { 63 | return SubAndGet(1); 64 | } 65 | 66 | Atomic& operator=(const T& x) 67 | { 68 | __sync_val_compare_and_swap(&val_, val_, x); 69 | return *this; 70 | } 71 | 72 | private: 73 | volatile T val_; 74 | 75 | }; 76 | 77 | typedef Atomic AtomicInt8; 78 | typedef Atomic AtomicInt16; 79 | typedef Atomic AtomicInt32; 80 | typedef Atomic AtomicInt64; 81 | 82 | } // namespace Explorer 83 | 84 | #endif /*_EXPLORER_ATOMIC_H_*/ 85 | -------------------------------------------------------------------------------- /src/include/base.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_BASE_H_ 2 | #define _EXPLORER_BASE_H_ 3 | 4 | #include 5 | 6 | namespace Explorer { 7 | 8 | class NoCopy 9 | { 10 | public: 11 | NoCopy() = default; 12 | 13 | private: 14 | NoCopy(const NoCopy&) = delete; 15 | NoCopy& operator=(const NoCopy&) = delete; 16 | }; 17 | 18 | template 19 | class NoCopyTemplate 20 | { 21 | public: 22 | NoCopyTemplate() = default; 23 | 24 | private: 25 | NoCopyTemplate(const NoCopyTemplate& ) = delete; 26 | NoCopyTemplate& operator=(const NoCopyTemplate& ) = delete; 27 | }; 28 | 29 | typedef std::function Task; 30 | typedef std::function Func; 31 | 32 | } // namespace Explorer 33 | 34 | #endif // _EXPLORER_BASE_H_ 35 | -------------------------------------------------------------------------------- /src/include/boundedQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_WORK_QUEUE_H_ 2 | #define _EXPLORER_WORK_QUEUE_H_ 3 | 4 | #include "condition.h" 5 | #include 6 | 7 | namespace Explorer { 8 | 9 | template 10 | class BoundedQueue : private NoCopy 11 | { 12 | public: 13 | explicit BoundedQueue(int maxSize) 14 | : mutex_(), 15 | notEmpty_(), 16 | notFull_(), 17 | queue_(), 18 | maxSize_(maxSize), 19 | clear_(false) 20 | { } 21 | 22 | void Push(const T& x) 23 | { 24 | MutexGuard mtx(mutex_); 25 | while (queue_.size() == maxSize_) 26 | { 27 | notFull_.Wait(mutex_); 28 | } 29 | assert(!(queue_.size() == maxSize_)); 30 | queue_.push(x); 31 | notEmpty_.Signal(); 32 | } 33 | 34 | T Pop() 35 | { 36 | MutexGuard mtx(mutex_); 37 | while (queue_.empty() && !clear_) 38 | { 39 | notEmpty_.Wait(mutex_); 40 | } 41 | if (clear_) 42 | return T(); 43 | assert(!queue_.empty()); 44 | T ret(queue_.front()); 45 | queue_.pop(); 46 | notFull_.Signal(); 47 | return ret; 48 | } 49 | 50 | void Clear() 51 | { 52 | MutexGuard mtx(mutex_); 53 | clear_ = true; 54 | notEmpty_.BroadCast(); 55 | } 56 | 57 | int Size() 58 | { 59 | MutexGuard mtx(mutex_); 60 | return queue_.size(); 61 | } 62 | 63 | private: 64 | mutable Mutex mutex_; 65 | Condition notEmpty_; 66 | Condition notFull_; 67 | std::queue queue_; 68 | int maxSize_; 69 | bool clear_; 70 | }; 71 | 72 | } // namespace Explorer 73 | 74 | #endif /*_EXPLORER_BOUNDED_QUEUE_H_*/ 75 | -------------------------------------------------------------------------------- /src/include/condition.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_CONDITION_H_ 2 | #define _EXPLORER_CONDITION_H_ 3 | 4 | #include // ETIMEDOUT 5 | #include // timespec 6 | 7 | #include "base.h" 8 | #include "mutex.h" 9 | 10 | namespace Explorer { 11 | 12 | class Condition : private NoCopy 13 | { 14 | public: 15 | Condition() { assert(0 == pthread_cond_init(&cond_, 0)); } 16 | 17 | ~Condition() { assert(0 == pthread_cond_destroy(&cond_)); } 18 | 19 | void Wait(Mutex& mutex) { assert(0 == pthread_cond_wait(&cond_, 20 | mutex.GetMutex())); } 21 | 22 | void Signal() { assert(0 == pthread_cond_signal(&cond_)); } 23 | 24 | void BroadCast() { assert(0 == pthread_cond_broadcast(&cond_));} 25 | 26 | bool TimeWait(Mutex& mutex, double seconds) 27 | { 28 | struct timespec abstime; 29 | const int64_t nanoTimePerSecond = 1e9; 30 | int64_t nanoSeconds = static_cast(seconds * nanoTimePerSecond); 31 | 32 | struct timeval now; 33 | gettimeofday(&now, NULL); //系统不支持clock_gettime()函数 34 | abstime.tv_sec = now.tv_sec; 35 | abstime.tv_nsec = now.tv_usec * 1000; 36 | abstime.tv_sec += static_cast((abstime.tv_nsec + nanoSeconds) 37 | / nanoTimePerSecond); 38 | abstime.tv_nsec = static_cast((abstime.tv_nsec + nanoSeconds) 39 | % nanoTimePerSecond); 40 | 41 | return ETIMEDOUT == 42 | pthread_cond_timedwait(&cond_, mutex.GetMutex(), &abstime); 43 | 44 | } 45 | 46 | private: 47 | pthread_cond_t cond_; 48 | 49 | }; 50 | 51 | } // namespace Explorer 52 | 53 | #endif // _EXPLORER_CONDITION_H_ 54 | -------------------------------------------------------------------------------- /src/include/log.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "log.h" 5 | 6 | namespace Explorer { 7 | 8 | Logv::Logv() {} 9 | 10 | Logv& Logv::GetLogger() 11 | { 12 | static Logv log; 13 | return log; 14 | } 15 | 16 | void Logv::logv(const char* fmt ...) 17 | { 18 | char buf[1024]; 19 | char *p = buf; 20 | char *e = buf + sizeof(buf); 21 | va_list args; 22 | va_start(args, fmt); 23 | p += vsnprintf(p, e - p, fmt, args); 24 | va_end(args); 25 | *p++ = '\n'; 26 | *p++ = '\0'; 27 | printf("%s", buf); 28 | } 29 | 30 | } // namespace Explorer 31 | -------------------------------------------------------------------------------- /src/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_LOG_H_ 2 | #define _EXPLORER_LOG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Explorer { 9 | 10 | #define Info(...) Logv::GetLogger().logv(__VA_ARGS__) 11 | #define Warn(...) Logv::GetLogger().logv(__VA_ARGS__) 12 | #define Error(...) Logv::GetLogger().logv(__VA_ARGS__) 13 | #define Fatal(...) Logv::GetLogger().logv(__VA_ARGS__) 14 | #define ExitIf(b, ...) do {if (b) {Logv::GetLogger().logv(__VA_ARGS__); exit(0);}} while (0) 15 | #define FatalIf(b, ...) do {if (b) {Logv::GetLogger().logv(__VA_ARGS__); assert(0);}} while (0) 16 | 17 | class Logv 18 | { 19 | public: 20 | static Logv& GetLogger(); 21 | void logv(const char* fmt ...); 22 | 23 | private: 24 | Logv(); 25 | }; 26 | 27 | } // namespace Explorer 28 | 29 | #endif // _EXPLORER_LOG_H_ 30 | -------------------------------------------------------------------------------- /src/include/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_MUTEX_H_ 2 | #define _EXPLORER_MUTEX_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "base.h" 8 | 9 | namespace Explorer { 10 | 11 | class Condition; 12 | 13 | class Mutex : private NoCopy 14 | { 15 | public: 16 | friend class Condition; 17 | 18 | Mutex() { assert(0 == pthread_mutex_init(&mutex_, 0)); } 19 | 20 | ~Mutex() { assert(0 == pthread_mutex_destroy(&mutex_)); } 21 | 22 | void Lock() { assert(0 == pthread_mutex_lock(&mutex_)); } 23 | 24 | void Unlock() { assert(0 == pthread_mutex_unlock(&mutex_)); } 25 | 26 | pthread_mutex_t* GetMutex() { return &mutex_; } 27 | 28 | private: 29 | pthread_mutex_t mutex_; 30 | }; 31 | 32 | class MutexGuard : private NoCopy 33 | { 34 | public: 35 | MutexGuard(Mutex& mutex) 36 | : mutex_(mutex) 37 | { 38 | mutex_.Lock(); 39 | } 40 | 41 | ~MutexGuard() { mutex_.Unlock(); } 42 | 43 | private: 44 | Mutex& mutex_; 45 | }; 46 | 47 | } // namespace Explorer 48 | 49 | #endif // _EXPLORER_MUTEX_H_ 50 | -------------------------------------------------------------------------------- /src/include/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_THREAD_H_ 2 | #define _EXPLORER_THREAD_H_ 3 | 4 | #include 5 | 6 | #include "base.h" 7 | 8 | namespace Explorer { 9 | 10 | class Thread : private NoCopy 11 | { 12 | public: 13 | Thread(const Func& func) 14 | : func_(func) 15 | {} 16 | 17 | void Start() 18 | { 19 | std::thread tmp(func_); 20 | thread_.swap(tmp); 21 | } 22 | 23 | void Stop() { thread_.join(); } 24 | 25 | private: 26 | Func func_; 27 | std::thread thread_; 28 | }; 29 | 30 | } // namespace Explorer 31 | 32 | #endif // _EXPLORER_THREAD_H_ 33 | -------------------------------------------------------------------------------- /src/include/threadPool.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_THREAD_POOL_H_ 2 | #define _EXPLORER_THREAD_POOL_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "base.h" 8 | #include "atomic.h" 9 | #include "boundedQueue.h" 10 | #include "thread.h" 11 | 12 | /* 13 | * 设计思想 14 | * 让线程从阻塞队列中取出任务 15 | * 当队列为空时,线程阻塞,直到往队列中添加了新任务 16 | * 当队列为满时,线程阻塞,直到从队列中取走了任务 17 | */ 18 | 19 | namespace Explorer { 20 | 21 | template 22 | class ThreadPool : private NoCopyTemplate 23 | { 24 | public: 25 | ThreadPool(std::shared_ptr> queue, int threadNum); 26 | 27 | void Clear(); // 销毁阻塞在空队列上的线程 28 | 29 | private: 30 | void Run(); // 线程池中每个线程的执行函数 31 | 32 | private: 33 | AtomicInt8 working_; 34 | int threadNum_; 35 | std::shared_ptr> queue_; // 线程池取得工作任务的队列 36 | std::vector> threads_; 37 | }; 38 | 39 | template 40 | ThreadPool::ThreadPool(std::shared_ptr> queue, 41 | int threadNum) 42 | : working_(0), 43 | threadNum_(threadNum), 44 | queue_(queue) 45 | { 46 | // 线程数最大设为8 47 | if (threadNum_ <= 0) 48 | threadNum_ = 1; 49 | if (threadNum_ > 8) 50 | threadNum_ = 8; 51 | threads_.resize(threadNum_); 52 | for (int i = 0; i < threads_.size(); ++i) 53 | { 54 | // 创建线程 55 | threads_[i] = std::make_shared([this] {this->Run();}); 56 | // 启动线程 57 | threads_[i]->Start(); 58 | } 59 | working_ = 1; 60 | } 61 | 62 | template 63 | void ThreadPool::Run() 64 | { 65 | while (1) 66 | { 67 | // 从工作队列取出任务 68 | T task = queue_->Pop(); // 队列为空,则线程阻塞 69 | if (0 == working_.Get()) // 外部条件控制线程终止 70 | break; 71 | task(); // 执行任务 72 | } 73 | } 74 | 75 | template 76 | void ThreadPool::Clear() 77 | { 78 | if (!working_.Get()) 79 | return ; 80 | working_ = 0; 81 | queue_->Clear(); // 唤醒阻塞线程,并且使线程终止,销毁线程池 82 | for (int i = 0; i < threads_.size(); ++i) 83 | threads_[i]->Stop(); // 回收终止线程资源 84 | } 85 | 86 | } // namespace Explorer 87 | 88 | #endif // _EXPLORER_THREAD_POOL_H_ 89 | -------------------------------------------------------------------------------- /src/kvstore/kvClient.cc: -------------------------------------------------------------------------------- 1 | #include "kvClient.h" 2 | 3 | namespace Explorer { 4 | 5 | KvClient::KvClient(int threadNums, int queueMaxSize, uint16_t port, const char* ip) 6 | : loop_(std::make_shared(threadNums, queueMaxSize)), 7 | queue_(loop_->GetQueue()), 8 | con_(Address(port, ip), loop_->GetEpoller()), 9 | count_(0) 10 | {} 11 | 12 | void KvClient::RunDb() 13 | { 14 | Command(); 15 | 16 | // 客户端立即终止 17 | loop_->RunAfter(0, [this] {this->GetLoop()->Exit();}); 18 | } 19 | 20 | Connection& KvClient::GetConnection() 21 | { 22 | return con_; 23 | } 24 | 25 | std::shared_ptr KvClient::GetLoop() 26 | { 27 | return loop_; 28 | } 29 | 30 | void KvClient::Work() 31 | { 32 | con_.Send(buf_); 33 | } 34 | 35 | void KvClient::Command() 36 | { 37 | int time = 0; 38 | 39 | while(1) 40 | { 41 | int argNum; 42 | 43 | if (time == GetCount()) 44 | { 45 | std::cout << " > "; 46 | time++; 47 | } 48 | else 49 | continue ; 50 | 51 | GetInput(); 52 | argNum = input_.size(); 53 | 54 | if (argNum == 0) 55 | { 56 | --time; 57 | continue; 58 | } 59 | if (argNum == 1) 60 | { 61 | int ret = Helper(); 62 | if (ret == -1) 63 | return ; 64 | else if (ret == 1) 65 | continue ; 66 | else 67 | { 68 | --time; 69 | continue ; 70 | } 71 | } 72 | 73 | if (!strcasecmp(input_[0].c_str(), "set") || 74 | !strcasecmp(input_[0].c_str(), "get") || 75 | !strcasecmp(input_[0].c_str(), "del") || 76 | !strcasecmp(input_[0].c_str(), "update")) 77 | { 78 | if (CheckCommand()) 79 | queue_->Push([this] {this->Work();}); 80 | else 81 | { 82 | --time; 83 | continue ; 84 | } 85 | } 86 | else 87 | { 88 | --time; 89 | printf(" Command Error. Use \"h\" for help.\n"); 90 | } 91 | } 92 | } 93 | 94 | void KvClient::GetInput() 95 | { 96 | std::string in, arg; 97 | 98 | getline(std::cin, in); 99 | std::stringstream ss(in); 100 | 101 | const char* tmp = in.c_str(); 102 | buf_.Clear(); 103 | buf_.Append(tmp, strlen(tmp)); 104 | 105 | input_.clear(); 106 | while (ss >> arg) 107 | input_.push_back(arg); 108 | } 109 | 110 | void KvClient::Help() 111 | { 112 | printf(" -----------Help Document-----------\n"); 113 | printf(" commands below are case insensitive\n\n"); 114 | printf(" set key value\n"); 115 | printf(" get key\n"); 116 | printf(" get lkey rkey\n"); 117 | printf(" update key value\n"); 118 | printf(" del key\n"); 119 | printf(" stat\n"); 120 | printf(" q\n"); 121 | printf(" quit\n"); 122 | printf(" h\n"); 123 | printf(" ----------------END----------------\n"); 124 | printf("\n"); 125 | } 126 | 127 | int KvClient::Helper() 128 | { 129 | if (!strcasecmp(input_[0].c_str(), "q") || 130 | !strcasecmp(input_[0].c_str(), "quit")) 131 | return -1; 132 | else if (!strcasecmp(input_[0].c_str(), "stat")) 133 | { 134 | queue_->Push([this] {this->Work();}); 135 | return 1; 136 | } 137 | else if (!strcasecmp(input_[0].c_str(), "h")) 138 | Help(); 139 | else if (!strcasecmp(input_[0].c_str(), "set") || 140 | !strcasecmp(input_[0].c_str(), "get") || 141 | !strcasecmp(input_[0].c_str(), "del") || 142 | !strcasecmp(input_[0].c_str(), "update") || 143 | !strcasecmp(input_[0].c_str(), "get")) 144 | printf(" Argument Error. Use \"h\" for help.\n"); 145 | else 146 | printf(" Command Error. Use \"h\" for help.\n"); 147 | return 0; 148 | } 149 | 150 | bool KvClient::CheckCommand() 151 | { 152 | int argNum = input_.size(); 153 | if (!strcasecmp(input_[0].c_str(), "set")) 154 | { 155 | if (argNum == 3) 156 | return true; 157 | } 158 | else if (!strcasecmp(input_[0].c_str(), "get")) 159 | { 160 | if (argNum == 2 || argNum == 3) 161 | return true; 162 | } 163 | else if (!strcasecmp(input_[0].c_str(), "del")) 164 | { 165 | if (argNum == 2) 166 | return true; 167 | 168 | } 169 | else // "update" 170 | { 171 | if (argNum == 3) 172 | return true; 173 | } 174 | printf(" Argument Error. Use \"h\" for help.\n"); 175 | return false; 176 | } 177 | 178 | void KvClient::IncCount() 179 | { 180 | ++count_; 181 | } 182 | 183 | uint16_t KvClient::GetCount() 184 | { 185 | return count_.Get(); 186 | } 187 | 188 | } // namespace Explorer 189 | -------------------------------------------------------------------------------- /src/kvstore/kvClient.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_KV_CLIENT_H_ 2 | #define _EXPLORER_KV_CLIENT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../tree/bPlusTree.h" 11 | #include "../net/eventLoop.h" 12 | #include "../net/sig.h" 13 | #include "../net/connection.h" 14 | #include "../include/log.h" 15 | #include "../include/thread.h" 16 | #include "../include/boundedQueue.h" 17 | #include "../include/atomic.h" 18 | 19 | namespace Explorer { 20 | 21 | class KvClient 22 | { 23 | public: 24 | KvClient(int threadNums, int queueMaxSize, 25 | uint16_t port = 8000, const char* ip = "127.0.0.1"); 26 | 27 | void RunDb(); 28 | 29 | Connection& GetConnection(); 30 | 31 | std::shared_ptr GetLoop(); 32 | 33 | void IncCount(); 34 | 35 | uint16_t GetCount(); 36 | 37 | private: 38 | void Work(); 39 | 40 | void Command(); 41 | 42 | void GetInput(); 43 | 44 | bool CheckCommand(); 45 | 46 | void Help(); 47 | 48 | int Helper(); 49 | 50 | 51 | private: 52 | std::shared_ptr loop_; 53 | std::shared_ptr> queue_; 54 | Connection con_; 55 | 56 | std::vector input_; 57 | Buffer buf_; 58 | AtomicInt16 count_; 59 | }; 60 | 61 | } // namespace Explorer 62 | 63 | #endif // _EXPLORER_KV_CLIENT_H_ 64 | -------------------------------------------------------------------------------- /src/kvstore/kvServer.cc: -------------------------------------------------------------------------------- 1 | #include "kvServer.h" 2 | 3 | namespace Explorer { 4 | 5 | KvServer::KvServer(int threadNums, int queueMaxSize, const char* filePath) 6 | : loop_(std::make_shared(threadNums, queueMaxSize)), 7 | queue_(loop_->GetQueue()), 8 | db_(filePath) 9 | { } 10 | 11 | void KvServer::GetArg(std::shared_ptr con, Buffer& input) 12 | { 13 | std::string in(input.BeginRead()); 14 | std::stringstream ss(in); 15 | std::string arg; 16 | while (ss >> arg) 17 | arg_.push_back(arg); 18 | input.Clear(); 19 | 20 | con_ = con; 21 | } 22 | 23 | std::shared_ptr KvServer::GetLoop() 24 | { 25 | return loop_; 26 | } 27 | 28 | 29 | void KvServer::RunDb() 30 | { 31 | while (1) 32 | { 33 | if (arg_.empty()) 34 | continue ; 35 | 36 | if (!strcasecmp(arg_[0].c_str(), "get")) 37 | { 38 | queue_->Push([this] {this->Search();}); 39 | } 40 | else if (!strcasecmp(arg_[0].c_str(), "set")) 41 | { 42 | queue_->Push([this] {this->Insert();}); 43 | } 44 | else if (!strcasecmp(arg_[0].c_str(), "update")) 45 | { 46 | queue_->Push([this] {this->Update();}); 47 | } 48 | else if (!strcasecmp(arg_[0].c_str(), "del")) 49 | { 50 | queue_->Push([this] {this->Del();}); 51 | } 52 | else // "stat" 53 | { 54 | queue_->Push([this] {this->Stat();}); 55 | } 56 | } 57 | 58 | } 59 | 60 | 61 | void KvServer::Insert() 62 | { 63 | char rep[512]; 64 | 65 | if (db_.Insert(arg_[1].c_str(), atoi(arg_[2].c_str())) != 0) 66 | sprintf(rep, " Key Already Exist.\n"); 67 | else 68 | sprintf(rep, " OK.\n"); 69 | buf_.Append(rep, strlen(rep)); 70 | con_->Send(buf_); 71 | arg_.clear(); 72 | } 73 | 74 | void KvServer::Update() 75 | { 76 | char rep[512]; 77 | 78 | if (db_.Update(arg_[1].c_str(), atoi(arg_[2].c_str())) != 0) 79 | sprintf(rep, " Key Not Exist.\n"); 80 | else 81 | sprintf(rep, " OK.\n"); 82 | buf_.Append(rep, strlen(rep)); 83 | con_->Send(buf_); 84 | arg_.clear(); 85 | } 86 | 87 | void KvServer::Del() 88 | { 89 | char rep[512]; 90 | 91 | if (db_.Remove(arg_[1].c_str()) != 0) 92 | sprintf(rep, " Key Not Found.\n"); 93 | else 94 | sprintf(rep, " OK.\n"); 95 | buf_.Append(rep, strlen(rep)); 96 | con_->Send(buf_); 97 | arg_.clear(); 98 | } 99 | 100 | void KvServer::Search() 101 | { 102 | char rep[512]; 103 | 104 | if (arg_.size() == 2) 105 | { 106 | valueType value; 107 | if (db_.Search(arg_[1].c_str(), &value) != 0) 108 | sprintf(rep, " Key Not Found.\n"); 109 | else 110 | sprintf(rep, " %d\n", value); 111 | buf_.Append(rep, strlen(rep)); 112 | con_->Send(buf_); 113 | } 114 | else // argNum == 3 115 | { 116 | keyType start(arg_[1].c_str()); 117 | valueType values[512]; 118 | bool next = true; 119 | while (next) 120 | { 121 | int ret = db_.SearchRange(&start, 122 | arg_[2].c_str(), 123 | values, 124 | 512, 125 | &next); 126 | if (ret <= 0) 127 | { 128 | sprintf(rep, " Key Not Found.\n"); 129 | buf_.Append(rep, strlen(rep)); 130 | con_->Send(buf_); 131 | 132 | return ; 133 | } 134 | for (int i = 0; i < ret; ++i) 135 | sprintf(rep + strlen(rep), " %d\n", values[i]); 136 | buf_.Append(rep, strlen(rep)); 137 | con_->Send(buf_); 138 | } 139 | } 140 | arg_.clear(); 141 | } 142 | 143 | void KvServer::Stat() 144 | { 145 | char rep[512]; 146 | 147 | meta metdt = db_.GetMeta(); 148 | sprintf(rep, " Order : %d\n", metdt.order); 149 | sprintf(rep + strlen(rep), " ValueSize : %d\n", metdt.valueSize); 150 | sprintf(rep + strlen(rep), " KeySize : %d\n", metdt.keySize); 151 | sprintf(rep + strlen(rep), " InternalNode : %d\n", metdt.internalNodeNum); 152 | sprintf(rep + strlen(rep), " LeafNode : %d\n", metdt.leafNodeNum); 153 | sprintf(rep + strlen(rep), " Height : %d\n", metdt.height); 154 | sprintf(rep + strlen(rep), " OffSet : %d\n", metdt.slot); 155 | 156 | buf_.Append(rep, strlen(rep)); 157 | con_->Send(buf_); 158 | 159 | arg_.clear(); 160 | } 161 | 162 | } // namespace Explorer 163 | -------------------------------------------------------------------------------- /src/kvstore/kvServer.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_KV_SERVER_H_ 2 | #define _EXPLORER_KV_SERVER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../net/eventLoop.h" 16 | #include "../net/buffer.h" 17 | #include "../net/connection.h" 18 | #include "../include/boundedQueue.h" 19 | #include "../tree/bPlusTree.h" 20 | 21 | namespace Explorer { 22 | 23 | class KvServer 24 | { 25 | public: 26 | KvServer(int threadNums, int queueMaxSize, const char* filePath); 27 | 28 | void GetArg(std::shared_ptr con, Buffer& input); 29 | 30 | std::shared_ptr GetLoop(); 31 | 32 | void RunDb(); 33 | 34 | private: 35 | void Insert(); 36 | void Update(); 37 | void Del(); 38 | void Search(); 39 | void Stat(); 40 | 41 | private: 42 | std::shared_ptr loop_; 43 | std::shared_ptr con_; 44 | std::shared_ptr> queue_; 45 | 46 | BPlusTree db_; 47 | Buffer buf_; 48 | std::vector arg_; 49 | }; 50 | 51 | } // namespace Explorer 52 | 53 | #endif // _EXPLORER_KV_SERVER_H_ 54 | -------------------------------------------------------------------------------- /src/net/address.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_ADDRESS_H_ 2 | #define _EXPLORER_ADDRESS_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Explorer { 9 | 10 | class Address 11 | { 12 | public: 13 | Address(uint16_t port, uint32_t ip) : port_(port), ip_(ip) {} 14 | 15 | Address(uint16_t port, const char* ip) : port_(port) 16 | { 17 | assert(0 != inet_pton(AF_INET, ip, &ip_)); 18 | } 19 | 20 | 21 | uint16_t Port() const { return port_; } 22 | 23 | uint32_t Ip() const { return ip_; } 24 | 25 | std::string ToString() const 26 | { 27 | char buf[MaxLen]; 28 | assert(inet_ntop(AF_INET, &ip_, buf, MaxLen)); 29 | return std::string(buf) + " port " + std::to_string(port_); 30 | } 31 | 32 | private: 33 | static const uint32_t MaxLen = 16; 34 | uint16_t port_; 35 | uint32_t ip_; 36 | }; 37 | 38 | } // namespace Explorer 39 | 40 | #endif // _EXPLORER_ADDRESS_H_ 41 | -------------------------------------------------------------------------------- /src/net/buffer.cc: -------------------------------------------------------------------------------- 1 | #include "buffer.h" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace Explorer { 7 | 8 | ssize_t 9 | Buffer::Read(int fd, int* savedErrno) 10 | { 11 | char extrabuf[65536]; // 64KB 12 | struct iovec vec[2]; 13 | vec[0].iov_base = Begin() + writerIndex_; 14 | vec[0].iov_len = WritableBytes(); 15 | vec[1].iov_base = extrabuf; 16 | vec[1].iov_len = sizeof(extrabuf); 17 | 18 | ssize_t n = readv(fd, vec, 2); // 分散读 19 | if ( n < 0) 20 | *savedErrno = errno; 21 | else if ( n < WritableBytes()) // 优先读到buffer_里 22 | writerIndex_ += n; 23 | else 24 | { 25 | writerIndex_ = buffer_.size(); // buffer_写满 26 | Append(extrabuf, n - WritableBytes()); // 剩下的追加到buffer_后 27 | } 28 | return n; 29 | } 30 | 31 | size_t 32 | Buffer::ReadableBytes() const 33 | { 34 | return writerIndex_ - readerIndex_; 35 | } 36 | 37 | size_t 38 | Buffer::WritableBytes() const 39 | { 40 | return buffer_.size() - writerIndex_; 41 | } 42 | 43 | size_t 44 | Buffer::PrependableBytes() const 45 | { 46 | return readerIndex_; 47 | } 48 | 49 | char* 50 | Buffer::BeginRead() const 51 | { 52 | return const_cast(&*buffer_.begin()) + readerIndex_; 53 | } 54 | 55 | char* 56 | Buffer::BeginWrite() const 57 | { 58 | return const_cast(&*buffer_.begin()) + writerIndex_; 59 | } 60 | 61 | char* 62 | Buffer::Begin() const 63 | { 64 | return const_cast(&*buffer_.begin()) + PrependSize; 65 | } 66 | 67 | void 68 | Buffer::RetriveMove(size_t len) 69 | { 70 | assert(len <= ReadableBytes()); 71 | if (len < ReadableBytes()) 72 | { 73 | readerIndex_ += len; 74 | } 75 | else 76 | { 77 | readerIndex_ = PrependSize; 78 | writerIndex_ = PrependSize; 79 | } 80 | } 81 | 82 | void 83 | Buffer::Retrive(char* data, size_t len) 84 | { 85 | assert(len <= ReadableBytes()); 86 | std::copy(BeginRead(), BeginRead() + len, data); 87 | RetriveMove(len); 88 | } 89 | 90 | void 91 | Buffer::Retrive(void* data, size_t len) 92 | { 93 | Retrive(static_cast(data), len); 94 | } 95 | 96 | void 97 | Buffer::Append(const char* data, size_t len) 98 | { 99 | if (len > WritableBytes()) 100 | { 101 | if (WritableBytes() + PrependableBytes() < len + PrependSize) 102 | { 103 | // 扩充Buffer 104 | buffer_.resize(writerIndex_ + len); 105 | } 106 | else // 利用头部预留空间 107 | { 108 | // 移动已使用内存起始位置到PrependSize 109 | size_t len = ReadableBytes(); 110 | std::copy(BeginRead(), BeginWrite(), Begin()); 111 | readerIndex_ = PrependSize; 112 | writerIndex_ = readerIndex_ + len; 113 | } 114 | assert(WritableBytes() >= len); 115 | } 116 | std::copy(data, data + len, BeginWrite()); 117 | writerIndex_ += len; 118 | } 119 | 120 | void 121 | Buffer::Append(const void* data, size_t len) 122 | { 123 | Append(static_cast(data), len); 124 | } 125 | 126 | void 127 | Buffer::Prepend(const void* data, size_t len) 128 | { 129 | assert(len <= PrependableBytes()); 130 | readerIndex_ -= len; 131 | const char* position = static_cast(data); 132 | std::copy(position, position + len, BeginRead()); 133 | } 134 | 135 | void 136 | Buffer::Clear() 137 | { 138 | readerIndex_ = writerIndex_ = PrependSize; 139 | buffer_.clear(); 140 | buffer_.resize(PrependSize + InitialSize); 141 | } 142 | 143 | void 144 | Buffer::Unget(size_t len) 145 | { 146 | MoveReaderIndex(-len); 147 | } 148 | 149 | void Buffer::MoveWriterIndex(ssize_t len) 150 | { 151 | if (len > 0) 152 | { 153 | size_t size = len < WritableBytes() ? len : WritableBytes(); 154 | writerIndex_ += size; 155 | } 156 | else 157 | { 158 | size_t size = (-len) < (ReadableBytes() + PrependableBytes()) ? 159 | (-len) : (ReadableBytes() + PrependableBytes()); 160 | writerIndex_ -= size; 161 | if (writerIndex_ < readerIndex_) 162 | readerIndex_ = writerIndex_; 163 | } 164 | } 165 | 166 | void Buffer::MoveReaderIndex(ssize_t len) 167 | { 168 | if (len > 0) 169 | { 170 | size_t size = (len) < (ReadableBytes() + WritableBytes()) ? 171 | (len) : (ReadableBytes() + WritableBytes()); 172 | readerIndex_ += size; 173 | } 174 | else 175 | { 176 | size_t size = (-len) < PrependableBytes() ? (-len) : PrependableBytes(); 177 | readerIndex_ -= size; 178 | } 179 | 180 | } 181 | 182 | } // namespace Explorer 183 | -------------------------------------------------------------------------------- /src/net/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_BUFFER_H_ 2 | #define _EXPLORER_BUFFER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Explorer { 10 | 11 | class Buffer 12 | { 13 | public: 14 | static const size_t InitialSize = 1024; 15 | static const size_t PrependSize = 8; 16 | 17 | explicit Buffer(size_t initialSize = InitialSize) 18 | : buffer_(PrependSize + initialSize), 19 | readerIndex_(PrependSize), 20 | writerIndex_(PrependSize) 21 | { } 22 | 23 | ssize_t Read(int fd, int* savedErrno); 24 | 25 | size_t ReadableBytes() const; 26 | 27 | size_t WritableBytes() const; 28 | 29 | size_t PrependableBytes() const; 30 | 31 | char* BeginRead() const; 32 | 33 | char* BeginWrite() const; 34 | 35 | char* Begin() const; 36 | 37 | void RetriveMove(size_t len); 38 | 39 | // 从Buffer提取数据到data 40 | void Retrive(char* data, size_t len); 41 | 42 | void Retrive(void* data, size_t len); 43 | 44 | // 追加写数据到Buffer 45 | void Append(const char* data, size_t len); 46 | 47 | void Append(const void* data, size_t len); 48 | 49 | // 写数据到Buffer的beginRead()-len到beginRead() 50 | void Prepend(const void* data, size_t len); 51 | 52 | void Clear(); 53 | 54 | void Unget(size_t len); 55 | 56 | void MoveWriterIndex(ssize_t len); 57 | 58 | void MoveReaderIndex(ssize_t len); 59 | 60 | private: 61 | std::vector buffer_; 62 | size_t readerIndex_; 63 | size_t writerIndex_; 64 | }; 65 | 66 | } // namespace Explorer 67 | 68 | #endif /*_EXPLORER_BUFFER_H_*/ 69 | -------------------------------------------------------------------------------- /src/net/callback.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_CALLBACK_H_ 2 | #define _EXPLORER_CALLBACK_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace Explorer { 8 | 9 | class Connection; 10 | 11 | typedef std::function ReadCallback; 12 | typedef std::function WriteCallback; 13 | typedef std::function)> ConnectCallback; 14 | 15 | } // namespace Explorer 16 | 17 | #endif // _EXPLORER_CALLBACK_H_ 18 | -------------------------------------------------------------------------------- /src/net/channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "channel.h" 4 | #include "epoller.h" 5 | 6 | namespace Explorer { 7 | 8 | Channel::Channel(int fd, std::shared_ptr epoller, 9 | const ReadCallback& readCb, const WriteCallback& writeCb) 10 | : fd_(fd), 11 | epoller_(epoller), 12 | readCb_(readCb), 13 | writeCb_(writeCb) 14 | { 15 | events_ = ReadEvent; 16 | epoller_->AddChannel(this); // 创建Channel时,即向Epoller注册描述符 17 | } 18 | 19 | Channel::~Channel() 20 | { 21 | // 从Epoller移除Channel 22 | epoller_->RemoveChannel(this); 23 | 24 | close(fd_); // 在这里关闭套接字,而不是在connection的析构函数关闭 25 | } 26 | 27 | int Channel::Fd() const 28 | { 29 | return fd_; 30 | } 31 | 32 | uint32_t Channel::Events() const 33 | { 34 | return events_; 35 | } 36 | 37 | bool Channel::ReadReady() const 38 | { 39 | return events_ & ReadEvent; 40 | } 41 | 42 | bool Channel::WriteReady() const 43 | { 44 | return events_ & WriteEvent; 45 | } 46 | 47 | void Channel::SetReadCallback(const ReadCallback& readCb) 48 | { 49 | readCb_ = readCb; 50 | } 51 | 52 | void Channel::SetWriteCallback(const WriteCallback& writeCb) 53 | { 54 | writeCb_ = writeCb; 55 | } 56 | 57 | void Channel::EnableRead(bool flag) 58 | { 59 | if (flag) 60 | events_ |= ReadEvent; 61 | else 62 | events_ &= ~ReadEvent; 63 | epoller_->UpdateChannel(this); 64 | } 65 | 66 | void Channel::EnableWrite(bool flag) 67 | { 68 | if (flag) 69 | events_ |= WriteEvent; 70 | else 71 | events_ &= ~WriteEvent; 72 | epoller_->UpdateChannel(this); 73 | } 74 | 75 | void Channel::HandleRead() 76 | { 77 | readCb_(); 78 | } 79 | 80 | void Channel::HandleWrite() 81 | { 82 | writeCb_(); 83 | } 84 | 85 | } // namespace Explorer 86 | -------------------------------------------------------------------------------- /src/net/channel.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_CHANNEL_H_ 2 | #define _EXPLORER_CHANNEL_H_ 3 | 4 | #include 5 | 6 | #include "../include/base.h" 7 | #include "callback.h" 8 | 9 | namespace Explorer { 10 | 11 | class Epoller; 12 | 13 | class Channel : private NoCopy 14 | { 15 | public: 16 | friend class Connection; 17 | 18 | Channel(int fd, std::shared_ptr epoller, 19 | const ReadCallback& readCb, const WriteCallback& writeCb); 20 | ~Channel(); 21 | 22 | int Fd() const; 23 | uint32_t Events() const; 24 | bool ReadReady() const; 25 | bool WriteReady() const; 26 | 27 | void SetReadCallback(const ReadCallback& readCb); 28 | void SetWriteCallback(const WriteCallback& writeCb); 29 | void EnableRead(bool flag); 30 | void EnableWrite(bool flag); 31 | 32 | void HandleRead(); 33 | void HandleWrite(); 34 | 35 | private: 36 | int fd_; 37 | uint32_t events_; 38 | std::shared_ptr epoller_; 39 | ReadCallback readCb_; 40 | WriteCallback writeCb_; 41 | }; 42 | 43 | } // namespace Explorer 44 | 45 | #endif // _EXPLORER_CHANNEL_H_ 46 | -------------------------------------------------------------------------------- /src/net/connection.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "connection.h" 7 | #include "epoller.h" 8 | #include "channel.h" 9 | 10 | namespace Explorer { 11 | 12 | // 服务器端用 13 | Connection::Connection(const Socket& socket, std::shared_ptr epoller) 14 | : socket_(socket), 15 | readCb_(nullptr), 16 | writeCb_(nullptr) 17 | { 18 | assert(socket_.SetNonBlock()); // socket已连接 19 | channel_ = std::make_shared(socket.Fd(), epoller, 20 | [this]() {this->HandleRead();}, 21 | [this]() {this->HandleWrite();}); 22 | connected_ = true; 23 | } 24 | 25 | // 客户端用 26 | Connection::Connection(const Address& server, std::shared_ptr epoller) 27 | : readCb_(nullptr), 28 | writeCb_(nullptr) 29 | { 30 | assert(socket_.Create()); 31 | if (!socket_.Connect(server)) 32 | { 33 | printf("socket connect server %s failed : %s\n", 34 | server.ToString().c_str(), strerror(errno)); 35 | return ; 36 | } 37 | assert(socket_.SetNonBlock()); 38 | channel_ = std::make_shared(socket_.Fd(), epoller, 39 | [this] {this->HandleRead();}, 40 | [this] {this->HandleWrite();}); 41 | connected_ = true; 42 | } 43 | 44 | Connection::~Connection() 45 | { 46 | // 关闭注册在Connection上Channel的套接字 47 | // 这里关闭套接字后,会导致析构其成员Channel对象时,RemoveChannel没有套接字而出错 48 | // 所以,关闭套接字可以移到Channel的析构函数进行 49 | //Close(); 50 | } 51 | 52 | 53 | Buffer& Connection::GetInput() 54 | { 55 | return input_; 56 | } 57 | 58 | Buffer& Connection::GetOutput() 59 | { 60 | return output_; 61 | } 62 | 63 | 64 | void Connection::HandleRead() 65 | { 66 | if (!connected_) 67 | { 68 | printf("connection not open\n"); 69 | return ; 70 | } 71 | bool blocked = false; 72 | Buffer buf; 73 | uint32_t read = socket_.Read(buf.BeginWrite(), 74 | buf.WritableBytes(), 75 | &blocked); 76 | input_.Clear(); 77 | input_.Append(buf.BeginRead(), read); 78 | if (!read && !blocked) 79 | { 80 | Close(); 81 | return ; 82 | } 83 | if (readCb_ && read) 84 | readCb_(); // 调用由用户设置的描述符可读的回调函数 85 | } 86 | 87 | void Connection::HandleWrite() 88 | { 89 | if (!connected_) 90 | { 91 | printf("connection not open\n"); 92 | return ; 93 | } 94 | output_.Clear(); 95 | bool blocked = false; 96 | uint32_t write = socket_.Write(output_.BeginRead(), 97 | output_.ReadableBytes(), 98 | &blocked); 99 | if (!write && !blocked) 100 | { 101 | Close(); 102 | return ; 103 | } 104 | output_.RetriveMove(write); 105 | if (output_.ReadableBytes() == 0) 106 | { 107 | if (writeCb_) 108 | writeCb_(); 109 | if (channel_->WriteReady()) 110 | channel_->EnableWrite(false); 111 | } 112 | } 113 | 114 | void Connection::SetReadCallback(const ReadCallback& cb) 115 | { 116 | readCb_ = cb; 117 | } 118 | 119 | void Connection::SetWriteCallback(const ReadCallback& cb) 120 | { 121 | writeCb_ = cb; 122 | } 123 | 124 | 125 | // 服务器在已连接套接字可读时,发送数据给客户端 126 | void Connection::Send(Buffer& buffer) 127 | { 128 | output_.Append(buffer.BeginRead(), buffer.ReadableBytes()); 129 | buffer.Clear(); 130 | SendOutput(); 131 | } 132 | 133 | void Connection::Send(const char* buf) 134 | { 135 | Send(buf, strlen(buf)); 136 | } 137 | 138 | void Connection::Send(const char* buf, uint32_t len) 139 | { 140 | output_.Append(buf, len); 141 | SendOutput(); 142 | } 143 | 144 | void Connection::SendOutput() 145 | { 146 | if (!connected_) 147 | { 148 | output_.Clear(); 149 | return ; 150 | } 151 | bool blocked = false; 152 | uint32_t write = socket_.Write(output_.BeginRead(), 153 | output_.ReadableBytes(), 154 | &blocked); 155 | if (!write && !blocked) 156 | { 157 | Close(); 158 | return ; 159 | } 160 | output_.RetriveMove(write); 161 | } 162 | 163 | bool Connection::Success() const 164 | { 165 | return connected_; 166 | } 167 | 168 | bool Connection::Close() 169 | { 170 | if (socket_.Valid()) 171 | { 172 | connected_ = false; 173 | return socket_.Close(); 174 | } 175 | return true; 176 | } 177 | 178 | } // namespace Explorer 179 | -------------------------------------------------------------------------------- /src/net/connection.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_CONNECTION_H_ 2 | #define _EXPLORER_CONNECTION_H_ 3 | 4 | #include 5 | 6 | #include "../include/base.h" 7 | #include "callback.h" 8 | #include "address.h" 9 | #include "socket.h" 10 | #include "buffer.h" 11 | 12 | namespace Explorer { 13 | 14 | class Channel; 15 | class Epoller; 16 | 17 | class Connection : private NoCopy 18 | { 19 | public: 20 | Connection(const Socket& socket, std::shared_ptr epoller); 21 | Connection(const Address& server, std::shared_ptr epoller); 22 | ~Connection(); 23 | 24 | Buffer& GetInput(); 25 | Buffer& GetOutput(); 26 | 27 | void HandleRead(); 28 | void HandleWrite(); 29 | void SetReadCallback(const ReadCallback& cb); 30 | void SetWriteCallback(const ReadCallback& cb); 31 | 32 | void Send(Buffer& buffer); 33 | void Send(const char* buf); 34 | void Send(const char* buf, uint32_t len); 35 | void SendOutput(); 36 | 37 | bool Success() const; 38 | bool Close(); 39 | 40 | 41 | protected: 42 | bool connected_; 43 | 44 | Buffer input_; 45 | Buffer output_; 46 | 47 | Socket socket_; // 已连接套接字 48 | std::shared_ptr channel_; 49 | 50 | ReadCallback readCb_; 51 | WriteCallback writeCb_; 52 | }; 53 | 54 | } // namespace Explorer 55 | 56 | #endif // _EXPLORER_CONNECTION_H_ 57 | -------------------------------------------------------------------------------- /src/net/epoller.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "epoller.h" 5 | #include "channel.h" 6 | #include "../include/log.h" 7 | 8 | namespace Explorer { 9 | 10 | Epoller::Epoller() 11 | : events_(MaxEvents) 12 | { 13 | FatalIf((fd_ = epoll_create1(EPOLL_CLOEXEC)) < 0, 14 | "epoll create failed, %s", strerror(errno)); 15 | } 16 | 17 | Epoller::~Epoller() 18 | { 19 | close(fd_); 20 | } 21 | 22 | void Epoller::AddChannel(Channel* channel) 23 | { 24 | struct epoll_event event; 25 | memset(&event, 0, sizeof(event)); 26 | event.events = channel->Events(); 27 | event.data.ptr = channel; 28 | FatalIf(epoll_ctl(fd_, EPOLL_CTL_ADD, channel->Fd(), &event), 29 | "epoll add event failed, %s", strerror(errno)); 30 | } 31 | 32 | void Epoller::RemoveChannel(Channel* channel) 33 | { 34 | struct epoll_event event; 35 | memset(&event, 0, sizeof(event)); 36 | event.events = channel->Events(); 37 | event.data.ptr = channel; 38 | FatalIf(epoll_ctl(fd_, EPOLL_CTL_DEL, channel->Fd(), &event), 39 | "epoll remove event failed, %s fd: %d", 40 | strerror(errno), 41 | channel->Fd()); 42 | } 43 | 44 | void Epoller::UpdateChannel(Channel* channel) 45 | { 46 | struct epoll_event event; 47 | memset(&event, 0, sizeof(event)); 48 | event.events = channel->Events(); 49 | event.data.ptr = channel; 50 | FatalIf(epoll_ctl(fd_, EPOLL_CTL_MOD, channel->Fd(), &event), 51 | "epoll update event failed, %s ", strerror(errno)); 52 | } 53 | 54 | void Epoller::LoopOnce(int ms) 55 | { 56 | int ready = epoll_wait(fd_, &*events_.begin(), events_.size(), ms); 57 | FatalIf(ready == -1 && errno != EINTR, 58 | "epoll wait failed, %s", strerror(errno)); 59 | for (; --ready >= 0; ) { 60 | Channel *channel = (Channel *)events_[ready].data.ptr; 61 | uint32_t event = events_[ready].events; 62 | if (event & ReadEvent) { 63 | channel->HandleRead(); 64 | } else if (event & WriteEvent) { 65 | channel->HandleWrite(); 66 | } else { 67 | Fatal("unexpected epoll event"); 68 | } 69 | } 70 | } 71 | 72 | } // namespace Explorer 73 | -------------------------------------------------------------------------------- /src/net/epoller.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_EPOLLER_H_ 2 | #define _EXPLORER_EPOLLER_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "../include/base.h" 8 | 9 | const uint32_t ReadEvent = EPOLLIN; 10 | const uint32_t WriteEvent = EPOLLOUT; 11 | const uint32_t MaxEvents = 1024; 12 | 13 | namespace Explorer { 14 | 15 | class Channel; 16 | 17 | class Epoller : private NoCopy 18 | { 19 | public: 20 | Epoller(); 21 | ~Epoller(); 22 | 23 | void AddChannel(Channel* channel); 24 | void RemoveChannel(Channel* channel); 25 | void UpdateChannel(Channel* channel); 26 | 27 | void LoopOnce(int ms); 28 | 29 | private: 30 | int fd_; 31 | std::vector events_; 32 | }; 33 | 34 | } // namespace Explorer 35 | 36 | #endif // _EXPLORER_EPOLLER_H_ 37 | -------------------------------------------------------------------------------- /src/net/eventLoop.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "eventLoop.h" 4 | #include "epoller.h" 5 | #include "channel.h" 6 | #include "../include/threadPool.h" 7 | #include "../include/boundedQueue.h" 8 | #include "socket.h" 9 | #include "time.h" 10 | 11 | namespace Explorer { 12 | 13 | EventLoop::EventLoop(int threadNums, int queueMaxSize) 14 | : epoller_(std::make_shared()), 15 | queue_(std::make_shared>(queueMaxSize)), 16 | pool_(std::make_shared>(queue_, threadNums)), 17 | running_(true), 18 | nextTimeout_(MaxTimeout), 19 | seq_(0) 20 | { 21 | assert(!pipe(wakeUp_)); 22 | assert(Socket(wakeUp_[0]).SetNonBlock()); 23 | channel_ = std::make_shared(wakeUp_[0], epoller_, nullptr, nullptr); 24 | channel_->SetReadCallback([this]() { 25 | char buf; 26 | ssize_t r = read(channel_->Fd(), &buf, sizeof(buf)); 27 | assert(r == sizeof(buf)); 28 | }); 29 | pid_ = pthread_self(); 30 | } 31 | 32 | EventLoop::~EventLoop() 33 | { 34 | close(wakeUp_[1]); 35 | } 36 | 37 | void EventLoop::Loop() 38 | { 39 | while (running_) 40 | { 41 | epoller_->LoopOnce(std::min(5000, nextTimeout_)); 42 | HandleTimeout(); 43 | } 44 | if (nextTimeout_ != MaxTimeout) 45 | { 46 | epoller_->LoopOnce(nextTimeout_); 47 | HandleTimeout(); 48 | } 49 | else 50 | epoller_->LoopOnce(0); 51 | repeat_.clear(); 52 | pending_.clear(); 53 | pool_->Clear(); 54 | } 55 | 56 | void EventLoop::Exit() 57 | { 58 | MutexGuard mtx(mutex_); 59 | if (running_) 60 | { 61 | running_ = false; 62 | WakeUp(); // 使管道可读,检测running_,退出Loop 63 | } 64 | } 65 | 66 | void EventLoop::WakeUp() 67 | { 68 | char buf; 69 | ssize_t r = write(wakeUp_[1], &buf, sizeof(buf)); 70 | assert(r > 0); 71 | } 72 | 73 | 74 | std::shared_ptr EventLoop::GetEpoller() 75 | { 76 | return epoller_; 77 | } 78 | 79 | void EventLoop::RunNow(Task& task) 80 | { 81 | RunAfter(0, task); 82 | } 83 | 84 | //TimerId EventLoop::RunAfter(int64_t milliSec, Task& task) 85 | TimerId EventLoop::RunAfter(int64_t milliSec, Task task) 86 | { 87 | MutexGuard mtx(mutex_); 88 | if (!running_) 89 | return TimerId(); 90 | TimerId id {Time::Now() + milliSec, seq_++}; // 构造定时器 91 | pending_.insert({id, task}); // 添加到定时器集合 92 | if (pthread_self() != pid_) 93 | WakeUp(); 94 | else 95 | Refresh(); // 更新最近超时时间 96 | return id; 97 | } 98 | 99 | //TimerId EventLoop::RunEvery(int64_t milliSec, Task& task) 100 | TimerId EventLoop::RunEvery(int64_t milliSec, Task task) 101 | { 102 | MutexGuard mtx(mutex_); 103 | if (!running_) 104 | return TimerId(); 105 | uint32_t seq = seq_++; 106 | TimeRep rep {milliSec, Time::Now() + milliSec}; // 构造间隔定时器 107 | TimerId id {rep.second, seq}; 108 | repeat_.insert({seq, rep}); // 添加到间隔定时器集合 109 | pending_.insert({id, task}); // 添加到定时器集合 110 | if (pthread_self() != pid_) 111 | WakeUp(); 112 | else 113 | Refresh(); // 更新最近超时时间 114 | return {milliSec, seq}; 115 | } 116 | 117 | void EventLoop::RescheduleAfter(TimerId* id, int64_t milliSec, Task& task) 118 | { 119 | MutexGuard mtx(mutex_); 120 | if (!running_) 121 | return ; 122 | TimerId nid {Time::Now() + milliSec, seq_++}; 123 | auto item = pending_.find(*id); 124 | if (item != pending_.end()) 125 | pending_.erase(*id); 126 | pending_.insert({nid, task}); 127 | *id = nid; 128 | if (pthread_self() != pid_) 129 | WakeUp(); 130 | else 131 | Refresh(); 132 | } 133 | 134 | void EventLoop::RescheduleAfter(const TimerId& timerId, int64_t milliSec) 135 | { 136 | MutexGuard mtx(mutex_); 137 | if (!running_) 138 | return ; 139 | TimerId id {Time::Now() + milliSec, seq_++}; 140 | auto item = pending_.find(timerId); 141 | if (item == pending_.end()) 142 | return ; 143 | Task task = item->second; 144 | pending_.erase(item); 145 | pending_.insert({id, task}); 146 | if (pthread_self() != pid_) 147 | WakeUp(); 148 | else 149 | Refresh(); 150 | } 151 | 152 | // 从定时器集合中去除定时器 153 | void EventLoop::Cancel(const TimerId& Timer) 154 | { 155 | MutexGuard mtx(mutex_); 156 | 157 | auto item = repeat_.find(Timer.second); 158 | if (item != repeat_.end()) 159 | repeat_.erase(item); 160 | auto it = pending_.find(Timer); 161 | if (it != pending_.end()) 162 | pending_.erase(it); 163 | } 164 | 165 | // epoll_wait超时,处理定时器集合中定时器 166 | void EventLoop::HandleTimeout() 167 | { 168 | TimerId now {Time::Now(), 0xffffffff}; 169 | std::vector expired; 170 | // 从定时器集合中找出超时定时器,将其任务添加到超时队列中 171 | while (running_ && 172 | !pending_.empty() && 173 | pending_.begin()->first <= now) 174 | { 175 | expired.push_back(pending_.begin()->second); 176 | const TimerId& id = pending_.begin()->first; 177 | auto item = repeat_.find(id.second); // 查看该定时器是否是间隔定时器 178 | if (item != repeat_.end()) // 重新添加到定时器集合中 179 | { 180 | TimerId nid {now.first + item->second.first, id.second}; 181 | item->second.second = nid.first; 182 | pending_.insert({nid, pending_.begin()->second}); 183 | } 184 | pending_.erase(pending_.begin()); 185 | } 186 | Refresh(); 187 | for (int i = 0; i < expired.size(); ++i) 188 | queue_->Push(expired[i]); // 将超时任务添加到工作队列中 189 | } 190 | 191 | // 更新下次最近超时时间 192 | void EventLoop::Refresh() 193 | { 194 | if (pending_.empty()) 195 | nextTimeout_ = MaxTimeout; 196 | else 197 | { 198 | auto it = pending_.begin()->first; 199 | int64_t tmp = it.first - Time::Now(); 200 | nextTimeout_ = tmp < 0 ? 0 : int(tmp); 201 | } 202 | } 203 | 204 | std::shared_ptr>& EventLoop::GetQueue() 205 | { 206 | return queue_; 207 | } 208 | 209 | } // namespace Explorer 210 | -------------------------------------------------------------------------------- /src/net/eventLoop.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_EVENT_LOOP_H_ 2 | #define _EXPLORER_EVENT_LOOP_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "../include/base.h" 8 | #include "../include/mutex.h" 9 | 10 | namespace Explorer { 11 | 12 | class Epoller; 13 | class Channel; 14 | 15 | template 16 | class ThreadPool; 17 | 18 | template 19 | class BoundedQueue; 20 | 21 | // 定时器 22 | typedef std::pair TimerId; // <超时的时间戳,定时器标识> 23 | 24 | typedef std::pair TimeRep; // <间隔时间,超时时间戳> 25 | 26 | class EventLoop : private NoCopy 27 | { 28 | public: 29 | EventLoop(int threadNums, int queueMaxSize); 30 | ~EventLoop(); 31 | 32 | void Loop(); 33 | void Exit(); 34 | std::shared_ptr GetEpoller(); 35 | 36 | void RunNow(Task& task); 37 | 38 | TimerId RunAfter(int64_t milliSec, Task task); 39 | TimerId RunEvery(int64_t milliSec, Task task); 40 | 41 | void RescheduleAfter(TimerId* id, int64_t milliSec, Task& task); 42 | void RescheduleAfter(const TimerId& timerId, int64_t milliSec); 43 | 44 | void Cancel(const TimerId& timerId); 45 | 46 | std::shared_ptr>& GetQueue(); 47 | 48 | private: 49 | void HandleTimeout(); 50 | void WakeUp(); 51 | void Refresh(); 52 | 53 | private: 54 | static const int MaxTimeout = 0x7fffffff; 55 | 56 | std::shared_ptr> queue_; // 工作队列 57 | std::shared_ptr> pool_; // 线程池 58 | std::shared_ptr channel_; // 管理每个loop的描述符 59 | std::shared_ptr epoller_; 60 | 61 | Mutex mutex_; 62 | bool running_; // 用于控制loop的退出 63 | int wakeUp_[2]; // 和WakeUp()配合,使loop立即检测running_状态标识 64 | int nextTimeout_; 65 | uint64_t pid_; 66 | uint32_t seq_; // 每个定时器的身份标志 67 | 68 | std::map repeat_; // 间隔定时器集合 <定时器标识,间隔定时器> 69 | std::map pending_; // 定时器集合 <定时器,定时器任务> 70 | }; 71 | 72 | } // namespace Explorer 73 | 74 | #endif // _EXPLORER_EVENT_LOOP_H_ 75 | -------------------------------------------------------------------------------- /src/net/server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "server.h" 4 | #include "eventLoop.h" 5 | #include "channel.h" 6 | #include "epoller.h" 7 | 8 | namespace Explorer { 9 | 10 | Server::Server(std::shared_ptr eventLoop, uint16_t port) 11 | : port_(port), 12 | eventLoop_(eventLoop), 13 | listen_(nullptr), 14 | connectCb_(nullptr) 15 | { } 16 | 17 | Server::~Server() 18 | { 19 | if (listen_) 20 | Close(); 21 | } 22 | 23 | void Server::Start() 24 | { 25 | // 设置服务器监听套接字 26 | assert(socket_.Create() && socket_.SetReuseAddress() && 27 | socket_.Bind(port_) && socket_.Listen()); 28 | 29 | // 向epoll注册监听套接字 30 | listen_ = std::make_shared(socket_.Fd(), eventLoop_->GetEpoller(), 31 | [this]() {HandleAccept();}, nullptr); 32 | } 33 | 34 | void Server::Close() 35 | { 36 | socket_.Close(); // 关闭监听套接字 37 | for (auto con : connections_) 38 | con->Close(); // 关闭已连接套接字 39 | } 40 | 41 | void Server::HandleAccept() 42 | { 43 | int fd; // 已连接套接字 44 | 45 | fd = socket_.Accept(); // 连接到来,创建已连接套接字 46 | assert(fd > 0); 47 | // 注册已连接套接字,及其可读、可写的回调函数 48 | std::shared_ptr con = 49 | std::make_shared(Socket(fd), eventLoop_->GetEpoller()); 50 | if (connectCb_) 51 | connectCb_(con); 52 | connections_.push_back(con); // 新连接加入已连接队列 53 | } 54 | 55 | void Server::SetConnectCallback(const ConnectCallback& cb) 56 | { 57 | connectCb_ = cb; 58 | } 59 | 60 | uint16_t Server::Port() const 61 | { 62 | return port_; 63 | } 64 | 65 | std::vector>& Server::Connections() 66 | { 67 | return connections_; 68 | } 69 | 70 | } // namespace Explorer 71 | -------------------------------------------------------------------------------- /src/net/server.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_SERVER_H_ 2 | #define _EXPLORER_SERVER_H_ 3 | 4 | #include 5 | 6 | #include "../include/base.h" 7 | #include "callback.h" 8 | #include "socket.h" 9 | #include "connection.h" 10 | 11 | namespace Explorer { 12 | 13 | class Channel; 14 | class EventLoop; 15 | 16 | class Server : private NoCopy 17 | { 18 | public: 19 | Server(std::shared_ptr eventLoop, uint16_t port); 20 | ~Server(); 21 | 22 | void Start(); 23 | void Close(); 24 | void HandleAccept(); // 客户端新连接到来时的服务器回调函数 25 | void SetConnectCallback(const ConnectCallback& cb); 26 | 27 | uint16_t Port() const; 28 | std::vector>& Connections(); 29 | 30 | protected: 31 | uint16_t port_; 32 | Socket socket_; 33 | std::shared_ptr eventLoop_; 34 | std::shared_ptr listen_; // 用于向Epoller注册监听套接字,等待连接到来 35 | std::vector> connections_; // 目前的已连接队列 36 | ConnectCallback connectCb_; // 可由用户设置的新连接到来时的回调函数 37 | }; 38 | 39 | } // namespace Explorer 40 | 41 | #endif // _EXPLORER_SERVER_H_ 42 | -------------------------------------------------------------------------------- /src/net/sig.cc: -------------------------------------------------------------------------------- 1 | #include "sig.h" 2 | 3 | namespace Explorer { 4 | 5 | std::unordered_map> Signal::handlers_; 6 | 7 | } // namespace Explorer; 8 | -------------------------------------------------------------------------------- /src/net/sig.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_SIGNAL_H_ 2 | #define _EXPLORER_SIGNAL_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Explorer { 9 | 10 | class Signal 11 | { 12 | public: 13 | static void Register(int signo, const std::function& handler) 14 | { 15 | handlers_[signo] = handler; 16 | signal(signo, signal_handler); 17 | } 18 | 19 | static void signal_handler(int signo) 20 | { 21 | handlers_[signo](); 22 | } 23 | 24 | private: 25 | static std::unordered_map> handlers_; 26 | }; 27 | 28 | } // namespace Explorer 29 | 30 | #endif // _EXPLORER_SIGNAL_H_ 31 | -------------------------------------------------------------------------------- /src/net/socket.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "socket.h" 9 | 10 | namespace Explorer { 11 | 12 | Socket::Socket() : fd_(-1) {} 13 | 14 | Socket::Socket(int fd) : fd_(fd) {} 15 | 16 | int Socket::Fd() const 17 | { 18 | return fd_; 19 | } 20 | 21 | bool Socket::Valid() const 22 | { 23 | return fd_ != -1; 24 | } 25 | 26 | bool Socket::Create() 27 | { 28 | fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 29 | return fd_ != -1; 30 | } 31 | 32 | bool Socket::Bind(uint16_t port) 33 | { 34 | struct sockaddr_in servaddr; 35 | memset(&servaddr, 0, sizeof(servaddr)); 36 | servaddr.sin_family = AF_INET; 37 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 38 | servaddr.sin_port = htons(port); 39 | return 0 == bind(fd_, 40 | (const struct sockaddr*)&servaddr, 41 | sizeof(servaddr)); 42 | } 43 | 44 | bool Socket::Connect(const Address& addr) 45 | { 46 | struct sockaddr_in servaddr; 47 | memset(&servaddr, 0, sizeof(servaddr)); 48 | servaddr.sin_family = AF_INET; 49 | servaddr.sin_addr.s_addr = addr.Ip(); 50 | servaddr.sin_port = htons(addr.Port()); 51 | return 0 == connect(fd_, 52 | (const struct sockaddr*)&servaddr, 53 | sizeof(servaddr)); 54 | } 55 | 56 | bool Socket::Listen() 57 | { 58 | return 0 == listen(fd_, BACKLOG); 59 | } 60 | 61 | int Socket::Accept() 62 | { 63 | struct sockaddr_in cliaddr; 64 | int confd; 65 | 66 | memset(&cliaddr, 0, sizeof(cliaddr)); 67 | socklen_t len = sizeof(cliaddr); 68 | confd = accept(fd_, (struct sockaddr*)&cliaddr, &len); 69 | return confd; 70 | } 71 | 72 | bool Socket::Close() 73 | { 74 | bool flag = true; 75 | if (fd_ != -1) 76 | { 77 | flag = !close(fd_); 78 | fd_ = -1; 79 | } 80 | return flag; 81 | } 82 | 83 | bool Socket::SetOption(int optname, int optval) 84 | { 85 | return 0 == setsockopt(fd_, 86 | SOL_SOCKET, 87 | optname, 88 | &optval, 89 | sizeof(optval)); 90 | } 91 | 92 | bool Socket::GetOption(int optname, int* optval) 93 | { 94 | socklen_t len = static_cast(sizeof(*optval)); 95 | return 0 == getsockopt(fd_, 96 | SOL_SOCKET, 97 | optname, 98 | optval, 99 | &len); 100 | } 101 | 102 | bool Socket::SetReuseAddress() 103 | { 104 | return SetOption(SO_REUSEADDR, 1); 105 | } 106 | 107 | bool Socket::GetPeerName(Address* addr) 108 | { 109 | struct sockaddr_in peeraddr; 110 | socklen_t len = sizeof(peeraddr); 111 | 112 | memset(&peeraddr, 0, sizeof(peeraddr)); 113 | if (!getpeername(fd_, (struct sockaddr*)&peeraddr, &len)) 114 | { 115 | *addr = Address(ntohs(peeraddr.sin_port), 116 | peeraddr.sin_addr.s_addr); 117 | return true; 118 | } 119 | return false; 120 | } 121 | 122 | bool Socket::GetSockName(Address* addr) 123 | { 124 | struct sockaddr_in localaddr; 125 | socklen_t len = sizeof(localaddr); 126 | 127 | memset(&localaddr, 0, sizeof(localaddr)); 128 | if (!getsockname(fd_, (struct sockaddr*)&localaddr, &len)) 129 | { 130 | *addr = Address(ntohs(localaddr.sin_port), 131 | localaddr.sin_addr.s_addr); 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | bool Socket::AddFlag(int flag) 138 | { 139 | int cmd = fcntl(fd_, F_GETFL, 0); 140 | assert(cmd != -1); 141 | cmd |= flag; 142 | return -1 != fcntl(fd_, F_SETFL, flag); 143 | } 144 | 145 | bool Socket::SetNonBlock() 146 | { 147 | return AddFlag(O_NONBLOCK); 148 | } 149 | 150 | uint32_t Socket::Write(const char* data, uint32_t len, bool* blocked) 151 | { 152 | uint32_t written = 0; 153 | while (written < len) 154 | { 155 | ssize_t ret = write(fd_, data + written, len - written); 156 | if (ret > 0) 157 | { 158 | written += ret; 159 | continue; 160 | } 161 | if (ret == -1) 162 | { 163 | if (errno == EINTR) 164 | continue; 165 | if (errno == EAGAIN || errno == EWOULDBLOCK) 166 | { 167 | *blocked = true; 168 | return written; 169 | } 170 | else 171 | { 172 | printf("write error, %s\n", strerror(errno)); 173 | break; 174 | } 175 | } 176 | if (ret == 0) 177 | return written; 178 | } 179 | return written; 180 | } 181 | 182 | uint32_t Socket::Read(char* data, uint32_t len, bool* blocked) 183 | { 184 | uint32_t hasRead = 0; 185 | while (hasRead < len) 186 | { 187 | ssize_t ret = read(fd_, data + hasRead, len - hasRead); 188 | if (ret > 0) 189 | { 190 | hasRead += ret; 191 | continue; 192 | } 193 | if (ret == -1) 194 | { 195 | if (errno == EINTR) 196 | continue; 197 | if (errno == EAGAIN || errno == EWOULDBLOCK) 198 | { 199 | *blocked = true; 200 | return hasRead; 201 | } 202 | else 203 | { 204 | printf("read error, %s\n", strerror(errno)); 205 | break; 206 | } 207 | } 208 | if (ret == 0) 209 | return hasRead; 210 | } 211 | return hasRead; 212 | } 213 | 214 | } // namespace Explorer 215 | -------------------------------------------------------------------------------- /src/net/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_SOCKET_H_ 2 | #define _EXPLORER_SOCKET_H_ 3 | 4 | #include "address.h" 5 | 6 | namespace Explorer { 7 | 8 | class Socket 9 | { 10 | public: 11 | Socket(); 12 | Socket(int fd); 13 | 14 | int Fd() const; 15 | bool Valid() const; 16 | 17 | bool Create(); 18 | bool Bind(uint16_t port); 19 | bool Connect(const Address& addr); 20 | bool Listen(); 21 | int Accept(); 22 | bool Close(); 23 | 24 | bool SetOption(int value, int optval); 25 | bool GetOption(int value, int* optval); 26 | bool SetReuseAddress(); 27 | bool GetPeerName(Address* addr); 28 | bool GetSockName(Address* addr); 29 | bool AddFlag(int flag); 30 | bool SetNonBlock(); 31 | 32 | uint32_t Write(const char* data, uint32_t len, bool* blocked); 33 | uint32_t Read(char* data, uint32_t len, bool* blocked); 34 | 35 | private: 36 | static const int BACKLOG = 10240; 37 | int fd_; 38 | }; 39 | 40 | } // namespace Explorer 41 | 42 | #endif // _EXPLORER_SOCKET_H_ 43 | -------------------------------------------------------------------------------- /src/net/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_TIME_H_ 2 | #define _EXPLORER_TIME_H_ 3 | 4 | #include 5 | 6 | namespace Explorer { 7 | 8 | class Time 9 | { 10 | public: 11 | static int64_t Now() { return NowMicro() / 1000; } 12 | 13 | static int64_t NowMicro() 14 | { 15 | struct timeval tv; 16 | gettimeofday(&tv, 0); 17 | return int64_t(tv.tv_sec) * 1000000 + tv.tv_usec; 18 | } 19 | 20 | }; 21 | 22 | } // namespace Explorer 23 | 24 | #endif // _EXPLORER_TIME_H_ 25 | -------------------------------------------------------------------------------- /src/test/file/Makefile: -------------------------------------------------------------------------------- 1 | objects = test.o channel.o epoller.o socket.o buffer.o log.o eventLoop.o connection.o \ 2 | server.o bPlusTree.o sig.o kvClient.o kvServer.o 3 | 4 | VPATH = ../../net : ../../include : ../../tree : ../../kvstore 5 | 6 | test : $(objects) 7 | g++ $(objects) -o test -lpthread 8 | 9 | .PHONY : clean 10 | clean : 11 | -rm test $(objects) 12 | -------------------------------------------------------------------------------- /src/test/file/test.cc: -------------------------------------------------------------------------------- 1 | #include "../../include/base.h" 2 | #include "../../include/mutex.h" 3 | #include "../../include/condition.h" 4 | #include "../../include/thread.h" 5 | #include "../../include/log.h" 6 | #include "../../include/boundedQueue.h" 7 | #include "../../include/threadPool.h" 8 | 9 | #include "../../net/address.h" 10 | #include "../../net/socket.h" 11 | #include "../../net/buffer.h" 12 | #include "../../net/time.h" 13 | #include "../../net/channel.h" 14 | #include "../../net/epoller.h" 15 | #include "../../net/eventLoop.h" 16 | #include "../../net/connection.h" 17 | #include "../../net/server.h" 18 | #include "../../net/sig.h" 19 | 20 | #include "../../tree/bPlusTreeBase.h" 21 | #include "../../tree/bPlusTree.h" 22 | 23 | #include "../../kvstore/kvClient.h" 24 | #include "../../kvstore/kvServer.h" 25 | 26 | 27 | int main() {} 28 | -------------------------------------------------------------------------------- /src/test/kvstore/exp-client/Makefile: -------------------------------------------------------------------------------- 1 | objects = exp-client.o kvClient.o channel.o epoller.o socket.o buffer.o log.o sig.o\ 2 | eventLoop.o connection.o server.o bPlusTree.o 3 | 4 | VPATH = ../../../net : ../../../include : ../../../tree : ../../../kvstore 5 | 6 | exp-cli : $(objects) 7 | g++ $(objects) -o exp-cli -lpthread 8 | 9 | .PHONY : clean 10 | clean : 11 | -rm exp-cli $(objects) 12 | -------------------------------------------------------------------------------- /src/test/kvstore/exp-client/exp-client.cc: -------------------------------------------------------------------------------- 1 | #include "../../../kvstore/kvClient.h" 2 | 3 | using namespace Explorer; 4 | 5 | // 3种线程 6 | int main() 7 | { 8 | const char* ip = "127.0.0.1"; 9 | KvClient client(5, 8, 8000, ip); 10 | std::shared_ptr loop = client.GetLoop(); 11 | Connection& con = client.GetConnection(); 12 | 13 | Signal::Register(SIGINT, [&]{loop->Exit();}); 14 | ExitIf(!con.Success(), ""); 15 | 16 | // 设置客户端套接字可读的回调函数 17 | con.SetReadCallback([&con, &client]() { 18 | printf("%s", 19 | con.GetInput().BeginRead()); 20 | con.GetInput().Clear(); 21 | client.IncCount(); 22 | }); 23 | 24 | // 创建线程处理客户端命令 25 | Thread getInputThread([&client]() { 26 | client.RunDb(); 27 | }); 28 | 29 | getInputThread.Start(); 30 | 31 | // 检测套接字上的可读事件 32 | loop->Loop(); 33 | 34 | getInputThread.Stop(); 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/test/kvstore/exp-server/Makefile: -------------------------------------------------------------------------------- 1 | objects = exp-server.o kvServer.o channel.o epoller.o socket.o buffer.o log.o sig.o\ 2 | eventLoop.o connection.o server.o bPlusTree.o 3 | 4 | VPATH = ../../../net : ../../../include : ../../../tree : ../../../kvstore 5 | 6 | exp-srv : $(objects) 7 | g++ $(objects) -o exp-srv -lpthread 8 | 9 | .PHONY : clean 10 | clean : 11 | -rm exp-srv $(objects) 12 | -------------------------------------------------------------------------------- /src/test/kvstore/exp-server/exp-server.cc: -------------------------------------------------------------------------------- 1 | #include "../../../net/sig.h" 2 | #include "../../../net/server.h" 3 | #include "../../../include/thread.h" 4 | #include "../../../kvstore/kvServer.h" 5 | 6 | using namespace Explorer; 7 | 8 | #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 9 | 10 | int main() 11 | { 12 | const char* filePath = "test.db"; 13 | open(filePath, O_CREAT | O_EXCL, FILE_MODE); 14 | 15 | KvServer kvsrv(2, 8, "test.db"); 16 | std::shared_ptr loop = kvsrv.GetLoop(); 17 | 18 | Signal::Register(SIGINT, [&]{loop->Exit();}); 19 | Server server(loop, 8000); 20 | server.Start(); 21 | 22 | server.SetConnectCallback([&kvsrv](std::shared_ptr con) { 23 | con->SetReadCallback([con, &kvsrv]() { 24 | kvsrv.GetArg(con, con->GetInput()); 25 | }); 26 | }); 27 | 28 | Thread sendReplyThread([&kvsrv]() { 29 | kvsrv.RunDb(); 30 | }); 31 | sendReplyThread.Start(); 32 | 33 | loop->Loop(); 34 | 35 | sendReplyThread.Stop(); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/test/threadPool/Makefile: -------------------------------------------------------------------------------- 1 | objects = test.o 2 | 3 | VPATH = ../../net : ../../include 4 | 5 | test : $(objects) 6 | g++ -g $(objects) -o test -lpthread 7 | 8 | .PHONY : clean 9 | clean : 10 | -rm test $(objects) 11 | -------------------------------------------------------------------------------- /src/test/threadPool/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../../include/threadPool.h" 4 | 5 | int flag = 0; 6 | 7 | void assign() 8 | { 9 | printf("thread %d\n", flag++); 10 | } 11 | 12 | int main() 13 | { 14 | using namespace Explorer; 15 | 16 | std::shared_ptr> pqueue = std::make_shared>(20); 17 | for (int i = 0; i < 15; i++) 18 | pqueue->Push(assign); 19 | 20 | ThreadPool pool(pqueue, 6); // 创建线程池,线程开始运行 21 | sleep(1); // 等待线程执行任务 22 | 23 | pool.Clear(); // 立即销毁线程池 24 | printf("end\n"); 25 | } 26 | -------------------------------------------------------------------------------- /src/test/timer/Makefile: -------------------------------------------------------------------------------- 1 | objects = test.o channel.o epoller.o socket.o buffer.o log.o eventLoop.o 2 | 3 | VPATH = ../../net : ../../include 4 | 5 | test : $(objects) 6 | g++ $(objects) -o test -lpthread 7 | 8 | .PHONY : clean 9 | clean : 10 | -rm test $(objects) 11 | -------------------------------------------------------------------------------- /src/test/timer/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../../net/eventLoop.h" 4 | 5 | int flag = 0; 6 | 7 | void assign() 8 | { 9 | printf("thread %d\n", flag++); 10 | } 11 | 12 | int main() 13 | { 14 | using namespace Explorer; 15 | 16 | // 创建工作队列-->启动线程池-->线程阻塞在工作队列上-->创建epoller、channel 17 | EventLoop loop(5, 9); 18 | 19 | Task func = assign; 20 | loop.RunAfter(1000, func); // 添加定时器、更新超时时间 21 | loop.RunAfter(2000, func); // 添加定时器、更新超时时间 22 | loop.RunEvery(1000, func); // 添加间隔定时器 23 | 24 | // 根据最小超时时间调用epoll_wait-->处理超时-->找出超时的定时器-->添加任务到工作队列 25 | // 阻塞的线程开始工作-->队列空、线程继续阻塞 26 | loop.Loop(); 27 | } 28 | -------------------------------------------------------------------------------- /src/test/tree/Makefile: -------------------------------------------------------------------------------- 1 | objects = tree.o bPlusTree.o 2 | 3 | VPATH = ../../net : ../../include : ../../tree 4 | 5 | tree : $(objects) 6 | g++ $(objects) -o tree -lpthread 7 | 8 | .PHONY : clean 9 | clean : 10 | -rm tree $(objects) 11 | -------------------------------------------------------------------------------- /src/test/tree/tree.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../../tree/bPlusTree.h" 11 | 12 | using namespace std; 13 | using namespace Explorer; 14 | 15 | #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 16 | 17 | void getInput(vector& input) 18 | { 19 | string in, arg; 20 | 21 | getline(cin, in); 22 | stringstream ss(in); 23 | 24 | while (ss >> arg) 25 | input.push_back(arg); 26 | } 27 | 28 | void stat(BPlusTree& db) 29 | { 30 | meta metdt = db.GetMeta(); 31 | printf(" Order : %d\n", metdt.order); 32 | printf(" ValueSize : %d\n", metdt.valueSize); 33 | printf(" KeySize : %d\n", metdt.keySize); 34 | printf(" InternalNode : %d\n", metdt.internalNodeNum); 35 | printf(" LeafNode : %d\n", metdt.leafNodeNum); 36 | printf(" Height : %d\n", metdt.height); 37 | printf(" OffSet : %d\n", metdt.slot); 38 | } 39 | 40 | void help() 41 | { 42 | printf(" -----------Help Document-----------\n"); 43 | printf(" commands below are case insensitive\n\n"); 44 | printf(" set key value\n"); 45 | printf(" get key\n"); 46 | printf(" get lkey rkey\n"); 47 | printf(" update key value\n"); 48 | printf(" del key\n"); 49 | printf(" stat\n"); 50 | printf(" q\n"); 51 | printf(" quit\n"); 52 | printf(" h\n"); 53 | printf(" ----------------END----------------\n"); 54 | printf("\n"); 55 | } 56 | 57 | int helper(BPlusTree& db, vector& input, int argNum) 58 | { 59 | if (!strcasecmp(input[0].c_str(), "q") || 60 | !strcasecmp(input[0].c_str(), "quit")) 61 | return -1; 62 | else if (!strcasecmp(input[0].c_str(), "stat")) 63 | stat(db); 64 | else if (!strcasecmp(input[0].c_str(), "h")) 65 | help(); 66 | else if (!strcasecmp(input[0].c_str(), "set") || 67 | !strcasecmp(input[0].c_str(), "get") || 68 | !strcasecmp(input[0].c_str(), "del") || 69 | !strcasecmp(input[0].c_str(), "update") || 70 | !strcasecmp(input[0].c_str(), "get")) 71 | printf(" Argument Error. Use \"h\" for help.\n"); 72 | else 73 | printf(" Command Error. Use \"h\" for help.\n"); 74 | return 0; 75 | } 76 | 77 | void insert(BPlusTree& db, vector& input, int argNum) 78 | { 79 | if (argNum != 3) 80 | { 81 | printf(" Argument Error. Use \"h\" for help.\n"); 82 | return ; 83 | } 84 | if (db.Insert(input[1].c_str(), atoi(input[2].c_str())) != 0) 85 | printf(" Key Already Exist.\n"); 86 | } 87 | 88 | void update(BPlusTree& db, vector& input, int argNum) 89 | { 90 | if (argNum != 3) 91 | { 92 | printf(" Argument Error. Use \"h\" for help.\n"); 93 | return ; 94 | } 95 | if (db.Update(input[1].c_str(), atoi(input[2].c_str())) != 0) 96 | printf(" Key Not Exist.\n"); 97 | } 98 | 99 | void del(BPlusTree& db, vector& input, int argNum) 100 | { 101 | if (argNum != 2) 102 | { 103 | printf(" Argument Error. Use \"h\" for help.\n"); 104 | return ; 105 | } 106 | if (db.Remove(input[1].c_str()) != 0) 107 | printf(" Key Not Found.\n"); 108 | } 109 | 110 | void search(BPlusTree& db, vector& input, int argNum) 111 | { 112 | if (argNum == 2) 113 | { 114 | valueType value; 115 | if (db.Search(input[1].c_str(), &value) != 0) 116 | printf(" Key Not Found.\n"); 117 | else 118 | printf(" %d\n", value); 119 | } 120 | else if (argNum == 3) 121 | { 122 | keyType start(input[1].c_str()); 123 | valueType values[512]; 124 | bool next = true; 125 | while (next) 126 | { 127 | int ret = db.SearchRange(&start, 128 | input[2].c_str(), 129 | values, 130 | 512, 131 | &next); 132 | if (ret <= 0) 133 | { 134 | printf(" Key Not Found.\n"); 135 | return ; 136 | } 137 | for (int i = 0; i < ret; ++i) 138 | printf(" %d\n", values[i]); 139 | } 140 | } 141 | else 142 | printf(" Argument Error. Use \"h\" for help.\n"); 143 | } 144 | 145 | void command(BPlusTree& db) 146 | { 147 | while(1) 148 | { 149 | int argNum; 150 | vector input; 151 | 152 | cout << " > "; 153 | getInput(input); 154 | argNum = input.size(); 155 | 156 | if (argNum == 0) 157 | continue; 158 | if (argNum == 1) 159 | { 160 | int ret = helper(db, input, argNum); 161 | if (ret == -1) 162 | return ; 163 | else 164 | continue ; 165 | } 166 | 167 | if (!strcasecmp(input[0].c_str(), "get")) 168 | { 169 | search(db, input, argNum); 170 | } 171 | else if (!strcasecmp(input[0].c_str(), "set")) 172 | { 173 | insert(db, input, argNum); 174 | } 175 | else if (!strcasecmp(input[0].c_str(), "update")) 176 | { 177 | update(db, input, argNum); 178 | } 179 | else if (!strcasecmp(input[0].c_str(), "del")) 180 | { 181 | del(db, input, argNum); 182 | } 183 | else 184 | printf(" Command Error. Use \"h\" for help.\n"); 185 | } 186 | } 187 | 188 | void runDb() 189 | { 190 | const char* filePath = "test.db"; 191 | 192 | open(filePath, O_CREAT | O_EXCL, FILE_MODE); 193 | BPlusTree db(filePath); 194 | 195 | command(db); 196 | } 197 | 198 | int main() 199 | { 200 | runDb(); 201 | 202 | return 0; 203 | } 204 | -------------------------------------------------------------------------------- /src/test/web/client/Makefile: -------------------------------------------------------------------------------- 1 | objects = webClient.o channel.o epoller.o socket.o buffer.o log.o eventLoop.o connection.o \ 2 | server.o sig.o 3 | 4 | VPATH = ../../../net : ../../../include 5 | 6 | webClient : $(objects) 7 | g++ $(objects) -o webClient -lpthread 8 | 9 | .PHONY : clean 10 | clean : 11 | -rm webClient $(objects) 12 | -------------------------------------------------------------------------------- /src/test/web/client/webClient.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../../../net/eventLoop.h" 4 | #include "../../../net/sig.h" 5 | #include "../../../net/connection.h" 6 | #include "../../../include/log.h" 7 | 8 | using namespace Explorer; 9 | 10 | int main() 11 | { 12 | // 每个Channel管理一个描述符 13 | // 创建工作队列、线程池、线程池阻塞、创建loop的Channel、公共的Epoller、向Epoller注册Channel 14 | std::shared_ptr loop = std::make_shared(1, 8); 15 | // 创建连接套接字、创建连接的Channel、向Channel注册连接套接字、向公共的Epoller注册Channel 16 | Connection con(Address(8000, "127.0.0.1"), loop->GetEpoller()); 17 | Signal::Register(SIGINT, [&]{loop->Exit();}); 18 | 19 | ExitIf(!con.Success(), ""); 20 | // 设置客户端套接字可读的回调函数 21 | con.SetReadCallback([&con]() { 22 | //printf("read %u : %s\n", 23 | // con.GetInput().ReadableBytes(), 24 | // con.GetInput().BeginRead()); 25 | con.GetInput().Clear(); 26 | }); 27 | 28 | // 客户端运行5秒后终止 29 | loop->RunAfter(20000, [&loop](){loop->Exit();}); 30 | 31 | // 每0.5秒发送一次 32 | TimerId id1 = loop->RunEvery(500, [&con]() { 33 | con.Send("hello world! "); 34 | }); 35 | // 每0.7秒发送一次 36 | TimerId id2 = loop->RunEvery(700, [&con]() { 37 | con.Send("hello uestc! "); 38 | }); 39 | TimerId id3 = loop->RunAfter(9000, [&con]() { 40 | con.Send("hello Explorer! "); 41 | }); 42 | 43 | // 1.5秒后取消定时器,发送3次id1 44 | loop->RunAfter(1500, [&loop, id1]() { 45 | loop->Cancel(id1); 46 | }); 47 | // 3.5秒后取消定时器,发送5次id2 48 | loop->RunAfter(3500, [&loop, id2]() { 49 | loop->Cancel(id2); 50 | }); 51 | 52 | // 检测套接字上的可读事件 53 | loop->Loop(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /src/test/web/server/Makefile: -------------------------------------------------------------------------------- 1 | objects = webServer.o channel.o epoller.o socket.o buffer.o log.o eventLoop.o connection.o \ 2 | server.o sig.o 3 | 4 | VPATH = ../../../net : ../../../include 5 | 6 | webServer : $(objects) 7 | g++ $(objects) -o webServer -lpthread 8 | 9 | .PHONY : clean 10 | clean : 11 | -rm webServer $(objects) 12 | -------------------------------------------------------------------------------- /src/test/web/server/webServer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../../../net/server.h" 4 | #include "../../../net/sig.h" 5 | #include "../../../net/eventLoop.h" 6 | 7 | using namespace Explorer; 8 | 9 | int main() 10 | { 11 | // 创建工作队列、线程池-->线程启动阻塞在空队列 12 | // -->创建Epoller、Channel-->向Epoller注册Channel 13 | std::shared_ptr loop = std::make_shared(2, 8); 14 | 15 | Signal::Register(SIGINT, [&]{loop->Exit();}); // 注册SIGINT信号,使loop退出Loop()循环 16 | Server server(loop, 8000); // 创建Server 17 | server.Start(); // 创建、绑定、监听套接字、向Epoller注册监听套接字 18 | // Server.HandleAccept()调用connectCb_() 19 | server.SetConnectCallback([](std::shared_ptr con) { 20 | // Server的connectCb_()作用是注册connection的readCb_ 21 | con->SetReadCallback([con]() { 22 | printf("read %u : %s\n", 23 | con->GetInput().ReadableBytes(), 24 | con->GetInput().BeginRead()); 25 | con->Send(con->GetInput()); 26 | }); 27 | }); 28 | // server.HandleAccept-->Connection()-->Connection.ReadCallback() 29 | loop->Loop(); // 循环调用Epoller->LoopOnce()等待注册的描述符可读 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /src/tree/bPlusTree.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "bPlusTree.h" 4 | 5 | using std::upper_bound; 6 | using std::lower_bound; 7 | using std::binary_search; 8 | 9 | namespace Explorer { 10 | 11 | // 在节点对半查找时需要定义比较运算符 12 | // 比较索引/记录与键的大小 13 | OPERATOR_KEYCMP(index) 14 | OPERATOR_KEYCMP(record) 15 | 16 | // 节点首关键字位置 17 | template 18 | inline typename T::child 19 | begin(T& node) 20 | { 21 | return node.children; 22 | } 23 | 24 | // 节点尾关键字位置 25 | template 26 | inline typename T::child 27 | end(T& node) 28 | { 29 | return node.children + node.n; 30 | } 31 | 32 | inline index* find(internalNode& node, const keyType& key) 33 | { 34 | return upper_bound(begin(node), end(node) - 1, key); 35 | } 36 | 37 | inline record* find(leafNode& node, const keyType& key) 38 | { 39 | return lower_bound(begin(node), end(node), key); 40 | } 41 | 42 | BPlusTree::BPlusTree(const char* path, bool empty) 43 | : fp_(NULL), 44 | fpLevel_(0) 45 | { 46 | bzero(path_, sizeof(path_)); 47 | strcpy(path_, path); 48 | 49 | if (!empty) 50 | { 51 | // 第一次之后使用时才成功 52 | if (map(&meta_, OFFSET_META) != 0) 53 | empty = true; 54 | } 55 | 56 | if (empty) 57 | { 58 | // 第一次使用时调用,以初始化 59 | openFile("w+"); 60 | initFromEmpty(); 61 | closeFile(); 62 | } 63 | } 64 | 65 | int BPlusTree::Insert(const keyType& key, valueType value) 66 | { 67 | off_t parent = searchIndex(key); 68 | off_t offset = searchLeaf(parent, key); 69 | leafNode leaf; 70 | map(&leaf, offset); 71 | 72 | // 叶子节点中查找键 73 | if (binary_search(begin(leaf), end(leaf), key)) // 若键已存在 74 | return -1; 75 | 76 | if (leaf.n == meta_.order) // 叶子节点已满,分裂 77 | { 78 | // 创建新叶子节点 79 | leafNode newLeaf; 80 | nodeCreate(offset, &leaf, &newLeaf); 81 | 82 | size_t point = leaf.n / 2; 83 | bool placeRight = keyComp(key, leaf.children[point].key) > 0; 84 | if (placeRight) 85 | ++point; 86 | 87 | // 分裂 88 | std::copy(leaf.children + point, leaf.children + leaf.n, newLeaf.children); 89 | newLeaf.n = leaf.n - point; 90 | leaf.n = point; 91 | 92 | // 插入key-value对 93 | if (placeRight) 94 | insertRecordNoSplit(&newLeaf, key, value); 95 | else 96 | insertRecordNoSplit(&leaf, key, value); 97 | 98 | // 写入磁盘 99 | unmap(&leaf, offset); 100 | unmap(&newLeaf, leaf.next); 101 | 102 | // 更新父节点 103 | insertKeyToIndex(parent, newLeaf.children[0].key, offset, leaf.next); 104 | } 105 | else 106 | { 107 | // 插入key-value对并写入磁盘 108 | insertRecordNoSplit(&leaf, key, value); 109 | unmap(&leaf, offset); 110 | } 111 | return 0; 112 | } 113 | 114 | int BPlusTree::Remove(const keyType& key) 115 | { 116 | internalNode parent; 117 | leafNode leaf; 118 | 119 | off_t parentOff = searchIndex(key); 120 | map(&parent, parentOff); 121 | 122 | index* where = find(parent, key); 123 | off_t offset = where->child; 124 | map(&leaf, offset); 125 | 126 | if (!binary_search(begin(leaf), end(leaf), key)) 127 | return -1; 128 | 129 | size_t minN = meta_.leafNodeNum == 1 ? 0 : meta_.order / 2; 130 | assert(leaf.n >= minN && leaf.n <= meta_.order); 131 | 132 | record* toDelete = find(leaf, key); 133 | std::copy(toDelete + 1, end(leaf), toDelete); 134 | leaf.n--; 135 | 136 | // 借键或合并叶子节点 137 | if (leaf.n < minN) 138 | { 139 | bool borrowed = false; 140 | // 从左节点借 141 | if (leaf.prev != 0) 142 | borrowed = borrowKey(false, leaf); 143 | // 从右节点借 144 | if (!borrowed && leaf.next != 0) 145 | borrowed = borrowKey(true, leaf); 146 | // 左右节点都无可借 147 | if (!borrowed) 148 | { 149 | assert(leaf.next != 0 || leaf.prev != 0); 150 | keyType indexKey; 151 | if (where == end(parent) - 1) 152 | { 153 | // 与左节点合并 154 | assert(leaf.prev != 0); 155 | leafNode prev; 156 | map(&prev, leaf.prev); 157 | indexKey = begin(prev)->key; 158 | 159 | mergeLeafs(&prev, &leaf); 160 | nodeRemove(&prev, &leaf); 161 | unmap(&prev, leaf.prev); 162 | } 163 | else 164 | { 165 | // 与右节点合并 166 | assert(leaf.next != 0); 167 | leafNode next; 168 | map(&next, leaf.next); 169 | indexKey = begin(leaf)->key; 170 | 171 | mergeLeafs(&leaf, &next); 172 | nodeRemove(&leaf, &next); 173 | unmap(&leaf, offset); 174 | } 175 | removeFromIndex(parentOff, parent, indexKey); 176 | } 177 | else 178 | unmap(&leaf, offset); 179 | } 180 | else 181 | unmap(&leaf, offset); 182 | return 0; 183 | } 184 | 185 | int BPlusTree::Update(const keyType& key, valueType value) 186 | { 187 | off_t offset = searchLeaf(key); 188 | leafNode leaf; 189 | map(&leaf, offset); 190 | 191 | record *rc = find(leaf, key); 192 | if (rc != leaf.children + leaf.n) 193 | { 194 | if (keyComp(key, rc->key) == 0) 195 | { 196 | rc->value = value; 197 | unmap(&leaf, offset); 198 | return 0; 199 | } 200 | } 201 | else 202 | return -1; 203 | } 204 | 205 | int BPlusTree::Search(const keyType& key, valueType* value) const 206 | { 207 | leafNode leaf; 208 | map(&leaf, searchLeaf(key)); 209 | record *rc = find(leaf, key); 210 | if (rc != leaf.children + leaf.n) 211 | { 212 | *value = rc->value; 213 | return keyComp(rc->key, key); 214 | } 215 | else 216 | return -1; 217 | } 218 | 219 | int BPlusTree::SearchRange(keyType* left, const keyType& right, 220 | valueType* values, size_t max, bool *next) const 221 | { 222 | if (left == NULL || keyComp(*left, right) > 0) 223 | return -1; 224 | 225 | off_t offLeft = searchLeaf(*left); 226 | off_t offRight = searchLeaf(right); 227 | off_t off = offLeft; 228 | size_t i = 0; 229 | record *b, *e; 230 | 231 | leafNode leaf; 232 | while (off != offRight && off != 0 && i < max) 233 | { 234 | map(&leaf, off); 235 | if (offLeft == off) 236 | b = find(leaf, *left); 237 | else 238 | b = begin(leaf); 239 | e = leaf.children + leaf.n; 240 | for (; b != e && i < max; ++b, ++i) 241 | values[i] = b->value; 242 | off = leaf.next; 243 | } 244 | 245 | if (i < max) 246 | { 247 | map(&leaf, offRight); 248 | b = find(leaf, *left); 249 | e = upper_bound(begin(leaf), end(leaf), right); 250 | for (; b != e && i < max; ++b, ++i) 251 | values[i] = b->value; 252 | } 253 | 254 | if (next != NULL) 255 | { 256 | if (i == max && b != e) 257 | { 258 | *next = true; 259 | *left = b->key; 260 | } 261 | else 262 | *next = false; 263 | } 264 | 265 | return i; 266 | } 267 | 268 | meta BPlusTree::GetMeta() const 269 | { 270 | return meta_; 271 | } 272 | 273 | void BPlusTree::initFromEmpty() 274 | { 275 | // 初始化元数据 276 | bzero(&meta_, sizeof(meta_)); 277 | meta_.order = ORDER; 278 | meta_.valueSize = sizeof(valueType); 279 | meta_.keySize = sizeof(keyType); 280 | meta_.height = 1; 281 | meta_.slot = OFFSET_BLOCK; 282 | 283 | // 初始化根节点 284 | internalNode root; 285 | root.next = root.prev = root.parent = 0; 286 | meta_.rootOffset = alloc(&root); 287 | 288 | // 初始化叶子节点 289 | leafNode leaf; 290 | leaf.next = leaf.prev = 0; 291 | leaf.parent = meta_.rootOffset; 292 | meta_.leafOffset = root.children[0].child = alloc(&leaf); 293 | 294 | // 节点信息写入磁盘 295 | unmap(&meta_, OFFSET_META); 296 | unmap(&root, meta_.rootOffset); 297 | unmap(&leaf, meta_.leafOffset); 298 | } 299 | 300 | off_t BPlusTree::searchIndex(const keyType& key) const 301 | { 302 | off_t pos = meta_.rootOffset; 303 | int height = meta_.height; 304 | while (height > 1) 305 | { 306 | internalNode node; 307 | map(&node, pos); 308 | index* i = upper_bound(begin(node), end(node) - 1, key); // zx 309 | pos = i->child; 310 | --height; 311 | } 312 | return pos; 313 | } 314 | 315 | off_t BPlusTree::searchLeaf(const keyType& key) const 316 | { 317 | return searchLeaf(searchIndex(key), key); 318 | } 319 | 320 | off_t BPlusTree::searchLeaf(off_t parent, const keyType& key) const 321 | { 322 | internalNode node; 323 | map(&node, parent); 324 | index* i = upper_bound(begin(node), end(node) - 1, key); 325 | return i->child; 326 | } 327 | 328 | void BPlusTree::insertRecordNoSplit(leafNode* leaf, 329 | const keyType& key, 330 | const valueType& value) 331 | { 332 | record* where = upper_bound(begin(*leaf), end(*leaf), key); // 二分查找确定位置 333 | std::copy_backward(where, end(*leaf), end(*leaf) + 1); // 移动元素 334 | where->key = key; 335 | where->value = value; 336 | leaf->n++; 337 | } 338 | 339 | void BPlusTree::insertKeyToIndex(off_t offset, const keyType& key, 340 | off_t old, off_t after) 341 | { 342 | if (offset == 0) 343 | { 344 | // 创建新的根节点 345 | internalNode root; 346 | root.next = root.prev = root.parent = 0; 347 | meta_.rootOffset = alloc(&root); 348 | meta_.height++; 349 | 350 | root.n = 2; 351 | root.children[0].child = old; 352 | root.children[0].key = key; 353 | root.children[1].child = after; 354 | 355 | unmap(&meta_, OFFSET_META); 356 | unmap(&root, meta_.rootOffset); 357 | 358 | resetIndexChildrenParent(begin(root), end(root), meta_.rootOffset); 359 | return ; 360 | } 361 | 362 | internalNode node; 363 | map(&node, offset); 364 | assert(node.n <= meta_.order); 365 | 366 | if (node.n == meta_.order) // 父节点同样已满 367 | { 368 | internalNode newNode; 369 | nodeCreate(offset, &node, &newNode); 370 | 371 | size_t point = (node.n - 1) / 2; 372 | bool placeRight = keyComp(key, node.children[point].key) > 0; 373 | if (placeRight) 374 | ++point; 375 | if (placeRight && keyComp(key, node.children[point].key) < 0) 376 | point--; 377 | 378 | keyType middleKey = node.children[point].key; 379 | std::copy(begin(node) + point + 1, end(node), begin(newNode)); 380 | newNode.n = node.n - point - 1; 381 | node.n = point + 1; 382 | if (placeRight) 383 | insertKeyToIndexNoSplit(newNode, key, after); 384 | else 385 | insertKeyToIndexNoSplit(node, key, after); 386 | 387 | unmap(&node, offset); 388 | unmap(&newNode, node.next); 389 | resetIndexChildrenParent(begin(newNode), end(newNode), node.next); 390 | insertKeyToIndex(node.parent, middleKey, offset, node.next); // 递归 391 | } 392 | else 393 | { 394 | insertKeyToIndexNoSplit(node, key, after); 395 | unmap(&node, offset); 396 | } 397 | } 398 | 399 | void BPlusTree::insertKeyToIndexNoSplit(internalNode& node, 400 | const keyType& key, 401 | off_t value) 402 | { 403 | index* where = upper_bound(begin(node), end(node) - 1, key); 404 | std::copy_backward(where, end(node), end(node) + 1); 405 | 406 | where->key = key; 407 | where->child = (where + 1)->child; 408 | (where + 1)->child = value; 409 | node.n++; 410 | } 411 | 412 | void BPlusTree::resetIndexChildrenParent(index* begin, index* end, off_t parent) 413 | { 414 | internalNode node; 415 | while (begin != end) 416 | { 417 | map(&node, begin->child); 418 | node.parent = parent; 419 | unmap(&node, begin->child, SIZE_NO_CHILDREN); 420 | ++begin; 421 | } 422 | } 423 | 424 | void BPlusTree::removeFromIndex(off_t offset, internalNode& node, const keyType& key) 425 | { 426 | size_t minN = meta_.rootOffset == offset ? 1 : meta_.order / 2; 427 | assert(node.n >= minN && node.n <= meta_.order); 428 | 429 | keyType indexKey = begin(node)->key; 430 | index *toDelete = find(node, key); 431 | if (toDelete != end(node)) 432 | { 433 | (toDelete + 1)->child = toDelete->child; 434 | std::copy(toDelete + 1, end(node), toDelete); 435 | } 436 | node.n--; 437 | 438 | if (node.n == 1 && meta_.rootOffset == offset && meta_.internalNodeNum != 1) 439 | { 440 | unalloc(&node, meta_.rootOffset); 441 | meta_.height--; 442 | meta_.rootOffset = node.children[0].child; 443 | unmap(&meta_, OFFSET_META); 444 | return ; 445 | } 446 | 447 | if (node.n < minN) 448 | { 449 | internalNode parent; 450 | map(&parent, node.parent); 451 | 452 | // 从左右节点借 453 | bool borrowed = false; 454 | if (offset != begin(parent)->child) 455 | borrowed = borrowKey(false, node, offset); 456 | if (!borrowed && offset != (end(parent) - 1)->child) 457 | borrowed = borrowKey(true, node, offset); 458 | 459 | if (!borrowed) // 合并 460 | { 461 | assert(node.next != 0 || node.prev != 0); 462 | 463 | if (offset == (end(parent) - 1)->child) 464 | { 465 | assert(node.prev != 0); 466 | internalNode prev; 467 | map(&prev, node.prev); 468 | 469 | index *where = find(parent, begin(prev)->key); 470 | resetIndexChildrenParent(begin(node), end(node), node.prev); 471 | mergeKeys(where, prev, node); 472 | unmap(&prev, node.prev); 473 | } 474 | else 475 | { 476 | assert(node.next != 0); 477 | internalNode next; 478 | map(&next, node.next); 479 | 480 | index *where = find(parent, indexKey); 481 | resetIndexChildrenParent(begin(next), end(next), offset); 482 | mergeKeys(where, node, next); 483 | unmap(&node, offset); 484 | } 485 | 486 | removeFromIndex(node.parent, parent, indexKey); 487 | } 488 | else 489 | unmap(&node, offset); 490 | } 491 | else 492 | unmap(&node, offset); 493 | } 494 | 495 | bool BPlusTree::borrowKey(bool fromRight, leafNode& borrower) 496 | { 497 | off_t lenderOff = fromRight ? borrower.next : borrower.prev; 498 | leafNode lender; 499 | map(&lender, lenderOff); 500 | 501 | assert(lender.n >= meta_.order / 2); 502 | if (lender.n != meta_.order / 2) 503 | { 504 | typename leafNode::child whereToLend, whereToPut; 505 | if (fromRight) 506 | { 507 | whereToLend = begin(lender); 508 | whereToPut = end(borrower); 509 | changeParentChild(borrower.parent, begin(borrower)->key, 510 | lender.children[1].key); 511 | } 512 | else 513 | { 514 | whereToLend = end(lender) - 1; 515 | whereToPut = begin(borrower); 516 | changeParentChild(lender.parent, begin(lender)->key, 517 | whereToLend->key); 518 | } 519 | 520 | std::copy_backward(whereToPut, end(borrower), end(borrower) + 1); 521 | *whereToPut = *whereToLend; 522 | borrower.n++; 523 | 524 | std::copy_backward(whereToLend + 1, end(lender), whereToLend); 525 | lender.n--; 526 | unmap(&lender, lenderOff); 527 | return true; 528 | } 529 | return false; 530 | } 531 | 532 | bool BPlusTree::borrowKey(bool fromRight, internalNode& borrower, off_t offset) 533 | { 534 | typedef typename internalNode::child child; 535 | off_t lenderOff = fromRight ? borrower.next : borrower.prev; 536 | internalNode lender; 537 | map(&lender, lenderOff); 538 | 539 | assert(lender.n >= meta_.order / 2); 540 | if (lender.n != meta_.order / 2) 541 | { 542 | child whereToLend, whereToPut; 543 | internalNode parent; 544 | 545 | if (fromRight) 546 | { 547 | whereToLend = begin(lender); 548 | whereToPut = end(borrower); 549 | map(&parent, borrower.parent); 550 | child where = lower_bound(begin(parent), end(parent) - 1, 551 | (end(borrower) - 1)->key); 552 | where->key = whereToLend->key; 553 | unmap(&parent, borrower.parent); 554 | } 555 | else 556 | { 557 | whereToLend = end(lender) - 1; 558 | whereToPut = begin(borrower); 559 | 560 | map(&parent, lender.parent); 561 | child where = find(parent, begin(lender)->key); 562 | whereToPut->key = where->key; 563 | where->key = (whereToLend - 1)->key; 564 | unmap(&parent, lender.parent); 565 | } 566 | 567 | std::copy_backward(whereToPut, end(borrower), end(borrower) + 1); 568 | *whereToPut = *whereToLend; 569 | borrower.n++; 570 | 571 | resetIndexChildrenParent(whereToLend, whereToLend + 1, offset); 572 | std::copy(whereToLend + 1, end(lender), whereToLend); 573 | lender.n--; 574 | unmap(&lender, lenderOff); 575 | return true; 576 | } 577 | return false; 578 | } 579 | 580 | void BPlusTree::changeParentChild(off_t parent, const keyType& o, const keyType& n) 581 | { 582 | internalNode node; 583 | map(&node, parent); 584 | 585 | index* w = find(node, o); 586 | assert(w != (node.children + node.n)); 587 | 588 | w->key = n; 589 | unmap(&node, parent); 590 | if (w == node.children + node.n - 1) 591 | { 592 | changeParentChild(node.parent, o, n); 593 | } 594 | } 595 | 596 | void BPlusTree::mergeLeafs(leafNode* left, leafNode* right) 597 | { 598 | std::copy(begin(*right), end(*right), end(*left)); 599 | left->n += right->n; 600 | } 601 | 602 | void BPlusTree::mergeKeys(index* where, internalNode& node, internalNode& next) 603 | { 604 | std::copy(begin(next), end(next), end(node)); 605 | node.n += next.n; 606 | nodeRemove(&node, &next); 607 | } 608 | 609 | void BPlusTree::openFile(const char* mode) const 610 | { 611 | if (fpLevel_ == 0) 612 | fp_ = fopen(path_, mode); 613 | ++fpLevel_; 614 | } 615 | 616 | void BPlusTree::closeFile() const 617 | { 618 | if (fpLevel_ == 1) 619 | fclose(fp_); 620 | --fpLevel_; 621 | } 622 | 623 | int BPlusTree::map(void* block, off_t offset, size_t size) const 624 | { 625 | openFile(); 626 | fseek(fp_, offset, SEEK_SET); 627 | size_t rd = fread(block, size, 1, fp_); // 从磁盘读入数据 628 | closeFile(); 629 | return rd - 1; 630 | } 631 | 632 | int BPlusTree::unmap(void* block, off_t offset, size_t size) const 633 | { 634 | openFile(); 635 | fseek(fp_, offset, SEEK_SET); 636 | size_t wt = fwrite(block, size, 1, fp_); // 向磁盘写入数据 637 | closeFile(); 638 | return wt - 1; 639 | } 640 | 641 | off_t BPlusTree::alloc(size_t size) 642 | { 643 | off_t slot = meta_.slot; 644 | meta_.slot += size; 645 | return slot; 646 | } 647 | 648 | off_t BPlusTree::alloc(leafNode* leaf) 649 | { 650 | leaf->n = 0; 651 | meta_.leafNodeNum++; 652 | return alloc(sizeof(leafNode)); 653 | } 654 | 655 | off_t BPlusTree::alloc(internalNode* node) 656 | { 657 | node->n = 1; 658 | meta_.internalNodeNum++; 659 | return alloc(sizeof(internalNode)); 660 | } 661 | 662 | void BPlusTree::unalloc(leafNode* leaf, off_t offset) 663 | { 664 | --meta_.leafNodeNum; 665 | } 666 | 667 | void BPlusTree::unalloc(internalNode* leaf, off_t offset) 668 | { 669 | --meta_.internalNodeNum; 670 | } 671 | 672 | } // namespace Explorer 673 | -------------------------------------------------------------------------------- /src/tree/bPlusTree.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_BPLUSTREE_H_ 2 | #define _EXPLORER_BPLUSTREE_H_ 3 | 4 | #include 5 | 6 | #include "bPlusTreeBase.h" 7 | 8 | namespace Explorer { 9 | 10 | #define OFFSET_META 0 11 | #define OFFSET_BLOCK (OFFSET_META + sizeof(meta)) 12 | #define SIZE_NO_CHILDREN (sizeof(leafNode) - ORDER * sizeof(record)) 13 | 14 | // 元数据 15 | typedef struct { 16 | size_t order; // B+树的阶数 17 | size_t valueSize; // 值大小 18 | size_t keySize; // 键大小 19 | size_t internalNodeNum; // 内部节点数目 20 | size_t leafNodeNum; // 叶节点数目 21 | size_t height; // 树高(不包括叶节点) 22 | off_t slot; // 索引文件中分配新节点的起始偏移位置 23 | off_t rootOffset; // 根节点位置偏移量 24 | off_t leafOffset; // 第一个叶子节点的位置偏移量 25 | } meta; 26 | 27 | // 内部节点的索引字段 28 | struct index { 29 | keyType key; // 节点存储的关键字,即键 30 | off_t child; // 子节点在索引文件中的偏移量 31 | }; 32 | 33 | // 内部节点 34 | struct internalNode { 35 | typedef index* child; 36 | off_t parent; // 父节点 37 | off_t next; // 下一个内部节点 38 | off_t prev; // 前一个内部节点 39 | size_t n; // 子节点数目 40 | index children[ORDER]; // 存储每个子节点位置偏移量及关键字 41 | }; 42 | 43 | // 叶子节点中的记录 44 | struct record { 45 | keyType key; 46 | valueType value; 47 | }; 48 | 49 | // 叶节点 50 | struct leafNode { 51 | typedef record* child; 52 | off_t parent; 53 | off_t next; 54 | off_t prev; 55 | size_t n; // 叶节点中记录数目 56 | record children[ORDER]; 57 | }; 58 | 59 | class BPlusTree 60 | { 61 | public: 62 | BPlusTree(const char* path, bool empty = false); 63 | 64 | // 成功:0;键已存在:-1 65 | int Insert(const keyType& key, valueType value); 66 | // 成功:0;键未找到:-1 67 | int Remove(const keyType& key); 68 | // 成功:0;出错:-1 69 | int Update(const keyType& key, valueType value); 70 | // 成功:0;未找到:-1 71 | int Search(const keyType& key, valueType* value) const; 72 | // 成功:查找到的值数目;参数错误:-1 73 | int SearchRange(keyType* left, const keyType& right, 74 | valueType* values, size_t max, bool *next = NULL) const; 75 | // 元数据 76 | meta GetMeta() const; 77 | 78 | private: 79 | char path_[512]; // 索引文件路径 80 | meta meta_; 81 | mutable FILE* fp_; // 索引文件指针 82 | mutable int fpLevel_; // 索引文件的引用计数 83 | 84 | private: 85 | // 打开/关闭索引文件 86 | void openFile(const char* mode = "rb+") const; 87 | void closeFile() const; 88 | 89 | // 从磁盘读入节点 90 | template 91 | int map(T* block, off_t offset) const; 92 | int map(void* block, off_t offset, size_t size) const; 93 | 94 | // 向磁盘写回节点 95 | template 96 | int unmap(T* block, off_t offset) const; 97 | int unmap(void* block, off_t offset, size_t size) const; 98 | 99 | // 创建新节点 100 | template 101 | void nodeCreate(off_t offset, T* node, T* next); 102 | 103 | // 销毁节点 104 | template 105 | void nodeRemove(T* prev, T* node); 106 | 107 | // 分配/撤销节点 108 | off_t alloc(size_t size); 109 | off_t alloc(leafNode* leaf); 110 | off_t alloc(internalNode* node); 111 | void unalloc(leafNode* leaf, off_t offset); 112 | void unalloc(internalNode* leaf, off_t offset); 113 | 114 | // 初始化索引文件存储结构 115 | void initFromEmpty(); 116 | 117 | // 返回键所在叶子节点的父节点偏移量 118 | off_t searchIndex(const keyType& key) const; 119 | 120 | // 返回键所在叶子节点的偏移量 121 | off_t searchLeaf(const keyType& key) const; 122 | 123 | // 返回键所在叶子节点的偏移量 124 | off_t searchLeaf(off_t parent, const keyType& key) const; 125 | 126 | 127 | // 不用分裂叶子节点的将key-value插入到叶子节点中适当位置 128 | // 移动插入点后元素,插入后保持记录有序 129 | void insertRecordNoSplit(leafNode* leaf, 130 | const keyType& key, 131 | const valueType& value); 132 | 133 | 134 | // 分裂的新节点更新父节点索引信息 135 | void insertKeyToIndex(off_t offset, const keyType& key, 136 | off_t old, off_t after); 137 | 138 | // 不用分裂父节点的将分裂的新叶子节点的首个key插入父节点中 139 | void insertKeyToIndexNoSplit(internalNode& node, 140 | const keyType& key, 141 | off_t value); 142 | 143 | // 设置内部索引节点的父节点 144 | void resetIndexChildrenParent(index* begin, index* end, off_t parent); 145 | 146 | void removeFromIndex(off_t offset, internalNode& node, const keyType& key); 147 | 148 | void mergeLeafs(leafNode* left, leafNode* right); 149 | 150 | void mergeKeys(index* where, internalNode& node, internalNode& next); 151 | 152 | bool borrowKey(bool fromRight, leafNode& borrower); 153 | 154 | bool borrowKey(bool fromRight, internalNode& borrower, off_t offset); 155 | 156 | void changeParentChild(off_t parent, const keyType& o, const keyType& n); 157 | }; 158 | 159 | template 160 | int BPlusTree::map(T* block, off_t offset) const 161 | { 162 | return map(block, offset, sizeof(T)); 163 | } 164 | 165 | template 166 | int BPlusTree::unmap(T* block, off_t offset) const 167 | { 168 | return unmap(block, offset, sizeof(T)); 169 | } 170 | 171 | template 172 | void BPlusTree::nodeCreate(off_t offset, T* node, T* next) 173 | { 174 | next->parent = node->parent; 175 | next->next = node->next; 176 | next->prev = offset; 177 | node->next = alloc(next); 178 | if (next->next != 0) 179 | { 180 | T oldNext; 181 | map(&oldNext, next->next, SIZE_NO_CHILDREN); 182 | oldNext.prev = node->next; 183 | unmap(&oldNext, next->next, SIZE_NO_CHILDREN); 184 | } 185 | unmap(&meta_, OFFSET_META); 186 | } 187 | 188 | template 189 | void BPlusTree::nodeRemove(T* prev, T* node) 190 | { 191 | unalloc(node, prev->next); 192 | prev->next = node->next; 193 | if (node->next != 0) 194 | { 195 | T next; 196 | map(&next, node->next, SIZE_NO_CHILDREN); 197 | next.prev = node->prev; 198 | unmap(&next, node->next, SIZE_NO_CHILDREN); 199 | } 200 | unmap(&meta_, OFFSET_META); 201 | } 202 | 203 | } // namespace Explorer 204 | 205 | #endif // _EXPLORER_BPLUSTREE_H_ 206 | -------------------------------------------------------------------------------- /src/tree/bPlusTreeBase.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXPLORER_BPLUSTREE_BASE_H_ 2 | #define _EXPLORER_BPLUSTREE_BASE_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace Explorer { 8 | 9 | // 每个内部节点的子节点数目 10 | // 每个叶子节点存储的记录数目 11 | #define ORDER 20 12 | 13 | typedef int valueType; 14 | 15 | struct keyType { 16 | char k[16]; 17 | 18 | keyType(const char* str = "") 19 | { 20 | bzero(k, sizeof(k)); 21 | strcpy(k, str); 22 | } 23 | }; 24 | 25 | inline int keyComp(const keyType& a, const keyType& b) 26 | { 27 | int diff = strlen(a.k) - strlen(b.k); 28 | return diff == 0 ? strcmp(a.k, b.k) : diff; 29 | } 30 | 31 | #define OPERATOR_KEYCMP(type) \ 32 | bool operator<(const keyType& l, const type& r) { \ 33 | return keyComp(l, r.key) < 0; \ 34 | } \ 35 | bool operator<(const type& l, const keyType& r) { \ 36 | return keyComp(l.key, r) < 0; \ 37 | } \ 38 | bool operator==(const keyType&l, const type& r) { \ 39 | return keyComp(l, r.key) == 0; \ 40 | } \ 41 | bool operator==(const type& l, const keyType& r) { \ 42 | return keyComp(l.key, r) == 0; \ 43 | } 44 | 45 | } // namespace Explorer 46 | 47 | #endif // _EXPLORER_BPLUSTREE_BASE_H_ 48 | --------------------------------------------------------------------------------