Pārlūkot izejas kodu

完成bloomfiter,但是还没有测试

Gogs 3 mēneši atpakaļ
vecāks
revīzija
54c8e5fc54

+ 1 - 0
#define.md

@@ -10,5 +10,6 @@
 
 #### SKIP_MAX_SIZE    //控制跳表是否有最大限制和在最大限制的行为,当没有最大限制时可以恒定一直插入,有最大限制时当数据量到达上限会返回full而不会进行插入,同时有不同的构造函数,并且引入新的change_size(int)函数,默认未定义。
 
+#### _RANDOM_LIST_    //启用之后在skiplist.h中加入create_random_list() public函数,能够初始化内部随机数表
 
 

+ 5 - 2
lib/basic/nanxing_operator_check.h

@@ -1,6 +1,7 @@
 #ifndef _NANXING_CHECK_OPERATOR_H_
 #define _NANXING_CHECK_OPERATOR_H_
 #include<type_traits>
+#include<iostream>
 //这个文件的目的是为了做一些匹配性检查,检查一些泛型的实例化是否能满足一定的要求
 //使用SFINAE
 //这个头文件的操作需要编译器至少支持C++11才能用,但是在C++20中引入的约束模板类型已经成功的将这些抽象的操作加入语法中
@@ -10,8 +11,10 @@
 #define NANXING_TYPETRAIT_TEMPLATE_T_V_ template<typename T ,typename V =void >
 #define NANXING_TYPETRAIT_TEMPLATE_T_ template<typename T > 
 #define NANXING_BASIC_OPERATOR_(Type, Op) nanxing::Op##_admit<Type>::value   //注意要写成这样才行
-#define NANXING_OPERATOR_FORBIDEN_(Type,Op) nanxing::op##_forbiden<Type>::value
-namespace nanxing{
+#define NANXING_OPERATOR_FORBIDEN_(Type,Op) nanxing::Op##_forbiden<Type>::value
+
+namespace nanxing
+{
     template<typename...>         //这里用泛型的作用在于为了后面做模板参数匹配
     using void_t=void;
 

+ 29 - 0
lib/extend/extend.md

@@ -0,0 +1,29 @@
+## extend
+<p>这个extend的目的是为了完成一个完整的数据库库,一个完整的数据库从的我的设计上看包含以下几个部分</p>
+
+## 基本组件
+<p>|-内存缓存</p>
+<p>|-查询过滤器</p>
+<p>|-持久化存储</p>
+<p>|-数据序列化</p>
+<p>|-数据反序列化</p>
+<p>|-LRU缓存</p>
+
+### 内存缓存
+用skiplist作为内存缓存数据结构,skiplist有实现简单,插入删除时间复杂度低,相对红黑树,插入删除调整方便,同时支持连续索引,redis和leveldb都是使用skiplist作为缓存。
+
+### 查询过滤器
+为了防止出现缓存穿透,提供了相应的过滤器,目前包括bloomfilter和Cuckoofilter来实现数据存在性校验
+
+### 持久化存储
+将数据持久化存储到磁盘上,在持久化存储中使用了lsm-tree来实现高性能写入
+
+### 数据序列化
+
+### 数据反序列化
+
+### LRU缓存
+使用LRU算法来实现内存查询缓存
+
+## 分布式扩展
+<p>|-raft一致性算法<p>

+ 68 - 14
lib/extend/filter.h

@@ -2,9 +2,13 @@
 #include<cmath>
 #include<cstdlib>
 #include<cstring>
+#include<exception>
 #include"../basic/nanxing_operator_check.h"
+
 namespace nanxing_extend
 {
+
+
     //这是个意外,本来是想工厂类和不同的过滤器划分到不同文件的,但是由于贯彻head_only,还没想出来怎么组织文件,只能丢在一起了
     //同时也是一个控制类,即这个类本身带有控制功能,只允许一次产生持有唯一的filter
     //如果不对产生的类进行管控,最后的结果很可能是完全无法处理,因为C++中内存分配方式过于多样,malloc,new,new[],数组。。。。乱七八糟,最后类内生成的空间完全无法析构,因为根本不知道类内怎么实现的
@@ -25,15 +29,18 @@ namespace nanxing_extend
         FilterPolicy(){};
         FilterPolicy(FilterPolicy&&){}
         virtual void policy_print(){producter->policy_print();}     //输出对应的计算公式 
-        virtual void parameter_print(){producter->parameter_print();}     //输出过滤器的参数             
+        virtual void parameter_print(){producter->parameter_print();}     //输出过滤器的参数  
+        virtual void insert(K key)noexcept{};           
         //两个工厂函数用于生成不同的过滤器    
         FilterPolicy* creat_Bloomfilter(int N,int P);
         FilterPolicy* creat_Cuckoofilter();  
-        virtual void init_filter(){producter->init_filter();}   
+        virtual void init_filter(){producter->init_filter();}    //初始化过滤器
         virtual ~FilterPolicy(){};
     };
+
+    //bloomfilter
     template<typename K>
-    class bloomfilter:public FilterPolicy
+    class bloomfilter:public FilterPolicy<K>
     {
         static_assert(NANXING_BASIC_OPERATOR_(K,compare),"the type of key cannot compare");
     private:
@@ -42,13 +49,13 @@ namespace nanxing_extend
         constexpr static const int hash_prime_number2[10]={94399,94421,94427,94433,94439,94441,94447,94463,94477,94483};             //哈希函数的置偏值
         struct param{
             float P;          //概率参数
-            int k;             //哈希函数个数
+            int k=0;             //哈希函数个数
             int n;             //n数据长度
-            int m;              //bloomfilter长度
+            int m=0;              //bloomfilter长度
             param(float _p,int _n):P(_p),n(_n){}
         };
     private:
-        u_int64_t* bitarray;               //bloomfilter的核心数据结构,一个比特数组
+        char* bitarray;               //bloomfilter的核心数据结构,一个比特数组
         param parameter;
         
     protected:
@@ -57,25 +64,71 @@ namespace nanxing_extend
         bloomfilter& operator=(bloomfilter)=delete;           //不允许复制构造
         void caculater()noexcept                              //计算bloomfilter的参数
         {
-            parameter.m=static_cast<int>(-(parameter.n*std::log(parameter.P)/0.4804530139));
-            parameter.k=static_cast<int>(0.6931471806*(parameter.m/parameter.n));
+            this->parameter.m=static_cast<int>(-(parameter.n*std::log(parameter.P)/0.4804530139));
+            this->parameter.k=static_cast<int>(0.6931471806*(parameter.m/parameter.n));
         }
         int hash_function(int i,K data)                              //i代表第i个哈希函数,返回在bloomfilter中的位置
         {
             return ((static_cast<int>(data))*(this->hash_prime_number1[i])+(this->hash_prime_number2[i]))%(this->parameter.m);
         }
     public:
-        bloomfilter(float _p,int _n):bitarray(0),parameter(_p,_n){}
+        bloomfilter(float _p,int _n):bitarray(nullptr),parameter(_p,_n){}
+
         void init_filter()override{
+        LOOP:
             caculater();
-            bitarray=new u_int64_t[static_cast<int>(parameter.m/64)+1];           //构建数组
-            std::memset(bitarray,0,sizeof(u_int64_t)*static_cast<int>(parameter.m/64)+1);   //初始化
+        LOOP1:
+            try{
+                bitarray=new char[static_cast<int>(parameter.m/8)+1];           //构建数组
+            }
+            catch(std::bad_alloc)
+            {
+                char tmp_input;
+                std::cerr<<"May not have enough memory to use"<<std::endl;
+                std::cerr<<"if you want to try again,please input r"<<std::endl;
+                std::cerr<<"if you want to exit please input e"<<std::endl;
+                std::cerr<<"if you want to use less bloomfilter with higher error rates,please input p"<<std::endl;
+                std::cin>>tmp_input;
+                switch(tmp_input)
+                {
+                    case 'r':
+                        goto LOOP1;
+                        break;
+                    case 'e':
+                        std::terminate();
+                        break;
+                    case 'p':
+                        std::cerr<<"please input the new P by float"<<std::endl;
+                        std::cin>>this->parameter.P;
+                        goto LOOP;
+                        break;
+                }
+            }
+            std::memset(bitarray,0,sizeof(char)*static_cast<int>(parameter.m/8)+1);   //初始化
         }
+
         void policy_print()override                  //打印出使用的公式
         {
             std::cout<<"m=-((nlnP)/((ln2)^2))"<<"//m为bloomfilter的长度"<<std::endl;
             std::cout<<"k=ln2*(m/n)"<<"//k为所需的哈希函数的个数"<<std::endl;
         }
+
+        void insert(K key)noexcept override
+        {
+            if(this->parameter.k==0)
+            {
+                std::cerr<<"the filter never init,and the filter is useless."<<std::endl;
+                return;
+            }
+            for(int i=0;i<this->parameter.k;i++)
+            {
+                int tmp=this->hash_function(i,key);
+                int filter_u=static_cast<int>(tmp/8);
+                int move=tmp%8;
+                this->bitarray[filter_u]||('1'<<(7-move));
+            }
+        }
+
         virtual ~bloomfilter()
         {
             if(bitarray!=nullptr)
@@ -85,8 +138,9 @@ namespace nanxing_extend
         }  
     };
 
+    //布谷鸟过滤器
     template<typename K>
-    class Cuckoofilter:public FilterPolicy
+    class Cuckoofilter:public FilterPolicy<K>
     {
         static_assert(NANXING_BASIC_OPERATOR_(K,compare),"the type of key cannot compare");
     };
@@ -98,7 +152,7 @@ namespace nanxing_extend
         {
             delete producter;
         }
-        producter=new bloomfilter(N,P);
+        producter=new bloomfilter<K>(N,P);
         return producter;
     }
 
@@ -109,7 +163,7 @@ namespace nanxing_extend
         {
             delete producter;
         }
-        producter=new Cuckoofilter;
+        producter=new Cuckoofilter<K>;
         return producter;
     }
 }

+ 37 - 30
lib/extend/skiplist.h

@@ -136,7 +136,7 @@ namespace nanxing_extend
                 std::terminate();
             }
         }
-    #elif
+    #else
         skipList(int _max_level,int _max_size):max_size(_max_size),max_level(_max_level),random_level(nullptr)
         {
             try
@@ -154,7 +154,34 @@ namespace nanxing_extend
                 throw newNode_error();
             }
         }
-    #endif                       
+    #endif              
+
+    #ifdef _RANDOM_LIST_
+        void create_random_list()                 //直接生成随机数表
+        {
+        #ifdef NANXING_THREAD_
+            std::lock_guard<std::shared_mutex> lock(RW_lock);             
+        #endif
+            if(random_level!=nullptr)
+            {
+                return;
+            }            
+            try{
+                random_level=::new int[1024];                     //刚好是一页的大小(4KB)
+            }
+            catch(std::bad_alloc)
+            {
+                throw random_error();
+                return;
+            }
+            std::mt19937 rnd(std::chrono::system_clock::now().time_since_epoch().count());
+            for(int i=0;i<1024;i++)
+            {
+                random_level[i]=(rnd()%max_level)+1;
+            }
+        }
+    #endif
+         
         auto insert(K _key,V _value)->std::variant<Skip_result,V>              //如果相同的时候我们考虑将value返回,由于限制为侵入式链表因此实际上不会内存泄露
         {
         #ifdef NANXING_THREAD_
@@ -168,7 +195,11 @@ namespace nanxing_extend
             }
         #endif
             int rand_level=0;
-            ptr updata[max_level]={nullptr};          //用于更新的数组
+            ptr* updata=new ptr[max_level];          //用于更新的数组
+            for(int i=0;i<max_level;i++)
+            {
+                updata[i]=nullptr;
+            }
             ptr point=head[max_level-1];
             
             ptr new_node;
@@ -200,8 +231,8 @@ namespace nanxing_extend
                         point=point->next_node[i];              //更新point指针
                     }
                 }
-            }                
-            [[likely]]
+            }
+            [[likely]]                
             if(random_level!=nullptr)
             {
                 rand_level=random_level[current_size%1024];
@@ -233,7 +264,7 @@ namespace nanxing_extend
             std::variant<Skip_result,V> sk;
             if(current_size==0)
             {
-                std:cerr<<"The skiplist is empty"<<std::endl;
+                std::cerr<<"The skiplist is empty"<<std::endl;
                 return sk=Skip_result::empty;
             }
             else
@@ -313,30 +344,6 @@ namespace nanxing_extend
             return sk=Skip_result::falure;
         }
                 
-        void init_skip()                 //直接生成随机数表
-        {
-        #ifdef NANXING_THREAD_
-            std::lock_guard<std::shared_mutex> lock(RW_lock);             
-        #endif
-            if(random_level!=nullptr)
-            {
-                return;
-            }            
-            try{
-                random_level=::new int[1024];                     //刚好是一页的大小(4KB)
-            }
-            catch(std::bad_alloc)
-            {
-                throw random_error();
-                return;
-            }
-            std::mt19937 rnd(std::chrono::system_clock::now().time_since_epoch().count());
-            for(int i=0;i<1024;i++)
-            {
-                random_level[i]=(rnd()%max_level)+1;
-            }
-        }
-
 
         void Print()noexcept
         {

BIN
lib/tests/skiplist_test


+ 5 - 3
lib/tests/skiplist_test.cpp

@@ -1,5 +1,6 @@
 #define _NANXING_TEST_
-#include"../STL/extend/skiplist.h"
+#define _RANDOM_LIST_
+#include"../extend/skiplist.h"
 #include"time.h"
 
 void test_insert(int roll,int key_type,int level,bool control)                                //roll代表插入次数,key_type代表给出的key的随机数总数,control代表是否启用init
@@ -8,7 +9,8 @@ void test_insert(int roll,int key_type,int level,bool control)
     int random[key_type];
     if(control==1)
     {
-        test.init_skip();               //启用内部随机数表
+        
+        test.create_random_list();               //启用内部随机数表
     }
     std::mt19937 rnd(std::chrono::system_clock::now().time_since_epoch().count());
     for(auto& i:random)
@@ -28,6 +30,6 @@ void test_insert(int roll,int key_type,int level,bool control)
 
 int main()
 {
-    std::function<void()> fun{std::bind(test_insert,20000000,10240,15,false)};
+    std::function<void()> fun{std::bind(test_insert,2000000,10240,15,false)};
     nanxing_test::time_test(fun);
 }

+ 1 - 1
test.cpp

@@ -1,6 +1,6 @@
 #include<iostream>
 #include<typeinfo>
-#include"STL/extend/skiplist.h"
+#include"lib/extend/skiplist.h"
 #include<functional>
 #include<future>
 #include<chrono>