├── src ├── main │ ├── resources │ │ ├── mapfile │ │ │ └── 11.txt │ │ └── cfg.properties │ └── java │ │ └── io │ │ └── mycat │ │ └── bigmem │ │ ├── buffer │ │ ├── SwapByteBuffer.java │ │ ├── CompositeByteBuf.java │ │ ├── BufferAllocator.java │ │ ├── CatCallbackInf.java │ │ ├── ByteBuffer.java │ │ ├── Handle.java │ │ ├── ReferenceCounted.java │ │ ├── DirectArena.java │ │ ├── CacheThreadLocal.java │ │ ├── BitSet.java │ │ ├── AbstractReferenceCountedByteBuf.java │ │ ├── MemoryAllocator.java │ │ ├── Subpage.java │ │ └── ChunkList.java │ │ ├── sqlcache │ │ ├── package-info.java │ │ ├── IDataLoader.java │ │ ├── IRemoveKeyListener.java │ │ ├── ICache.java │ │ ├── impl │ │ │ ├── directmem │ │ │ │ ├── DirectMemoryFactory.java │ │ │ │ └── DirectMemorySQLResult.java │ │ │ └── mmap │ │ │ │ └── MappedMemFileBufferPage.java │ │ ├── IBufferPageFactory.java │ │ ├── IBufferPage.java │ │ ├── ISQLResult.java │ │ ├── AddressIndex.java │ │ ├── Keyer.java │ │ ├── BigSQLResult.java │ │ ├── MyCatBufferPage.java │ │ ├── CacheImp.java │ │ └── PageLRUCache.java │ │ ├── util │ │ ├── StringUtil.java │ │ ├── IOutils.java │ │ ├── MathUtil.java │ │ ├── ThreadPool.java │ │ ├── IllegalReferenceCountException.java │ │ ├── UnsafeMemory.java │ │ ├── PropertiesUtils.java │ │ ├── Utils.java │ │ ├── MpsQueue.java │ │ ├── internal │ │ │ └── ObjectUtil.java │ │ ├── UnsafeHelper.java │ │ └── ByteUtil.java │ │ ├── MycatBigMemory.java │ │ ├── chunkpageallot │ │ ├── recycle │ │ │ ├── MemoryPageClearUpInf.java │ │ │ └── impl │ │ │ │ └── MarkMovePageRecycleImpl.java │ │ ├── bufferpage │ │ │ ├── BufferPageMoveInf.java │ │ │ ├── BufferPageBase.java │ │ │ └── impl │ │ │ │ ├── DirectBufferPage.java │ │ │ │ └── FileMapBufferPage.java │ │ ├── MemoryAllocatorInf.java │ │ ├── buffer │ │ │ ├── DirectMemAddressInf.java │ │ │ ├── MycatSwapBufer.java │ │ │ ├── MycatMovableBufer.java │ │ │ ├── MycatBuffer.java │ │ │ ├── impl │ │ │ │ ├── DirectMycatBufferImpl.java │ │ │ │ └── DirectMycatBufferMoveImpl.java │ │ │ └── MycatBufferBase.java │ │ ├── console │ │ │ ├── BufferException.java │ │ │ └── ChunkMemoryAllotEnum.java │ │ ├── alloctor │ │ │ ├── ChunkMemoryAllotInf.java │ │ │ ├── impl │ │ │ │ ├── ChunkDirectMoveMemoryImpl.java │ │ │ │ ├── ChunkDirectMemoryImpl.java │ │ │ │ └── ChunkFileMapMemoryImpl.java │ │ │ └── MycatMemoryAllocator.java │ │ └── MycatMemoryAllocatorFactory.java │ │ ├── mempool │ │ ├── MyCatMemAlloctorImp.java │ │ ├── MyCatByteBuf.java │ │ └── PoolBuddyChunk.java │ │ ├── strategy │ │ ├── impl │ │ │ ├── FileMapCacheStategyImpl.java │ │ │ └── DirectMemCacheStategyImpl.java │ │ ├── CacheStrategyInf.java │ │ └── CacheStrategy.java │ │ ├── console │ │ ├── LocatePolicy.java │ │ └── PropertiesKeyEnum.java │ │ └── MyCatBigSqlResultsCache.java └── test │ ├── resources │ └── cfg.properties │ └── java │ └── io │ └── mycat │ └── bigmem │ ├── buffer │ ├── directmemory │ │ ├── TestFlag.java │ │ └── TestDirectBufferPool.java │ └── mapfile │ │ └── TestMapFileBuffer.java │ ├── allot │ ├── TestMycatBufferAllot.java │ ├── TestMycatBufferMemoryDirectAllot.java │ ├── recycle │ │ ├── MoveBufferRecycle.java │ │ └── mark │ │ │ ├── MarkMoveBufferRecycle2.java │ │ │ └── MarkMoveBufferRecycle.java │ └── TestMycatBufferMemoryMoveAllot.java │ └── sqlcache │ └── testBigSQLResultCache.java ├── doc ├── 系统架构.vsd ├── 缓存架构图.vsd ├── buffer类图.vsd ├── 内存分配类图.jpg ├── 内存分配类图.vsd ├── 内存页的移动.vsd ├── 结存结构说明.pptx ├── Cache 定制实现类图.png ├── BigResultCache.png ├── MycatBigMemory接口定义及参考说明.pptx ├── Cache定制实现类图.uml └── BigResultCache.uml ├── README.md └── pom.xml /src/main/resources/mapfile/11.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/系统架构.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/系统架构.vsd -------------------------------------------------------------------------------- /doc/缓存架构图.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/缓存架构图.vsd -------------------------------------------------------------------------------- /doc/buffer类图.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/buffer类图.vsd -------------------------------------------------------------------------------- /doc/内存分配类图.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/内存分配类图.jpg -------------------------------------------------------------------------------- /doc/内存分配类图.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/内存分配类图.vsd -------------------------------------------------------------------------------- /doc/内存页的移动.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/内存页的移动.vsd -------------------------------------------------------------------------------- /doc/结存结构说明.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/结存结构说明.pptx -------------------------------------------------------------------------------- /doc/Cache 定制实现类图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/Cache 定制实现类图.png -------------------------------------------------------------------------------- /doc/BigResultCache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/BigResultCache.png -------------------------------------------------------------------------------- /doc/MycatBigMemory接口定义及参考说明.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyCATApache/Mycat-BigMemoryAPI/HEAD/doc/MycatBigMemory接口定义及参考说明.pptx -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/SwapByteBuffer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | public class SwapByteBuffer { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/cfg.properties: -------------------------------------------------------------------------------- 1 | #\u591a\u79cd\u5185\u5b58\u5206\u914d\u7684\u5b9e\u73b0\u7c7b 2 | mycat.memory.allot.class=io.mycat.bigmem.cacheway.alloctor.MycatMemoryAllocator -------------------------------------------------------------------------------- /src/test/resources/cfg.properties: -------------------------------------------------------------------------------- 1 | #\u591a\u79cd\u5185\u5b58\u5206\u914d\u7684\u5b9e\u73b0\u7c7b 2 | mycat.memory.allot.class=io.mycat.bigmem.cacheway.alloctor.MycatMemoryAllocator -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mycat-BigMemoryAPI 2 | Mycat Big Memory API for Big Data Process and High performance program 3 | 4 | 5 | 关于项目信息,注意点: 6 | 1,需要生成javadoc信息,提交的代码的注意,不能有doc编译问题!(现在代码是自动生成javadoc信息的,不要跳过生成) 7 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/package-info.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | /** 4 | * 5 | * testCase: 6 | * \test\java\io\mycat\bigmem\sqlcache\testBigSQLResultCache.java 7 | * */ -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/CompositeByteBuf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | /** 4 | * Created by tracywwp on 2017/1/12 0012. 5 | * 实现零拷贝 ByteBuf 6 | */ 7 | public class CompositeByteBuf { 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | 2 | package io.mycat.bigmem.util; 3 | /** 4 | * 5 | *or zhangwy 2017年1月4日 上午7:38:12 6 | **/ 7 | public class StringUtil { 8 | public static final String NEWLINE = System.getProperty("line.separator"); 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /doc/Cache定制实现类图.uml: -------------------------------------------------------------------------------- 1 | 2 | 3 | JAVA 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | All 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/BufferAllocator.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | 4 | /** 5 | * allocator , recycle and gc buffers 6 | * or shenli 7 | * 8 | */ 9 | public interface BufferAllocator { 10 | 11 | public DirectByteBuffer directBuffer(int capacity); 12 | 13 | public void recycle(DirectByteBuffer theBuf) ; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/MycatBigMemory.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem; 2 | 3 | /** 4 | * 进行内存管理的主函数入口 5 | * 源文件名:MycatBigMemory.java 6 | * 文件版本:1.0.0 7 | * 创建作者:Think 8 | * 创建日期:2016年12月22日 9 | * 修改作者:Think 10 | * 修改日期:2016年12月22日 11 | * 文件描述:TODO 12 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 13 | */ 14 | public class MycatBigMemory { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/IDataLoader.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | /** 4 | * Value 数据加载接口 5 | * 6 | * or zagnix 7 | * @version 1.0 8 | * 2016-12-30 16:44 9 | */ 10 | public interface IDataLoader{ 11 | 12 | /** 13 | * Key失效,时候重新异步reload数据 14 | * @param keyer 参数 15 | * @return 返回 16 | */ 17 | public V reload(Keyer keyer); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/IRemoveKeyListener.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | /** 4 | * key 被移除时,回调该接口 5 | * 6 | * or zagnix 7 | * @version 1.0 8 | * 2016-12-30 16:47 9 | */ 10 | public interface IRemoveKeyListener { 11 | 12 | /** 13 | * 当Key被移除时,回调该接口 14 | * 15 | * @param key 参数 16 | * @param value 参数 17 | */ 18 | public void removeNotify(K key,V value); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/recycle/MemoryPageClearUpInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.recycle; 2 | 3 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageBase; 4 | 5 | /** 6 | * 进行内存页的内存整理的接口 7 | * or kk 8 | * 2017年1月2日 9 | */ 10 | public interface MemoryPageClearUpInf { 11 | 12 | /** 13 | * 进行内存页的数据整理接口定义 14 | * @param page 内存页信息 15 | */ 16 | public void pageClearUp(BufferPageBase page); 17 | 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/IOutils.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.io.Closeable; 4 | import java.io.IOException; 5 | 6 | public class IOutils { 7 | /** 8 | * 关闭流 9 | * @param stream 流参数 10 | */ 11 | public static void closeStream(Closeable stream) { 12 | if (null != stream) { 13 | try { 14 | stream.close(); 15 | } catch (IOException e) { 16 | e.printStackTrace(); 17 | } 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/CatCallbackInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | /** 4 | * 进行回调的相关的接口定义 5 | * 源文件名:MyCatCallbackInf.java 6 | * 文件版本:1.0.0 7 | * 创建作者:Think 8 | * 创建日期:2016年12月22日 9 | * 修改作者:Think 10 | * 修改日期:2016年12月22日 11 | * 文件描述:TODO 12 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 13 | */ 14 | public interface CatCallbackInf { 15 | 16 | /** 17 | * 进行异步的通知 18 | * 方法描述 19 | * @throws Exception 20 | * 2016年12月26日 21 | */ 22 | public void callBack() throws Exception; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/mempool/MyCatMemAlloctorImp.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.mempool; 2 | 3 | import io.mycat.bigmem.chunkpageallot.MemoryAllocatorInf; 4 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 5 | 6 | /** 7 | * Created by znix on 2016/12/31. 8 | */ 9 | public class MyCatMemAlloctorImp implements MemoryAllocatorInf{ 10 | @Override 11 | public MycatBufferBase allocMem(int allocFlag, int size) { 12 | return null; 13 | } 14 | 15 | @Override 16 | public void recyleMem(MycatBufferBase bufer) { 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/bufferpage/BufferPageMoveInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.bufferpage; 2 | 3 | import java.util.Set; 4 | 5 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 6 | 7 | /** 8 | * 用于定义内存页的接口信息 9 | * @author kk 10 | * @version 0.0.1 11 | */ 12 | public interface BufferPageMoveInf { 13 | 14 | /** 15 | * 获取分配出去的内存引用信息 16 | * @return 返回 17 | */ 18 | public Set getSliceMemory(); 19 | 20 | /** 21 | * 进行目标数据的拷贝操作 22 | * @param useBuffer 分配的内存对象的信息 23 | * @param notUseIndex 索引 24 | */ 25 | public void memoryCopy(MycatBufferBase useBuffer,int notUseIndex); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/MemoryAllocatorInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | 5 | /** 6 | * 整体的内存的分配接口 7 | * or liujun 8 | * 2016年12月29日 9 | */ 10 | public interface MemoryAllocatorInf { 11 | 12 | /** 13 | * 进行缓存空间的分配 14 | * 方法描述 15 | * @param allocFlag 按位来进行的 16 | * @param size 需要的内存大小 17 | * @return 18 | * 2016年12月20日 19 | */ 20 | public MycatBufferBase allocMem(int allocFlag, int size); 21 | 22 | /** 23 | * 进行缓存空间的部分释放,即释放buffer的limit与capacity之间的空间释放 24 | * 方法描述 25 | * @param bufer 参数 26 | * 2016年12月20日 27 | */ 28 | public void recyleMem(MycatBufferBase bufer); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/buffer/DirectMemAddressInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.buffer; 2 | 3 | /** 4 | * 直接内存操作接口相关的地址信息 5 | * 源文件名:DirectMemoryAddressInf.java 6 | * 文件版本:1.0.0 7 | * 创建作者:Think 8 | * 创建日期:2016年12月23日 9 | * 修改作者:Think 10 | * 修改日期:2016年12月23日 11 | * 文件描述:TODO 12 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 13 | */ 14 | public interface DirectMemAddressInf { 15 | 16 | /** 17 | * 获得内存地址的方法 18 | * 方法描述 19 | * @return 20 | * 2016年12月23日 21 | */ 22 | public long address(); 23 | 24 | /** 25 | * 获得附着的对象 26 | * 方法描述 27 | * @return 28 | * 2016年12月23日 29 | */ 30 | public Object getAttach(); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/MathUtil.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | public class MathUtil { 4 | /* 5 | * 求log 6 | * */ 7 | public static int log2p(int x) { 8 | int r = 0; 9 | while ((x >>= 1) != 0) 10 | r++; 11 | return r; 12 | } 13 | /* 14 | * 返回最接近x的2的n次方的 15 | * 16 | * */ 17 | public static int roundToPowerOfTwo(int x) { 18 | x --; 19 | x |= x >>> 1; 20 | x |= x >>> 2; 21 | x |= x >>> 4; 22 | x |= x >>> 8; 23 | x |= x >>> 16; 24 | x++; 25 | if (x < 0) { 26 | x >>>= 1; 27 | } 28 | return x; 29 | } 30 | public static void main(String[] args) { 31 | System.out.println(roundToPowerOfTwo(699999999)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/strategy/impl/FileMapCacheStategyImpl.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.strategy.impl; 2 | 3 | import java.util.Map; 4 | 5 | import io.mycat.bigmem.strategy.CacheStrategyInf; 6 | 7 | /** 8 | * 使用文件影射的缓存策略 9 | * 源文件名:FileMapCacheStategyImpl.java 10 | * 文件版本:1.0.0 11 | * 创建作者:liujun 12 | * 创建日期:2016年12月20日 13 | * 修改作者:liujun 14 | * 修改日期:2016年12月20日 15 | * 文件描述:TODO 16 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 17 | */ 18 | public class FileMapCacheStategyImpl implements CacheStrategyInf { 19 | 20 | @Override 21 | public T getBufferData(Map p) { 22 | return null; 23 | } 24 | 25 | @Override 26 | public boolean writeBufferdata(Map p) { 27 | return false; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/strategy/CacheStrategyInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.strategy; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 用来进行缓存的策略的接口 7 | * 源文件名:MemcacheInf.java 8 | * 文件版本:1.0.0 9 | * 创建作者:liujun 10 | * 创建日期:2016年12月20日 11 | * 修改作者:liujun 12 | * 修改日期:2016年12月20日 13 | * 文件描述:TODO 14 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 15 | */ 16 | public interface CacheStrategyInf { 17 | 18 | /** 19 | * 从缓存中获取数据 20 | * @param p 参数 21 | * @param 返回的泛型信息 22 | * @return 返回信息 23 | */ 24 | public T getBufferData(Map p); 25 | 26 | /** 27 | * 进行数据写入缓存 28 | * 方法描述 29 | * @param p 写入的查询结果集信息 30 | * @return 返回 31 | * 2016年12月20日 32 | */ 33 | public boolean writeBufferdata(Map p); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/ICache.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | /** 4 | * 定制化 Cache接口 5 | * 主要实现SQL结果集缓存规则 6 | * 1.缓存时间 7 | * 2.在缓存时间内,访问次数超过N次,重新从DB后台load数据,更新Value 8 | * or zagnix 9 | * @version 1.0 10 | * 2016-12-30 11:26 11 | */ 12 | public interface ICache { 13 | 14 | /** 15 | * 放入 16 | * @param key 参数 17 | * @param value 值 18 | * @param keyer 参数 19 | */ 20 | public void put(final K key,final V value,final Keyer keyer); 21 | 22 | /** 23 | * 24 | * @param key 参数 25 | * @return 返回 26 | */ 27 | public V get(final K key); 28 | 29 | 30 | /** 31 | * 参数信息 32 | * @param key 参数信息 33 | */ 34 | public void remove(final K key); 35 | 36 | /** 37 | * 38 | */ 39 | public void removeALL(); 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/console/LocatePolicy.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.console; 2 | 3 | /** 4 | * 策略信息 5 | * 源文件名:LocatePolicy.java 6 | * 文件版本:1.0.0 7 | * 创建作者:Think 8 | * 创建日期:2016年12月27日 9 | * 修改作者:Think 10 | * 修改日期:2016年12月27日 11 | * 文件描述:TODO 12 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 13 | */ 14 | public enum LocatePolicy { 15 | 16 | /** 17 | * 使用本地的内存进行缓存的策略 18 | * Core 19 | */ 20 | Core(1), 21 | 22 | /** 23 | * 使用文件进行映射的缓存的策略信息 24 | * Normal 25 | */ 26 | Normal(2); 27 | 28 | /** 29 | * 策略信息 30 | * policy 31 | */ 32 | private int policy; 33 | 34 | public int getPolicy() { 35 | return policy; 36 | } 37 | 38 | public void setPolicy(int policy) { 39 | this.policy = policy; 40 | } 41 | 42 | private LocatePolicy(int policy) { 43 | this.policy = policy; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/console/BufferException.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.console; 2 | 3 | /** 4 | * buffer相关的运行时异常信息 5 | * 源文件名:BufferException.java 6 | * 文件版本:1.0.0 7 | * 创建作者:liujun 8 | * 创建日期:2016年12月26日 9 | * 修改作者:liujun 10 | * 修改日期:2016年12月26日 11 | * 文件描述:TODO 12 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 13 | */ 14 | public class BufferException extends RuntimeException { 15 | 16 | /** 17 | * serialVersionUID 18 | */ 19 | private static final long serialVersionUID = 1L; 20 | 21 | /** 22 | * 纯描述信息 23 | * 构造方法 24 | * @param msg 消息 25 | */ 26 | public BufferException(String msg) { 27 | super(msg); 28 | } 29 | 30 | /** 31 | * 带异步信息 32 | * 构造方法 33 | * @param msg 消息 34 | * @param e 参数 35 | */ 36 | public BufferException(String msg, Throwable e) { 37 | super(msg, e); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/buffer/directmemory/TestFlag.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer.directmemory; 2 | 3 | public class TestFlag { 4 | 5 | public static void main(String[] args) { 6 | int tem1 = 1; 7 | print(tem1); 8 | 9 | int temp2 = 1<<1; 10 | print(temp2); 11 | 12 | int temp3 = 1<<2; 13 | print(temp3); 14 | 15 | 16 | int value4 = 7; 17 | print(value4); 18 | 19 | int value5 = 7&2; 20 | print(value5); 21 | 22 | int value6 = 7&4; 23 | print(value6); 24 | 25 | int value7= 1 <<0; 26 | print(value7); 27 | 28 | 29 | 30 | } 31 | 32 | public static void print(int value) 33 | { 34 | System.out.print(value + "\t"); 35 | System.out.println(Integer.toBinaryString(value)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/ByteBuffer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | public interface ByteBuffer { 4 | 5 | public abstract long readerIndex(); 6 | 7 | public abstract long writerIndex(); 8 | 9 | public abstract byte getByte(long index); 10 | 11 | public abstract short getShort(long index); 12 | 13 | public abstract int getInt(long index); 14 | 15 | public abstract long getLong(long index); 16 | 17 | public abstract float getFloat(long index); 18 | 19 | public abstract double getDouble(long index); 20 | 21 | public abstract byte putByte(long index, byte value); 22 | 23 | public abstract byte putShort(long index, short value); 24 | 25 | public abstract byte putInt(long index, int value); 26 | 27 | public abstract byte putLong(long index, long value); 28 | 29 | public abstract byte putFloat(long index, float value); 30 | 31 | public abstract byte putDouble(long index, double value); 32 | 33 | } -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/alloctor/ChunkMemoryAllotInf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.alloctor; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | 5 | /** 6 | * 大块的内存分配接口 7 | * or liujun 8 | * 2016年12月29日 9 | */ 10 | public interface ChunkMemoryAllotInf { 11 | 12 | /** 13 | * 进行分配内在的初始化操作 14 | * @param memSize 内存大小 15 | * @param chunkSize 块内存的大小 16 | * @param poolSize 内存池的大小 17 | */ 18 | public void allotorInit(int memSize, int chunkSize, short poolSize); 19 | 20 | /** 21 | * 进行缓存空间的分配 22 | * @param size 需要的内存大小 23 | * @return 返回信息 24 | */ 25 | public MycatBufferBase allocMem(int size); 26 | 27 | /** 28 | * 进行缓存空间的部分释放,即释放buffer的limit与capacity之间的空间释放 29 | * 方法描述 30 | * @param buffer 缓存 31 | * @return 返回是否为当前的chunk所回收 32 | * 2016年12月20日 33 | */ 34 | public boolean recyleMem(MycatBufferBase buffer); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/Handle.java: -------------------------------------------------------------------------------- 1 | 2 | package io.mycat.bigmem.buffer; 3 | 4 | /** 5 | * 分配的内存的句柄 6 | *or zhangwy 2017年1月7日 上午8:25:53 7 | **/ 8 | public class Handle { 9 | 10 | private long handle; 11 | private Chunk chunk; 12 | private int capacity; 13 | 14 | /** 15 | * 构造 16 | * @param handle 参数 17 | * @param chunk 参数 18 | * @param capacity 参数 19 | */ 20 | public Handle(long handle, Chunk chunk, int capacity) { 21 | super(); 22 | this.handle = handle; 23 | this.chunk = chunk; 24 | this.capacity = capacity; 25 | } 26 | public long getHandle() { 27 | return handle; 28 | } 29 | public void setHandle(long handle) { 30 | this.handle = handle; 31 | } 32 | public Chunk getChunk() { 33 | return chunk; 34 | } 35 | public void setChunk(Chunk chunk) { 36 | this.chunk = chunk; 37 | } 38 | public int getCapacity() { 39 | return capacity; 40 | } 41 | public void setCapacity(int capacity) { 42 | this.capacity = capacity; 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/ThreadPool.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | 7 | public class ThreadPool { 8 | 9 | /** 10 | * 线程池对象 11 | * POOLEXECUTOR 12 | */ 13 | private ExecutorService POOLEXECUTOR = Executors.newFixedThreadPool(10); 14 | 15 | private static final ThreadPool POOL_INSTANCE = new ThreadPool(); 16 | 17 | public static ThreadPool Instance() { 18 | return POOL_INSTANCE; 19 | } 20 | 21 | /** 22 | * 提交一个无返回值的任务 23 | * 方法描述 24 | * @param runjob 25 | * 2016年12月26日 26 | */ 27 | public void submit(Runnable runjob) { 28 | POOLEXECUTOR.submit(runjob); 29 | } 30 | 31 | /** 32 | * 提交一个带返回值的任务 33 | * @param callJob 参数 34 | * @param 参数信息 35 | */ 36 | public void submit(Callable callJob) { 37 | POOLEXECUTOR.submit(callJob); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/console/PropertiesKeyEnum.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.console; 2 | 3 | /** 4 | * 配制文件的key的信息 5 | * or liujun 6 | * 2016年12月30日 7 | * @version 0.0.1 8 | */ 9 | public enum PropertiesKeyEnum { 10 | 11 | /** 12 | * 进行内存分配算法的默认的实现 13 | */ 14 | MYCAT_MEMORY_ALLOT_CLASS("mycat.memory.allot.class",""); 15 | 16 | 17 | /** 18 | * 分配的内存标识 19 | * key 20 | */ 21 | private String key; 22 | 23 | /** 24 | * 类的相关信息 25 | * classFile 26 | */ 27 | private String value; 28 | 29 | 30 | 31 | private PropertiesKeyEnum(String key, String value) { 32 | this.key = key; 33 | this.value = value; 34 | } 35 | 36 | public String getKey() { 37 | return key; 38 | } 39 | 40 | public void setKey(String key) { 41 | this.key = key; 42 | } 43 | 44 | public String getValue() { 45 | return value; 46 | } 47 | 48 | public void setValue(String value) { 49 | this.value = value; 50 | } 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/impl/directmem/DirectMemoryFactory.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache.impl.directmem; 2 | 3 | import io.mycat.bigmem.sqlcache.IBufferPageFactory; 4 | import io.mycat.bigmem.sqlcache.MyCatBufferPage; 5 | 6 | import java.io.IOException; 7 | import java.util.Set; 8 | 9 | /** 10 | * Direct Memroy Page Factory 11 | * 12 | * or zagnix 13 | * 2016-12-28 07:46 14 | */ 15 | 16 | public class DirectMemoryFactory implements IBufferPageFactory{ 17 | public MyCatBufferPage acquirePage(long index) throws IOException { 18 | return null; 19 | } 20 | 21 | public void releasePage(long index) { 22 | 23 | } 24 | 25 | public void deletePage(long index) throws IOException { 26 | 27 | } 28 | 29 | public void flush() { 30 | 31 | } 32 | 33 | public void deleteAllPages() throws IOException { 34 | 35 | } 36 | 37 | public Set getExistingPageIndexSet() { 38 | return null; 39 | } 40 | 41 | public void releaseCachedPages() throws IOException { 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/impl/directmem/DirectMemorySQLResult.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache.impl.directmem; 2 | 3 | import io.mycat.bigmem.sqlcache.ISQLResult; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * 基于Direct Memory Cache,用queue实现 9 | * 10 | * or zagnix 11 | * 2016-12-28 07:46 12 | */ 13 | 14 | public class DirectMemorySQLResult implements ISQLResult { 15 | public long put(byte[] data) throws IOException { 16 | return 0; 17 | } 18 | 19 | public byte[] next() throws IOException { 20 | return new byte[0]; 21 | } 22 | 23 | public byte[] get(long index) throws IOException { 24 | return new byte[0]; 25 | } 26 | 27 | public long size() { 28 | return 0; 29 | } 30 | 31 | public boolean isEmpty() { 32 | return false; 33 | } 34 | 35 | public boolean isFull() { 36 | return false; 37 | } 38 | 39 | public void flush() { 40 | 41 | } 42 | 43 | public void removeAll() throws IOException { 44 | 45 | } 46 | 47 | public void recycle() throws IOException { 48 | 49 | } 50 | 51 | @Override 52 | public void reset() { 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/ReferenceCounted.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | /** 4 | * Created by tracywwp on 2017/1/11 0011. 5 | * 一个引用计数的对象,需要显式释放。 6 | */ 7 | public interface ReferenceCounted { 8 | 9 | /** 10 | * 返回此对象的引用计数 11 | * 这意味着该对象已被释放。 12 | * @return 返回 13 | */ 14 | int refCnt(); 15 | 16 | /** 17 | * 增加参考计数 +1 18 | * @return 返回 19 | */ 20 | ReferenceCounted retain(); 21 | 22 | /** 23 | * 通过指定增加引用计数 24 | * @param increment 参数 25 | * @return 返回 26 | */ 27 | ReferenceCounted retain(int increment); 28 | 29 | /** 30 | * 为调试目的记录当前对象的访问位置. 31 | * 如果这个对象是确定被泄露,信息记录该操作将提供给您通过 32 | * @return 返回信息 33 | */ 34 | ReferenceCounted touch(); 35 | 36 | /** 37 | * 记录该对象的当前访问的位置,用于调试目的额外的任意信息。 38 | * @param hint 参数 39 | * @return 返回 40 | */ 41 | ReferenceCounted touch(Object hint); 42 | 43 | /** 44 | *减少引用计数的{ 1 } 代码和回收这个对象如果引用计数达到{ 0 } 45 | *@return 返回 46 | * 47 | */ 48 | boolean release(); 49 | 50 | /** 51 | * 减少指定数的引用计数 52 | * @param decrement 参数信息 53 | * @return 返回 54 | */ 55 | boolean release(int decrement); 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/IllegalReferenceCountException.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | /** 4 | * Created by tracywwp on 2017/1/11 0011. 5 | * An {link IllegalStateException} which is raised when a user attempts to access a {link ReferenceCounted} whose 6 | * reference count has been decreased to 0 (and consequently freed). 7 | */ 8 | public class IllegalReferenceCountException extends IllegalStateException { 9 | 10 | private static final long serialVersionUID = -2507492394288153468L; 11 | 12 | public IllegalReferenceCountException() { } 13 | 14 | public IllegalReferenceCountException(int refCnt) { 15 | this("refCnt: " + refCnt); 16 | } 17 | 18 | public IllegalReferenceCountException(int refCnt, int increment) { 19 | this("refCnt: " + refCnt + ", " + (increment > 0? "increment: " + increment : "decrement: " + -increment)); 20 | } 21 | 22 | public IllegalReferenceCountException(String message) { 23 | super(message); 24 | } 25 | 26 | public IllegalReferenceCountException(String message, Throwable cause) { 27 | super(message, cause); 28 | } 29 | 30 | public IllegalReferenceCountException(Throwable cause) { 31 | super(cause); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/strategy/impl/DirectMemCacheStategyImpl.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.strategy.impl; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import io.mycat.bigmem.strategy.CacheStrategyInf; 7 | 8 | /** 9 | * 使用内存进行缓存的策略 10 | * 源文件名:DirectMemCacheStategyImpl.java 11 | * 文件版本:1.0.0 12 | * 创建作者:liujun 13 | * 创建日期:2016年12月20日 14 | * 修改作者:liujun 15 | * 修改日期:2016年12月20日 16 | * 文件描述:TODO 17 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 18 | */ 19 | public class DirectMemCacheStategyImpl implements CacheStrategyInf { 20 | 21 | /** 22 | * 进行缓存key与对应的内存的块的信息 23 | * cahceMap 24 | */ 25 | private Map cahceMap = new ConcurrentHashMap<>(); 26 | 27 | @Override 28 | public T getBufferData(Map p) { 29 | 30 | // 1,根据key从缓存中提取内存数据 31 | 32 | // 2,检查当前是否缓存是否在有效期内 33 | 34 | // 3,在有效期内,将结果返回 35 | 36 | return null; 37 | } 38 | 39 | @Override 40 | public boolean writeBufferdata(Map p) { 41 | 42 | // 1,获得数据信息 43 | // 2,计算填充数据的大小 44 | // 3,申请缓存的数据空间 45 | // 4,将数据装入缓存 46 | // 5,将缓存的数据放入map中 47 | // 6,返回结果 48 | return false; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/DirectArena.java: -------------------------------------------------------------------------------- 1 | 2 | package io.mycat.bigmem.buffer; 3 | 4 | import java.nio.ByteBuffer; 5 | 6 | import sun.nio.ch.DirectBuffer; 7 | 8 | /** 9 | * 10 | *or zhangwy 2017年1月2日 下午6:08:54 11 | **/ 12 | public class DirectArena extends Arena{ 13 | 14 | /** 15 | * @param pageSize 16 | * @param chunkSize 17 | * @param maxOrder 18 | */ 19 | DirectArena(int pageSize, int chunkSize, int maxOrder) { 20 | super(pageSize, chunkSize, maxOrder); 21 | } 22 | 23 | public Chunk newChunk() { 24 | Chunk chunk = new Chunk(this, ByteBuffer.allocateDirect(chunkSize), 25 | chunkSize, pageSize, maxOrder); 26 | return chunk; 27 | } 28 | public BaseByteBuffer newBuffer(int capacity) { 29 | return DirectByteBuffer.newInstance(capacity); 30 | } 31 | 32 | public void freeChunk(Chunk chunk) { 33 | //todo:待实现 34 | // chunk.getMemory().cleaner().clean(); 35 | chunk.getMemory().clear(); 36 | } 37 | 38 | 39 | /*创建一个不缓存的chunk 40 | * @see io.mycat.bigmem.buffer.Arena#newUnpoolChunk(int) 41 | */ 42 | @Override 43 | public Chunk newUnpoolChunk(int capacity) { 44 | Chunk chunk = new Chunk(this, ByteBuffer.allocateDirect(capacity), capacity); 45 | return chunk; 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/allot/TestMycatBufferAllot.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.allot; 2 | 3 | import io.mycat.bigmem.chunkpageallot.MemoryAllocatorInf; 4 | import io.mycat.bigmem.chunkpageallot.MycatMemoryAllocatorFactory; 5 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 6 | import io.mycat.bigmem.chunkpageallot.console.ChunkMemoryAllotEnum; 7 | 8 | /** 9 | * 测试内存的优先分配操作 10 | * or liujun 11 | * 2016年12月30日 12 | * @version 0.0.1 13 | */ 14 | public class TestMycatBufferAllot { 15 | 16 | public static void main(String[] args) { 17 | MemoryAllocatorInf memoryAllot = MycatMemoryAllocatorFactory.createMemoryAlloctor(); 18 | 19 | // 优先使用可移动的直接内存,如果容量不够,可使用内存映射 20 | int allocFlag = ChunkMemoryAllotEnum.MEMORY_DIRECT_MOVE.getLevel() 21 | + ChunkMemoryAllotEnum.MEMORY_MAPFILE.getLevel(); 22 | 23 | MycatBufferBase buffer = memoryAllot.allocMem(allocFlag, 1024 * 1024 * 256); 24 | 25 | System.out.println(buffer); 26 | // // 设置limit 27 | // buffer.limit(buffer.putPosition()); 28 | // // 进行内存回收 29 | // memoryAllot.recyleMem(buffer); 30 | 31 | MycatBufferBase buffer2 = memoryAllot.allocMem(allocFlag, 1024 * 1024 * 64); 32 | 33 | System.out.println(buffer2); 34 | 35 | System.out.println("进行内存的分配"); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/IBufferPageFactory.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import java.io.IOException; 4 | import java.util.Set; 5 | 6 | /** 7 | * Buffer Page Factory 接口 8 | * 9 | * or zagnix 10 | * 2016-12-27 22:59 11 | */ 12 | public interface IBufferPageFactory { 13 | 14 | /** 15 | * 根据index得到一页 16 | * 17 | * @param index 参数 18 | * @return 参数 19 | * @throws IOException 参数 20 | */ 21 | public MyCatBufferPage acquirePage(long index) throws IOException; 22 | 23 | /** 24 | * 回收Page 25 | * 26 | * @param index 参数 27 | */ 28 | public void releasePage(long index); 29 | 30 | /** 31 | * 删除一页 32 | * @param index 参数 33 | * @throws IOException 参数 34 | */ 35 | public void deletePage(long index) throws IOException; 36 | 37 | 38 | /** 39 | * 刷磁盘 40 | */ 41 | public void flush(); 42 | 43 | /** 44 | * 删除所有页 45 | * @throws IOException 参数 46 | */ 47 | public void deleteAllPages() throws IOException; 48 | 49 | 50 | /** 51 | * 得到所有的页 52 | * @return 参数 53 | */ 54 | public Set getExistingPageIndexSet(); 55 | 56 | 57 | /** 58 | * 从cache中移除所有的页 59 | * @throws IOException 参数 60 | */ 61 | public void releaseCachedPages() throws IOException; 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/buffer/MycatSwapBufer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.buffer; 2 | 3 | import java.io.IOException; 4 | 5 | import io.mycat.bigmem.buffer.CatCallbackInf; 6 | 7 | /** 8 | * 允许交换到磁盘的buffer 9 | * 10 | * 内存可以被管理器移动,可以被交换到磁盘里 11 | * 12 | * swapIn()与swapOut(CallBack)类似beginOp与commitOp操作, 13 | * 但多了内存加载与钝化的逻辑,客户端如果不想阻塞, 14 | * 则可以显示的调用swapIn(Callback notify); 15 | * 当服务端完成后,回调客户端,客户端后面可以发起正常操作 16 | * 17 | * 18 | * 源文件名:MycatSwapBufer.java 19 | * 文件版本:1.0.0 20 | * 创建作者:Think 21 | * 创建日期:2016年12月21日 22 | * 修改作者:Think 23 | * 修改日期:2016年12月21日 24 | * 文件描述:TODO 25 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 26 | */ 27 | public interface MycatSwapBufer { 28 | 29 | /** 30 | * 与beginOp操作类似,将前内存数据交换到磁盘上,标识开始 31 | * @throws IOException 异常 32 | */ 33 | public void swapln() throws IOException; 34 | 35 | /** 36 | * 与commitOp操作类似,当前交换到磁盘完成,标识结束 37 | */ 38 | public void swapOut(); 39 | 40 | /** 41 | * 进行操作标识,完成调用回调通知函数 42 | * @param notify 参数 43 | * @throws IOException 异常 44 | */ 45 | public void swapIn(CatCallbackInf notify) throws IOException; 46 | 47 | /** 48 | * 与commitOp操作类型,标识结束,完成调用回调通知函数 49 | * 方法描述 50 | * @param notify 通知 51 | * 2016年12月22日 52 | */ 53 | public void swapOut(CatCallbackInf notify); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/allot/TestMycatBufferMemoryDirectAllot.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.allot; 2 | 3 | import io.mycat.bigmem.chunkpageallot.MemoryAllocatorInf; 4 | import io.mycat.bigmem.chunkpageallot.MycatMemoryAllocatorFactory; 5 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 6 | import io.mycat.bigmem.chunkpageallot.console.ChunkMemoryAllotEnum; 7 | 8 | /** 9 | * 测试内存的可移动的分配操作 10 | * or liujun 11 | * 2016年12月30日 12 | * @version 0.0.1 13 | */ 14 | public class TestMycatBufferMemoryDirectAllot { 15 | 16 | public static void main(String[] args) throws InterruptedException { 17 | MemoryAllocatorInf memoryAllot = MycatMemoryAllocatorFactory.createMemoryAlloctor(); 18 | 19 | // 优先使用可移动的直接内存,如果容量不够,可使用内存映射 20 | int allocFlag = ChunkMemoryAllotEnum.MEMORY_DIRECT.getLevel(); 21 | 22 | // 先申请一个1k 23 | MycatBufferBase buffer = memoryAllot.allocMem(allocFlag, 4096 * 2); 24 | 25 | // 先申请一个2k 26 | MycatBufferBase buffer2 = memoryAllot.allocMem(allocFlag, 4096 * 2); 27 | 28 | buffer.beginOp(); 29 | 30 | buffer.putByte((byte) 11); 31 | buffer.putByte((byte) 22); 32 | buffer.putByte((byte) 33); 33 | 34 | buffer.limit(buffer.putPosition()); 35 | buffer.commitOp(); 36 | // 内存归还操作 37 | memoryAllot.recyleMem(buffer); 38 | 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/buffer/MycatMovableBufer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.buffer; 2 | 3 | /** 4 | * 可以被移动的buffer操作,即允许进行内存的整理 5 | * 6 | * 实现参考:服务端收到beginOp的时候, 7 | * 需要标记此Buffer不可被碎片整理线程搬动。。完成commitOp()以后, 8 | * 则可以被搬动,如果正在搬动中, 9 | * 下次客户端调用beginOp会阻塞一段时间, 10 | * 等待搬动结束才操作 11 | 12 | * 13 | * 14 | * 源文件名:MycatMovableBufer.java 15 | * 文件版本:1.0.0 16 | * 创建作者:Think 17 | * 创建日期:2016年12月21日 18 | * 修改作者:Think 19 | * 修改日期:2016年12月21日 20 | * 文件描述:TODO 21 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 22 | */ 23 | public interface MycatMovableBufer { 24 | 25 | /** 26 | * 内存可以被管理器移动,首次访问(一个begin 并且 commit操作之后)之前, 27 | * 用户需要先要调用beginOp(),即完整用法如下 28 | * Buf.beginOp(); 29 | * Read or write 30 | * Buf.commitOp(); 31 | * @throws InterruptedException 异常 32 | */ 33 | public void beginOp() throws InterruptedException; 34 | 35 | /** 36 | * 当前操作完成,事要进行内存整理 37 | */ 38 | public void commitOp(); 39 | 40 | /** 41 | * 获取当前内存是否可以进行内存整理 42 | * @return 标识 43 | */ 44 | public boolean getClearFlag(); 45 | 46 | /** 47 | * 进行内存的拷贝操作 48 | * @param srcAddress 源内存地址操作 49 | * @param targerAddress 目标地址操作 50 | * @param length 拷贝的数据长度 51 | */ 52 | public void memoryCopy(long srcAddress, long targerAddress, int length); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/allot/recycle/MoveBufferRecycle.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.allot.recycle; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | import io.mycat.bigmem.chunkpageallot.buffer.impl.DirectMycatBufferMoveImpl; 5 | import io.mycat.bigmem.chunkpageallot.bufferpage.impl.DirectMoveBufferPage; 6 | 7 | public class MoveBufferRecycle { 8 | 9 | public static void main(String[] args) throws InterruptedException { 10 | 11 | DirectMoveBufferPage movePage = new DirectMoveBufferPage(new DirectMycatBufferMoveImpl(64), 2); 12 | 13 | MycatBufferBase buffer1 = movePage.alloactionMemory(2); 14 | 15 | MycatBufferBase buffer2 = movePage.alloactionMemory(4); 16 | 17 | MycatBufferBase buffer3 = movePage.alloactionMemory(4); 18 | 19 | buffer1.beginOp(); 20 | buffer1.putByte((byte) 1); 21 | buffer1.putByte((byte) 1); 22 | buffer1.putByte((byte) 1); 23 | buffer1.putByte((byte) 1); 24 | buffer1.putByte((byte) 1); 25 | buffer1.commitOp(); 26 | 27 | // 进行buffer1的内存归还操作 28 | movePage.recycleBuffer(buffer1,0,1); 29 | 30 | buffer2.beginOp(); 31 | buffer2.putByte((byte) 2); 32 | buffer2.putByte((byte) 2); 33 | buffer2.commitOp(); 34 | 35 | movePage.recycleBuffer(buffer1,0,0); 36 | 37 | } 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/mempool/MyCatByteBuf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.mempool; 2 | 3 | import io.mycat.bigmem.chunkpageallot.MemoryAllocatorInf; 4 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBuffer; 5 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 6 | 7 | import java.nio.ByteBuffer; 8 | 9 | /** 10 | * Created by znix on 2016/12/31. 11 | */ 12 | public class MyCatByteBuf extends MycatBufferBase { 13 | private MemoryAllocatorInf alloctorInf; 14 | private long capacity; 15 | private long maxCapacity; 16 | private long writerIndex; 17 | private long readerIndex; 18 | 19 | 20 | @Override 21 | public void setByte(int offset, byte value) { 22 | 23 | } 24 | 25 | @Override 26 | public MycatBuffer putByte(byte b) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public byte getByte(int offset) { 32 | return 0; 33 | } 34 | 35 | @Override 36 | public byte get() { 37 | return 0; 38 | } 39 | 40 | @Override 41 | public void copyTo(ByteBuffer buffer) { 42 | 43 | } 44 | 45 | @Override 46 | public void recycleUnuse() { 47 | 48 | } 49 | 50 | @Override 51 | public MycatBufferBase slice() { 52 | return null; 53 | } 54 | 55 | @Override 56 | public void beginOp() { 57 | 58 | } 59 | 60 | @Override 61 | public void commitOp() { 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/allot/TestMycatBufferMemoryMoveAllot.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.allot; 2 | 3 | import io.mycat.bigmem.chunkpageallot.MemoryAllocatorInf; 4 | import io.mycat.bigmem.chunkpageallot.MycatMemoryAllocatorFactory; 5 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 6 | import io.mycat.bigmem.chunkpageallot.buffer.impl.DirectMycatBufferMoveImpl; 7 | import io.mycat.bigmem.chunkpageallot.console.ChunkMemoryAllotEnum; 8 | 9 | /** 10 | * 测试内存的可移动的分配操作 11 | * or liujun 12 | * 2016年12月30日 13 | * @version 0.0.1 14 | */ 15 | public class TestMycatBufferMemoryMoveAllot { 16 | 17 | public static void main(String[] args) throws InterruptedException { 18 | MemoryAllocatorInf memoryAllot = MycatMemoryAllocatorFactory.createMemoryAlloctor(); 19 | 20 | // 优先使用可移动的直接内存,如果容量不够,可使用内存映射 21 | int allocFlag = ChunkMemoryAllotEnum.MEMORY_DIRECT_MOVE.getLevel(); 22 | 23 | MycatBufferBase buffer = memoryAllot.allocMem(allocFlag, 1024 * 1024 * 1); 24 | 25 | System.out.println(buffer); 26 | 27 | MycatBufferBase buffer2 = memoryAllot.allocMem(allocFlag, 1024 * 1024 * 1); 28 | 29 | // 开始操作内存 30 | buffer2.beginOp(); 31 | 32 | // 填充数据 33 | buffer2.putByte((byte) 1); 34 | 35 | buffer2.limit(buffer2.putPosition()); 36 | // 内存操作完毕 37 | buffer2.commitOp(); 38 | 39 | // 进行内存的归还操作 40 | memoryAllot.recyleMem(buffer2); 41 | 42 | System.out.println(buffer2); 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/UnsafeMemory.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import sun.misc.Unsafe; 6 | 7 | import java.lang.reflect.Field; 8 | 9 | 10 | /** 11 | * Unsafe 工具类 12 | * 13 | * or zagnix 14 | * 2016-11-18 14:17 15 | */ 16 | public final class UnsafeMemory { 17 | private final static Logger logger = LoggerFactory.getLogger(UnsafeMemory.class); 18 | private static final Unsafe _UNSAFE; 19 | public static final int BYTE_ARRAY_OFFSET; 20 | static { 21 | Unsafe unsafe; 22 | try { 23 | Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 24 | theUnsafeField.setAccessible(true); 25 | unsafe = (Unsafe) theUnsafeField.get(null); 26 | } catch (Exception e) { 27 | logger.error(e.getMessage()); 28 | unsafe = null; 29 | } 30 | _UNSAFE = unsafe; 31 | if (_UNSAFE != null) { 32 | BYTE_ARRAY_OFFSET = _UNSAFE.arrayBaseOffset(byte[].class); 33 | } else { 34 | BYTE_ARRAY_OFFSET = 0; 35 | } 36 | } 37 | public static Unsafe getUnsafe() { 38 | return _UNSAFE; 39 | } 40 | 41 | /** 42 | * 将size规整化为pagesize的倍数 43 | * @param size 参数 44 | * @return 参数 45 | */ 46 | public static long roundToOsPageSzie(long size) { 47 | long pagesize = _UNSAFE.pageSize(); 48 | return (size + (pagesize-1)) & ~(pagesize-1); 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/strategy/CacheStrategy.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.strategy; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import io.mycat.bigmem.console.LocatePolicy; 7 | import io.mycat.bigmem.strategy.impl.DirectMemCacheStategyImpl; 8 | import io.mycat.bigmem.strategy.impl.FileMapCacheStategyImpl; 9 | 10 | /** 11 | * 缓存的策略信息 12 | * 源文件名:CacheStrategy.java 13 | * 文件版本:1.0.0 14 | * 创建作者:liujun 15 | * 创建日期:2016年12月20日 16 | * 修改作者:liujun 17 | * 修改日期:2016年12月20日 18 | * 文件描述:TODO 19 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 20 | */ 21 | public class CacheStrategy { 22 | 23 | /** 24 | * 缓存策略的信息存储的Map 25 | * strategyMap 26 | */ 27 | private static final Map strategyMap = new HashMap<>(); 28 | 29 | static { 30 | // 使用直接内存进行缓存的策略 31 | strategyMap.put(LocatePolicy.Core, new DirectMemCacheStategyImpl()); 32 | // 使用文件映射的方式进行缓存的策略 33 | strategyMap.put(LocatePolicy.Normal, new FileMapCacheStategyImpl()); 34 | } 35 | 36 | private static final CacheStrategy INSTANCE = new CacheStrategy(); 37 | 38 | private CacheStrategy() { 39 | 40 | } 41 | 42 | public static CacheStrategy getInstance() { 43 | return INSTANCE; 44 | } 45 | 46 | /** 47 | * 获得策略信息 48 | * 方法描述 49 | * @param policy 参数 50 | * @return 参数 51 | * 2016年12月20日 52 | */ 53 | public CacheStrategyInf getStrategy(LocatePolicy policy) { 54 | return strategyMap.get(policy); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/IBufferPage.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | 6 | /** 7 | * Cache Page接口 8 | * 9 | * or zagnix 10 | * @version 1.0 11 | * 2016-12-27 18:49 12 | */ 13 | 14 | public interface IBufferPage { 15 | 16 | /** 17 | * get bytes from Thread Local 18 | * 19 | * @param position 参数 20 | * @param length 参数 21 | * @return 参数 22 | */ 23 | public byte[] getBytes(int position, int length); 24 | 25 | /** 26 | * ByteBuffer slice from Thread Local 27 | * 28 | * @param position 参数 29 | * @param limit 参数 30 | * @return 参数 31 | */ 32 | public ByteBuffer slice(int position, int limit); 33 | 34 | /** 35 | * get ByteBuffer from Thread Local 36 | * 37 | * @param position 参数 38 | * @return 参数 39 | */ 40 | public ByteBuffer getLocalByteBuffer(int position); 41 | 42 | 43 | /** 44 | * 将数据刷到磁盘 45 | */ 46 | public void flush(); 47 | 48 | 49 | /** 50 | * 页号 51 | * 52 | * @return 返回 53 | */ 54 | long getPageIndex(); 55 | 56 | 57 | /** 58 | * 设置页有数据被写入了,属于’脏页‘ 59 | * 60 | * @param dirty 参数 61 | */ 62 | void setDirty(boolean dirty); 63 | 64 | /** 65 | * 页回收 66 | * @throws IOException 异常 67 | */ 68 | public void recycle() throws IOException; 69 | 70 | /** 71 | * 页是否被回收了 72 | * 73 | * @return 返回 74 | */ 75 | boolean isRecycled(); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/CacheThreadLocal.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | import io.mycat.bigmem.util.MpsQueue; 4 | 5 | public class CacheThreadLocal { 6 | 7 | protected Arena arena; 8 | protected final int tinySize ; /*tiny 类型缓存多少个*/ 9 | protected final int smallSize ; /*small 类型缓存多少个*/ 10 | protected final int normalSize ; /*normal 类型缓存多少个*/ 11 | protected final boolean cached; /*是否进行缓存*/ 12 | protected int pageSize; 13 | protected int maxOrder; 14 | private MpsQueue[] tinyCache =null; 15 | private MpsQueue[] smallCache = null; 16 | private MpsQueue[] normalCache = null; 17 | 18 | public CacheThreadLocal(Arena arena, int pageSize,int maxOrder, int tinySize, int smallSize,int normalSize) { 19 | this.arena = arena; 20 | this.pageSize = pageSize; 21 | this.tinySize = tinySize; 22 | this.smallSize = smallSize; 23 | cached = true; 24 | 25 | this.normalSize = normalSize; 26 | if(this.tinySize > 0) { 27 | initCache(tinyCache, arena.getTinySubpagePoolSize(), tinySize); 28 | } 29 | 30 | if(this.smallSize > 0) { 31 | initCache(smallCache, arena.getSmallSubpagePoolSize(), smallSize); 32 | } 33 | 34 | if(this.normalSize > 0) { 35 | 36 | } 37 | } 38 | @SuppressWarnings("unchecked") 39 | private void initCache(MpsQueue[] cache,int size, int cacheSize) { 40 | cache = new MpsQueue[size]; 41 | for(int i = 0 ; i < size; i++) { 42 | cache[i] = new MpsQueue<>(cacheSize); 43 | } 44 | 45 | } 46 | // public CacheThreadLocal() { 47 | // cached = false; 48 | // } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/buffer/MycatBuffer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.buffer; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | /** 6 | * buffer接口,类似byteBuffer接口, 7 | * 源文件名:MycatBufer.java 8 | * 文件版本:1.0.0 9 | * 创建作者:Think 10 | * 创建日期:2016年12月21日 11 | * 修改作者:Think 12 | * 修改日期:2016年12月21日 13 | * 文件描述:TODO 14 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 15 | */ 16 | public interface MycatBuffer { 17 | 18 | /** 19 | * 按偏移量设置buffer的值,进行绝对定位数据进行写入,不改变position的值 20 | * 方法描述 21 | * @param offset 参数 22 | * @param value 参数 23 | * 2016年12月21日 24 | */ 25 | public void setByte(int offset, byte value); 26 | 27 | /** 28 | * 放入byte信息 29 | * 方法描述 30 | * @param b 参数 31 | * @return 32 | * 2016年12月23日 33 | */ 34 | public MycatBuffer putByte(byte b); 35 | 36 | /** 37 | * 获取指定位置的byte值 38 | * 方法描述 39 | * @param offset 参数 40 | * @return 41 | * 2016年12月23日 42 | */ 43 | public byte getByte(int offset); 44 | 45 | /** 46 | * 按位获取数据 47 | * 方法描述 48 | * @return 49 | * 2016年12月23日 50 | */ 51 | public byte get(); 52 | 53 | /** 54 | * 向目标的buffer拷贝数据 55 | * 方法描述 56 | * @param buffer 参数 57 | * 2016年12月21日 58 | */ 59 | public void copyTo(ByteBuffer buffer); 60 | 61 | /** 62 | * 释放未使用的空间 63 | * 方法描述 64 | * 2016年12月21日 65 | */ 66 | public void recycleUnuse(); 67 | 68 | /** 69 | * 以当前的内存生成新的引用对象,使用读取指针定位 70 | * @return 返回 71 | */ 72 | public MycatBufferBase slice(); 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/ISQLResult.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * SQLResult 存放 实现接口 7 | * or zagnix 8 | * 2016-11-18 16:46 9 | */ 10 | public interface ISQLResult { 11 | 12 | /** 13 | * 该将sql row的二进制数据,存放到Cache中 14 | * @param data 参数 15 | * @return 返回 16 | * @throws IOException 异常 17 | */ 18 | public long put(byte[] data) throws IOException; 19 | 20 | /** 21 | * 获取一条sql row的二进制数据 22 | * @return 参数 23 | * @throws IOException 参数 24 | */ 25 | public byte[] next() throws IOException; 26 | 27 | /** 28 | * 根据index得到一条SQL row的二进制数据 29 | * @param index 参数 30 | * @return 参数 31 | * @throws IOException 参数 32 | */ 33 | public byte[] get(long index) throws IOException; 34 | 35 | 36 | /** 37 | * SQL结果集条数 38 | * @return 参数 39 | */ 40 | public long size(); 41 | 42 | /** 43 | * 是否没有缓存SQL结果集 44 | * @return 参数 45 | */ 46 | public boolean isEmpty() ; 47 | 48 | /** 49 | * Cache是否已经满了 50 | * @return 参数 51 | */ 52 | public boolean isFull(); 53 | 54 | /** 55 | * 将SQL结果集刷入磁盘 56 | */ 57 | public void flush(); 58 | 59 | /** 60 | * 删除数据页和索引页文件 61 | * @throws IOException 参数 62 | */ 63 | public void removeAll() throws IOException; 64 | 65 | /** 66 | * 将所有内存映射文件unmap 67 | * @throws IOException 参数 68 | */ 69 | public void recycle() throws IOException; 70 | 71 | 72 | /** 73 | * 复位读的位置0,即从头开始读取SQL结果集 74 | */ 75 | public void reset(); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/MycatMemoryAllocatorFactory.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot; 2 | 3 | import io.mycat.bigmem.buffer.MemoryAllocator; 4 | import io.mycat.bigmem.console.PropertiesKeyEnum; 5 | import io.mycat.bigmem.util.PropertiesUtils; 6 | 7 | /** 8 | * 内存分配器工厂接口 9 | * 源文件名:MycatMemoryAlloctorFactory.java 10 | * 文件版本:1.0.0 11 | * 创建作者:liujun 12 | * 创建日期:2016年12月28日 13 | * 修改作者:liujun 14 | * 修改日期:2016年12月28日 15 | * 文件描述:TODO 16 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 17 | */ 18 | public class MycatMemoryAllocatorFactory { 19 | 20 | /** 21 | * 创建内存分配器对象 22 | * 方法描述 23 | * @return 返回 24 | * 2016年12月28日 25 | */ 26 | public static MemoryAllocatorInf createMemoryAlloctor() { 27 | 28 | try { 29 | // 获得内存分配的配制信息 30 | String allotClass = PropertiesUtils.getInstance() 31 | .getValue(PropertiesKeyEnum.MYCAT_MEMORY_ALLOT_CLASS.getKey()); 32 | // 加载文件信息 33 | Class alloctorClass = Class.forName(allotClass); 34 | 35 | // 生成对象 36 | MemoryAllocatorInf alloctObject = (MemoryAllocatorInf) alloctorClass.newInstance(); 37 | 38 | return alloctObject; 39 | 40 | } catch (ClassNotFoundException e) { 41 | e.printStackTrace(); 42 | } catch (InstantiationException e) { 43 | e.printStackTrace(); 44 | } catch (IllegalAccessException e) { 45 | e.printStackTrace(); 46 | } 47 | 48 | return null; 49 | } 50 | 51 | /** 52 | * @seeMycat-BigMemory 53 | * @return 54 | * or shenli, zwyqz, tracywwp 55 | */ 56 | //todo:待抽取MemoryAllocator接口类 57 | public MemoryAllocator getJemalloc() 58 | { 59 | return MemoryAllocator.CURRENT; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/console/ChunkMemoryAllotEnum.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.console; 2 | 3 | import io.mycat.bigmem.chunkpageallot.alloctor.ChunkMemoryAllotInf; 4 | import io.mycat.bigmem.chunkpageallot.alloctor.impl.ChunkDirectMemoryImpl; 5 | import io.mycat.bigmem.chunkpageallot.alloctor.impl.ChunkDirectMoveMemoryImpl; 6 | import io.mycat.bigmem.chunkpageallot.alloctor.impl.ChunkFileMapMemoryImpl; 7 | 8 | /** 9 | * 进行大内存分配的级别对象信息 10 | * or liujun 11 | * 2016年12月29日 12 | */ 13 | public enum ChunkMemoryAllotEnum { 14 | 15 | /** 16 | * 直接内存分配操作,不可移动的内存 17 | */ 18 | MEMORY_DIRECT(1 << 2, 2, new ChunkDirectMemoryImpl()), 19 | 20 | /** 21 | * 可移动的内存操作 22 | */ 23 | MEMORY_DIRECT_MOVE(1 << 1, 1, new ChunkDirectMoveMemoryImpl()), 24 | 25 | /** 26 | * 内存映射文件操作 27 | */ 28 | MEMORY_MAPFILE(1, 0, new ChunkFileMapMemoryImpl()); 29 | 30 | /** 31 | * 当前的级别信息 32 | */ 33 | private int level; 34 | 35 | /** 36 | * 移动的位数 37 | */ 38 | private int moveBit; 39 | 40 | private ChunkMemoryAllotInf chunkAllot; 41 | 42 | private ChunkMemoryAllotEnum(int level, int moveBit, ChunkMemoryAllotInf chunkAllot) { 43 | this.level = level; 44 | this.moveBit = moveBit; 45 | this.chunkAllot = chunkAllot; 46 | } 47 | 48 | public int getLevel() { 49 | return level; 50 | } 51 | 52 | public void setLevel(int level) { 53 | this.level = level; 54 | } 55 | 56 | public ChunkMemoryAllotInf getChunkAllot() { 57 | return chunkAllot; 58 | } 59 | 60 | public void setChunkAllot(ChunkMemoryAllotInf chunkAllot) { 61 | this.chunkAllot = chunkAllot; 62 | } 63 | 64 | public int getMoveBit() { 65 | return moveBit; 66 | } 67 | 68 | public void setMoveBit(int moveBit) { 69 | this.moveBit = moveBit; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/buffer/directmemory/TestDirectBufferPool.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer.directmemory; 2 | 3 | import java.io.IOException; 4 | 5 | import io.mycat.bigmem.chunkpageallot.alloctor.MycatMemoryAllocator; 6 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBuffer; 7 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 8 | import io.mycat.bigmem.console.LocatePolicy; 9 | 10 | public class TestDirectBufferPool { 11 | 12 | public static void main(String[] args) throws IOException { 13 | 14 | // // 构建内存池对象 15 | // MycatMemoryAlloctor poolBuffer = new 16 | // MycatMemoryAlloctor(LocatePolicy.Core, 2048, 128, (short) 1); 17 | // 18 | // // 进行内存的申请 19 | // MycatBufferBase buffer = poolBuffer.allocMem(1,1024); 20 | // 21 | // buffer.beginOp(); 22 | // 23 | // // 进行内存数据卦 24 | // fillValue(buffer); 25 | // 26 | // printValue(buffer); 27 | // 28 | // // 进行内存的回收 29 | // // 测试全部回收 30 | // // 回收内存之前,需要设置limit的大小,以确定回收的内存大小 31 | // buffer.limit(256); 32 | // poolBuffer.recyleMem(buffer); 33 | // 34 | // // 测试内存归还后,是否可继续申请 35 | // MycatBufferBase buffer2 = poolBuffer.allocMem(1,1792); 36 | // 37 | // System.out.println("内存空间大小:" + buffer2.limit()); 38 | // 39 | // buffer.commitOp(); 40 | } 41 | 42 | /** 43 | * 进行内存的填充 44 | * 方法描述 45 | * @param buffer 46 | * @throws IOException 47 | * 2016年12月23日 48 | */ 49 | public static void fillValue(MycatBufferBase buffer) throws IOException { 50 | for (int i = 0; i < buffer.capacity(); i++) { 51 | buffer.putByte((byte) i); 52 | } 53 | } 54 | 55 | public static void printValue(MycatBufferBase buffer) { 56 | for (int i = 0; i < buffer.capacity(); i++) { 57 | System.out.print("curr value:" + buffer.get() + "\t"); 58 | if (i % 4 == 0) { 59 | System.out.println(); 60 | } 61 | } 62 | 63 | System.out.println(); 64 | System.out.println(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/PropertiesUtils.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.IOException; 5 | import java.util.HashMap; 6 | import java.util.Iterator; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | import java.util.Properties; 10 | 11 | import org.apache.log4j.Logger; 12 | 13 | /** 14 | * 进行资源文件的公共查找 15 | * 16 | * or kk 17 | * 2016年12月31日 18 | */ 19 | public class PropertiesUtils { 20 | 21 | private Logger log = Logger.getLogger(PropertiesUtils.class); 22 | 23 | private static final Map PROPER_MAP = new HashMap(); 24 | 25 | private static final PropertiesUtils PROINSTANCE = new PropertiesUtils(); 26 | 27 | static { 28 | // 加载配制文件信息 29 | PROINSTANCE.loadProperties("cfg.properties"); 30 | } 31 | 32 | private PropertiesUtils() { 33 | 34 | } 35 | 36 | public static PropertiesUtils getInstance() { 37 | return PROINSTANCE; 38 | } 39 | 40 | private void loadProperties(String fileName) { 41 | // 进行加载数据 42 | Properties pro = new Properties(); 43 | 44 | try { 45 | pro.load(PropertiesUtils.class.getResourceAsStream("/" + fileName)); 46 | } catch (FileNotFoundException e) { 47 | e.printStackTrace(); 48 | log.error("PropertiesUtils load properties not exception:", e); 49 | } catch (IOException e) { 50 | e.printStackTrace(); 51 | log.error("PropertiesUtils load properties IOException:", e); 52 | } 53 | 54 | if (null != pro.entrySet()) { 55 | Iterator> entryIter = pro.entrySet().iterator(); 56 | 57 | while (entryIter.hasNext()) { 58 | Entry entry = entryIter.next(); 59 | PROPER_MAP.put(entry.getKey(), entry.getValue()); 60 | } 61 | } 62 | } 63 | 64 | public String getValue(Object key) { 65 | Object rsp = PROPER_MAP.get(key); 66 | 67 | if (null != rsp) { 68 | return String.valueOf(rsp); 69 | } 70 | 71 | return null; 72 | } 73 | 74 | public static void main(String[] args) { 75 | 76 | System.out.println(PropertiesUtils.getInstance().getValue("IBS.Schedule.is.test.flag")); 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/Utils.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Random; 6 | import java.util.regex.Pattern; 7 | 8 | public class Utils { 9 | private static final String illegalChars = "/" + '\u0000' + '\u0001' + "-" + '\u001F' + '\u007F' + "-" + '\u009F' + '\uD800' + "-" + '\uF8FF' + '\uFFF0' 10 | + "-" + '\uFFFF'; 11 | private static final Pattern p = Pattern.compile("(^\\.{1,2}$)|[" + illegalChars + "]"); 12 | 13 | public static void validateFolder(String name) { 14 | if (name == null || name.length() == 0) { 15 | throw new IllegalArgumentException("folder name is emtpy"); 16 | } 17 | if(name.length() > 255) { 18 | throw new IllegalArgumentException("folder name is too long"); 19 | } 20 | if (p.matcher(name).find()) { 21 | throw new IllegalArgumentException("folder name [" + name + "] is illegal"); 22 | } 23 | } 24 | 25 | public static boolean isFilenameValid(String file) { 26 | File f = new File(file); 27 | try { 28 | f.getCanonicalPath(); 29 | return true; 30 | } catch (IOException e) { 31 | return false; 32 | } 33 | } 34 | 35 | public static void deleteDirectory(File dir) { 36 | if (!dir.exists()) return; 37 | File[] subs = dir.listFiles(); 38 | if (subs != null) { 39 | for (File f : dir.listFiles()) { 40 | if (f.isFile()) { 41 | if(!f.delete()) { 42 | throw new IllegalStateException("delete file failed: "+f); 43 | } 44 | } else { 45 | deleteDirectory(f); 46 | } 47 | } 48 | } 49 | if(!dir.delete()) { 50 | throw new IllegalStateException("delete directory failed: "+dir); 51 | } 52 | } 53 | 54 | static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 55 | static Random rnd = new Random(); 56 | 57 | public static String randomString(int len ) 58 | { 59 | StringBuilder sb = new StringBuilder( len ); 60 | for( int i = 0; i < len; i++ ) 61 | sb.append( AB.charAt( rnd.nextInt(AB.length()) ) ); 62 | return sb.toString(); 63 | } 64 | 65 | 66 | public static void deleteFile(File file) { 67 | if (!file.exists() || !file.isFile()) { 68 | return; 69 | } 70 | if (!file.delete()) { 71 | throw new IllegalStateException("delete file failed: "+file); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/allot/recycle/mark/MarkMoveBufferRecycle2.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.allot.recycle.mark; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | import io.mycat.bigmem.chunkpageallot.buffer.impl.DirectMycatBufferMoveImpl; 5 | import io.mycat.bigmem.chunkpageallot.bufferpage.impl.DirectMoveBufferPage; 6 | import io.mycat.bigmem.chunkpageallot.recycle.impl.MarkMovePageRecycleImpl; 7 | 8 | public class MarkMoveBufferRecycle2 { 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | 12 | DirectMoveBufferPage movePage = new DirectMoveBufferPage(new DirectMycatBufferMoveImpl(64), 2); 13 | 14 | MycatBufferBase buffer1 = movePage.alloactionMemory(4); 15 | 16 | MycatBufferBase buffer2 = movePage.alloactionMemory(4); 17 | 18 | buffer1.beginOp(); 19 | buffer1.putPosition(0); 20 | // 重置limit容量信息 21 | buffer1.limit(buffer1.putPosition() ); 22 | buffer1.commitOp(); 23 | 24 | // 进行buffer1的内存归还操作 25 | movePage.recycleBuffer(buffer1,0,0); 26 | 27 | buffer2.beginOp(); 28 | buffer2.putByte((byte) 21); 29 | buffer2.putByte((byte) 22); 30 | // 重新标识归还标识 31 | buffer2.limit(buffer2.putPosition() + 2); 32 | buffer2.commitOp(); 33 | 34 | movePage.recycleBuffer(buffer2,0,0); 35 | 36 | printValue(movePage.getBuffer()); 37 | 38 | MarkMovePageRecycleImpl mark = new MarkMovePageRecycleImpl(); 39 | mark.pageClearUp(movePage); 40 | 41 | 42 | 43 | buffer2.beginOp(); 44 | buffer2.putByte((byte) 23); 45 | buffer2.putByte((byte) 24); 46 | // 重新标识归还标识 47 | buffer2.commitOp(); 48 | 49 | System.out.println("-----------------------------"); 50 | System.out.println(); 51 | System.out.println(); 52 | 53 | printValue(movePage.getBuffer()); 54 | 55 | } 56 | 57 | public static void printValue(MycatBufferBase buffer) throws InterruptedException { 58 | 59 | buffer.beginOp(); 60 | 61 | buffer.getPosition(0); 62 | for (int i = 0; i < buffer.limit(); i++) { 63 | System.out.print("value:" + buffer.get() + "\t"); 64 | if (i % 4 == 3) { 65 | System.out.println(); 66 | } 67 | } 68 | 69 | System.out.println(); 70 | System.out.println(); 71 | 72 | buffer.commitOp(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/AddressIndex.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import io.mycat.bigmem.util.UnsafeMemory; 4 | import sun.misc.Unsafe; 5 | 6 | /** 7 | * cache padding from disruptor 8 | * 9 | * or zagnix 10 | * 2016-11-18 10:17 11 | */ 12 | 13 | class LhsPadding 14 | { 15 | protected long p1, p2, p3, p4, p5, p6, p7; 16 | } 17 | 18 | class Value extends LhsPadding 19 | { 20 | protected volatile long value; 21 | } 22 | 23 | class RhsPadding extends Value 24 | { 25 | protected long p9, p10, p11, p12, p13, p14, p15; 26 | } 27 | 28 | public class AddressIndex extends RhsPadding { 29 | static final long INITIAL_VALUE = -1L; 30 | private static final Unsafe UNSAFE = UnsafeMemory.getUnsafe(); 31 | private static final long VALUE_OFFSET; 32 | 33 | public AddressIndex() { 34 | this(INITIAL_VALUE); 35 | } 36 | 37 | public AddressIndex(long initialValue) { 38 | UNSAFE.putOrderedLong(this, VALUE_OFFSET, initialValue); 39 | } 40 | 41 | public long get() { 42 | return this.value; 43 | } 44 | 45 | public void set(long value) { 46 | UNSAFE.putOrderedLong(this, VALUE_OFFSET, value); 47 | } 48 | 49 | public void setVolatile(long value) { 50 | UNSAFE.putLongVolatile(this, VALUE_OFFSET, value); 51 | } 52 | 53 | /** 54 | * 内存地址值(通旧值this所在对象加上字节偏量VALUE_OFFSET找到所在的内存段) 55 | * 期望值: expectedValue 56 | * 新值: newValue 57 | * 如果 内存地址值 == 期望值 58 | * 则将新的值写入到内存地址中。 59 | * return true 60 | * else 61 | * return false 62 | * @param expectedValue 参数 63 | * @param newValue 参数 64 | * @return 返回 65 | */ 66 | public boolean compareAndSet(long expectedValue, long newValue) { 67 | return UNSAFE.compareAndSwapLong(this, VALUE_OFFSET, expectedValue, newValue); 68 | } 69 | 70 | 71 | public long incrementAndGet() { 72 | return this.addAndGet(1L); 73 | } 74 | 75 | public long addAndGet(long increment) { 76 | long currentValue; 77 | long newValue; 78 | do { 79 | currentValue = this.get(); 80 | newValue = currentValue + increment; 81 | } while(!this.compareAndSet(currentValue,newValue)); 82 | return newValue; 83 | } 84 | public String toString() { 85 | return Long.toString(this.get()); 86 | } 87 | static { 88 | try { 89 | VALUE_OFFSET = UNSAFE.objectFieldOffset(Value.class.getDeclaredField("value")); 90 | } catch (Exception e) { 91 | throw new RuntimeException(e); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/buffer/mapfile/TestMapFileBuffer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer.mapfile; 2 | 3 | import java.io.IOException; 4 | import java.nio.ByteBuffer; 5 | 6 | import io.mycat.bigmem.chunkpageallot.alloctor.MycatMemoryAllocator; 7 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 8 | import io.mycat.bigmem.chunkpageallot.buffer.MycatSwapBufer; 9 | import io.mycat.bigmem.console.LocatePolicy; 10 | 11 | public class TestMapFileBuffer { 12 | 13 | // public static void main(String[] args) throws IOException { 14 | // 15 | // try { 16 | // // 得到一个内存映射区的内存对象 17 | // MycatMemoryAlloctor poolBuffer = new 18 | // MycatMemoryAlloctor(LocatePolicy.Normal, 1024, 128, (short) 1); 19 | // 20 | // // 进行内存的申请 21 | // MycatBufferBase mybuffer = poolBuffer.allocMem(1,1024); 22 | // 23 | // mybuffer.beginOp(); 24 | // 25 | // mybuffer.putByte((byte) 10); 26 | // mybuffer.putByte((byte) 12); 27 | // mybuffer.putByte((byte) 120); 28 | // mybuffer.putByte((byte) 100); 29 | // mybuffer.putByte((byte) 90); 30 | // 31 | // for (int i = 0; i < mybuffer.limit(); i++) { 32 | // System.out.println(mybuffer.get()); 33 | // } 34 | // 35 | // System.out.println("当前写入的游标:" + mybuffer.putPosition()); 36 | // System.out.println("当前读取的游标:" + mybuffer.getPosition()); 37 | // 38 | // ByteBuffer bufferValue = ByteBuffer.allocateDirect(1024); 39 | // 40 | // mybuffer.copyTo(bufferValue); 41 | // 42 | // System.out.println(bufferValue); 43 | // 44 | // for (int i = 0; i < bufferValue.position(); i++) { 45 | // System.out.println(bufferValue.get(i)); 46 | // } 47 | // // 48 | // // mybuffer.recycleUnuse(); 49 | // 50 | // MycatSwapBufer mybufferSwap = (MycatSwapBufer) mybuffer; 51 | // 52 | // // 测试swapin以及swapOut 53 | // // 数据写入交换到磁盘 54 | // mybufferSwap.swapOut(); 55 | // 56 | // // 加载到内存 57 | // mybufferSwap.swapln(); 58 | // 59 | // System.out.println("交换后的结果:加载"); 60 | // 61 | // for (int i = 0; i < mybuffer.limit(); i++) { 62 | // System.out.println(mybuffer.get()); 63 | // } 64 | // 65 | // // 进行异步的通知 66 | // mybufferSwap.swapOut(() -> { 67 | // System.out.println("当前异步交换到磁盘"); 68 | // }); 69 | // 70 | // // 使用jdk8的特性 71 | // mybufferSwap.swapIn(() -> { 72 | // System.out.println("异步交换到内存中"); 73 | // }); 74 | // 75 | // System.out.println("交换后的结果:加载"); 76 | // 77 | // for (int i = 0; i < mybuffer.limit(); i++) { 78 | // System.out.println(mybuffer.get()); 79 | // } 80 | // 81 | // mybuffer.commitOp(); 82 | // } catch (Exception e) { 83 | // e.printStackTrace(); 84 | // } 85 | // 86 | // } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/MpsQueue.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | import java.util.concurrent.atomic.AtomicReferenceArray; 5 | 6 | /*cas的缓存循环数组, 7 | * 存数据:采用先占用位置,然后在放数据的原则. 8 | * 取数据:采用先取数据,置为cas置为空,然后在将读指针加一的原则, 9 | * 需要注意的时候,由于是循环数组,取出来数据不为空,有可能已经是又被放进去的数据了.要保证当前reader指针没被改变的情况下才可以去cas改变置为空. 10 | * zhangwy 11 | * */ 12 | public class MpsQueue { 13 | protected AtomicLong readerIndex; 14 | protected AtomicLong writerIndex; 15 | protected final int size ; 16 | protected final int mask ; 17 | AtomicReferenceArray buffer = null; 18 | public MpsQueue(int length) { 19 | size = MathUtil.roundToPowerOfTwo(length) ; 20 | mask = size - 1; 21 | buffer = new AtomicReferenceArray(size); 22 | readerIndex = new AtomicLong(0); 23 | writerIndex = new AtomicLong(0); 24 | } 25 | //idx % size 26 | public int idx(long index) { 27 | return (int) (index & mask); 28 | } 29 | //读指针获取 30 | public long getReaderIndex() { 31 | return readerIndex.get(); 32 | } 33 | //写指针获取 34 | public long getWriterIndex() { 35 | return writerIndex.get(); 36 | } 37 | /*放置元素*/ 38 | public boolean put(T element) { 39 | long reader ,writer ; 40 | long wrapSize ; 41 | if(element == null) { 42 | throw new IllegalArgumentException("element can't not be null"); 43 | } 44 | do { 45 | reader = getReaderIndex(); 46 | writer = getWriterIndex(); 47 | wrapSize = writer - reader ; 48 | //仍有空间放置 49 | if(wrapSize < size) { 50 | } else { 51 | return false; 52 | } 53 | } while(!writerIndex.compareAndSet(writer, writer + 1)); 54 | int offset = idx(writer); 55 | if(buffer.get(offset) != null) { 56 | throw new RuntimeException("buffer @" + writer + " must be null,but now is not null"); 57 | } 58 | buffer.set(offset, element); 59 | return true; 60 | } 61 | /** 62 | * get a element from the queue 63 | * @return 返回 64 | */ 65 | public T get() { 66 | T element = null; 67 | long reader ,writer ; 68 | int offset; 69 | do { 70 | reader = getReaderIndex() ; 71 | writer = getWriterIndex(); 72 | /*queue不为空*/ 73 | if(writer == reader) { 74 | return null; 75 | } 76 | offset = idx(reader); 77 | element = buffer.get(offset); 78 | /*元素已经被取走了*/ 79 | if(element == null ) continue; 80 | /*reader已经是最新*/ 81 | if(reader == getReaderIndex() && buffer.compareAndSet(offset, element, null)) { 82 | //System.out.println("pop :" +reader +":"+ offset + ":" + element); 83 | break; 84 | } 85 | }while(true); 86 | if(element != null) { 87 | while(!readerIndex.compareAndSet(reader, reader + 1)){ 88 | throw new RuntimeException(String.format("readerIndex is %d has been changed,is error", readerIndex)); 89 | } 90 | return element; 91 | } 92 | return null; 93 | } 94 | /** 95 | * 96 | */ 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/Keyer.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | /** 6 | * key cache生效规则 7 | * 8 | * or zagnix 9 | * @version 1.0 10 | * 2016-12-30 16:48 11 | */ 12 | 13 | public class Keyer { 14 | private long cacheTTL=0; 15 | private long lastAccessTime=0; 16 | 17 | /** 18 | * TTL 时间内访问次数 19 | */ 20 | private long accessCount=0; 21 | private AtomicLong refCount = new AtomicLong(0); 22 | 23 | private boolean autoRefresh = false; 24 | private String sql; 25 | private K key; 26 | private V value; 27 | 28 | private IDataLoader iDataLoader = null; 29 | private IRemoveKeyListener removeKeyListener = null; 30 | 31 | public long getCacheTTL() { 32 | return cacheTTL; 33 | } 34 | 35 | public void setCacheTTL(long cacheTTL) { 36 | this.cacheTTL = cacheTTL; 37 | } 38 | 39 | public long getLastAccessTime() { 40 | return lastAccessTime; 41 | } 42 | 43 | public void setLastAccessTime(long lastAccessTime) { 44 | this.lastAccessTime = lastAccessTime; 45 | } 46 | 47 | public AtomicLong getRefCount() { 48 | return refCount; 49 | } 50 | 51 | public void setRefCount(AtomicLong refCount) { 52 | this.refCount = refCount; 53 | } 54 | 55 | public K getKey() { 56 | return key; 57 | } 58 | 59 | public void setKey(K key) { 60 | this.key = key; 61 | } 62 | 63 | public V getValue() { 64 | return value; 65 | } 66 | 67 | public void setValue(V value) { 68 | this.value = value; 69 | } 70 | 71 | public IDataLoader getiDataLoader() { 72 | return iDataLoader; 73 | } 74 | 75 | public void setiDataLoader(IDataLoader iDataLoader) { 76 | this.iDataLoader = iDataLoader; 77 | } 78 | 79 | public IRemoveKeyListener getRemoveKeyListener() { 80 | return removeKeyListener; 81 | } 82 | 83 | public void setRemoveKeyListener(IRemoveKeyListener removeKeyListener) { 84 | this.removeKeyListener = removeKeyListener; 85 | } 86 | 87 | public long getAccessCount() { 88 | return accessCount; 89 | } 90 | 91 | public void setAccessCount(long accessCount) { 92 | this.accessCount = accessCount; 93 | } 94 | 95 | public String getSql() { 96 | return sql; 97 | } 98 | 99 | public void setSql(String sql) { 100 | this.sql = sql; 101 | } 102 | 103 | public boolean isAutoRefresh() { 104 | return autoRefresh; 105 | } 106 | 107 | public void setAutoRefresh(boolean autoRefresh) { 108 | this.autoRefresh = autoRefresh; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/BitSet.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | /** 3 | * 4 | *or zhangwy : 2016年12月28日 上午7:28:45 5 | **/ 6 | public class BitSet { 7 | 8 | private long[] bits; 9 | private final int aviableNum; 10 | private long nextAvail; 11 | 12 | 13 | /** 14 | * 构造 15 | * @param aviableNum 参数 16 | */ 17 | public BitSet(int aviableNum) { 18 | this.aviableNum = aviableNum; 19 | //变成64的倍数 20 | int size = ((this.aviableNum - 1) >>> 6 ) + 1; 21 | bits = new long[size]; 22 | nextAvail = -1; 23 | 24 | } 25 | 26 | public void set(long id) { 27 | checkBound(id); 28 | int base = (int) (id >>> 6); 29 | int offset = (int) (id &(0x3fL)); 30 | long value = (1L << offset); 31 | System.out.println(String.format("base %d offset %d", base, offset)); 32 | bits[base] |= value; 33 | print(); 34 | } 35 | 36 | private void checkBound(long id) { 37 | //ByteBuffer 38 | if(id < 0 || id > aviableNum) { 39 | throw new IndexOutOfBoundsException(String.format("%d 不能小于 0 或者大于容量 %d", id, aviableNum)); 40 | } 41 | } 42 | 43 | public void free(long id) { 44 | checkBound(id); 45 | int base = (int) (id >>> 6); 46 | int offset = (int) (id &(0x3fL)); 47 | long value = ~(1L << offset); 48 | bits[base] &= value; 49 | nextAvail = id; 50 | System.out.println(String.format("free base %d offset %d", base, offset)); 51 | print(); 52 | } 53 | 54 | public long findFree() { 55 | for(int index = 0 ; index < bits.length; index++) { 56 | if((~bits[index]) != 0) { 57 | return findFreebit(index); 58 | } 59 | } 60 | return -1; 61 | } 62 | public void print() { 63 | for(int i = 0 ; i < bits.length; i++) { 64 | System.out.println("bist " + i+ " : " + Long.toBinaryString(bits[i])); 65 | } 66 | } 67 | /** 68 | * 寻找单个long里面的空闲的位置 69 | *@return long 70 | * zhangwy : 2016年12月28日 上午7:50:24 71 | **/ 72 | private long findFreebit(int index) { 73 | if(nextAvail != -1) { 74 | long temp = nextAvail; 75 | nextAvail = -1; 76 | return temp; 77 | } 78 | long value = ~bits[index]; 79 | long flag = 0x1L ; 80 | for(int i = 0 ; i < 64 ; i++) { 81 | if((value & flag) != 0) { 82 | long id = (((long)index) << 6) + i; 83 | if(id < aviableNum) { 84 | return id; 85 | } 86 | return -1; 87 | } 88 | flag <<= 1; 89 | } 90 | 91 | return -1; 92 | } 93 | // public static void main(String[] args) { 94 | // MycatBitSet bitSet = new MycatBitSet(100); 95 | // for(int i = 64 ; i > 0; i--) { 96 | // bitSet.set(i); 97 | // } 98 | // bitSet.free(44); 99 | // bitSet.free(53); 100 | // 101 | // long id = bitSet.findFree(); 102 | // 103 | // System.out.println(bitSet.findFree()); 104 | // bitSet.set(bitSet.findFree()); 105 | // System.out.println(bitSet.findFree()); 106 | // 107 | // } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/bufferpage/BufferPageBase.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.bufferpage; 2 | 3 | import java.util.BitSet; 4 | import java.util.concurrent.atomic.AtomicBoolean; 5 | 6 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 7 | 8 | /** 9 | * 进行内存页数据的相关的抽象 10 | * or kk 11 | * 2017年1月3日 12 | * @version 0.0.1 13 | */ 14 | public abstract class BufferPageBase { 15 | 16 | /** 17 | * 操作的buffer信息 18 | * buffer 19 | */ 20 | protected MycatBufferBase buffer; 21 | 22 | /** 23 | * 每个chunk的大小 24 | * chunkSize 25 | */ 26 | protected int chunkSize; 27 | 28 | /** 29 | * 总的chunk数 30 | * chunkIndex 31 | */ 32 | protected int chunkCount; 33 | 34 | /** 35 | * 用于标识内存是否使用集合 36 | * memUseSet 37 | */ 38 | protected final BitSet memUseSet; 39 | 40 | /** 41 | * 是否锁定标识 42 | * isLock 43 | */ 44 | protected AtomicBoolean isLock = new AtomicBoolean(false); 45 | 46 | /** 47 | * 可以使用的chunkNum 48 | * useMemoryChunkNum 49 | */ 50 | protected int canUseChunkNum; 51 | 52 | public BufferPageBase(MycatBufferBase buffer, int chunkSize) { 53 | this.buffer = buffer; 54 | // 设置chunk的大小 55 | this.chunkSize = chunkSize; 56 | // 设置chunk的数量 57 | this.chunkCount = (int) buffer.limit() / this.chunkSize; 58 | // 设置当前内存标识块的大小 59 | this.memUseSet = new BitSet(this.chunkCount); 60 | // 默认可使用的chunk数量为总的chunk数 61 | this.canUseChunkNum = chunkCount; 62 | } 63 | 64 | public MycatBufferBase getBuffer() { 65 | return buffer; 66 | } 67 | 68 | public void setBuffer(MycatBufferBase buffer) { 69 | this.buffer = buffer; 70 | } 71 | 72 | public int getChunkSize() { 73 | return chunkSize; 74 | } 75 | 76 | public void setChunkSize(int chunkSize) { 77 | this.chunkSize = chunkSize; 78 | } 79 | 80 | public int getChunkCount() { 81 | return chunkCount; 82 | } 83 | 84 | public void setChunkCount(int chunkCount) { 85 | this.chunkCount = chunkCount; 86 | } 87 | 88 | public BitSet getMemUseSet() { 89 | return memUseSet; 90 | } 91 | 92 | /** 93 | * 需要实现的,能够计算可用chunk的方法 94 | * @param chunkNum 参数 95 | * @return 返回 96 | */ 97 | public abstract boolean checkNeedChunk(int chunkNum); 98 | 99 | /** 100 | * 进行指定内存块分配的方法 101 | * @param needChunkSize 需要的内存页数大小 102 | * @return 返回 103 | */ 104 | public abstract MycatBufferBase alloactionMemory(int needChunkSize); 105 | 106 | /** 107 | * 进宪内存归还的方法 108 | * @param parentBuffer 分配的内存对象 109 | * @param chunkStart 开始的内存块索引号 110 | * @param chunkNum 归还的数量 111 | * @return 返回 112 | */ 113 | public abstract boolean recycleBuffer(MycatBufferBase parentBuffer, int chunkStart, int chunkNum); 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/allot/recycle/mark/MarkMoveBufferRecycle.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.allot.recycle.mark; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | import io.mycat.bigmem.chunkpageallot.buffer.impl.DirectMycatBufferMoveImpl; 5 | import io.mycat.bigmem.chunkpageallot.bufferpage.impl.DirectMoveBufferPage; 6 | import io.mycat.bigmem.chunkpageallot.recycle.impl.MarkMovePageRecycleImpl; 7 | 8 | public class MarkMoveBufferRecycle { 9 | 10 | public static void main(String[] args) throws InterruptedException { 11 | 12 | DirectMoveBufferPage movePage = new DirectMoveBufferPage(new DirectMycatBufferMoveImpl(64), 2); 13 | 14 | MycatBufferBase buffer1 = movePage.alloactionMemory(4); 15 | 16 | MycatBufferBase buffer2 = movePage.alloactionMemory(4); 17 | 18 | MycatBufferBase buffer3 = movePage.alloactionMemory(4); 19 | 20 | buffer1.beginOp(); 21 | buffer1.putByte((byte) 11); 22 | buffer1.putByte((byte) 12); 23 | buffer1.putByte((byte) 13); 24 | buffer1.putByte((byte) 14); 25 | // 重置limit容量信息 26 | buffer1.limit(buffer1.putPosition()); 27 | buffer1.commitOp(); 28 | 29 | // 进行buffer1的内存归还操作 30 | movePage.recycleBuffer(buffer1, 0, 0); 31 | 32 | buffer2.beginOp(); 33 | buffer2.putByte((byte) 21); 34 | buffer2.putByte((byte) 22); 35 | // 重新标识归还标识 36 | buffer2.limit(buffer2.putPosition()); 37 | buffer2.commitOp(); 38 | 39 | movePage.recycleBuffer(buffer2, 0, 0); 40 | 41 | buffer3.beginOp(); 42 | buffer3.putByte((byte) 31); 43 | buffer3.limit(buffer3.putPosition() + 1); 44 | buffer3.commitOp(); 45 | 46 | // 回收内存 47 | movePage.recycleBuffer(buffer3, 0, 0); 48 | 49 | printValue(movePage.getBuffer()); 50 | 51 | MarkMovePageRecycleImpl mark = new MarkMovePageRecycleImpl(); 52 | mark.pageClearUp(movePage); 53 | 54 | System.out.println(); 55 | System.out.println(); 56 | System.out.println("-----------------------------"); 57 | System.out.println(); 58 | System.out.println(); 59 | 60 | printValue(movePage.getBuffer()); 61 | 62 | buffer3.beginOp(); 63 | buffer3.putByte((byte) 32); 64 | buffer3.commitOp(); 65 | 66 | System.out.println("-----------------------------"); 67 | System.out.println(); 68 | System.out.println(); 69 | 70 | printValue(movePage.getBuffer()); 71 | 72 | } 73 | 74 | public static void printValue(MycatBufferBase buffer) throws InterruptedException { 75 | 76 | buffer.beginOp(); 77 | 78 | buffer.getPosition(0); 79 | for (int i = 0; i < buffer.limit(); i++) { 80 | System.out.print("value:" + buffer.get() + "\t"); 81 | if (i % 4 == 3) { 82 | System.out.println(); 83 | } 84 | } 85 | 86 | System.out.println(); 87 | System.out.println(); 88 | 89 | buffer.commitOp(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/AbstractReferenceCountedByteBuf.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | import io.mycat.bigmem.util.IllegalReferenceCountException; 4 | 5 | import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; 6 | 7 | import static io.mycat.bigmem.util.internal.ObjectUtil.checkPositive; 8 | 9 | /** 10 | * Created by tracywwp on 2017/1/12 0012. 11 | * 12 | * 抽象基类{@link BaseByteBuffer }实现计数参考。 13 | */ 14 | public abstract class AbstractReferenceCountedByteBuf extends BaseByteBuffer { 15 | private static final AtomicIntegerFieldUpdater refCntUpdater = 16 | AtomicIntegerFieldUpdater.newUpdater(AbstractReferenceCountedByteBuf.class, "refCnt"); 17 | 18 | private volatile int refCnt = 1; 19 | 20 | protected AbstractReferenceCountedByteBuf(int maxCapacity) { 21 | super(maxCapacity); 22 | } 23 | 24 | @Override 25 | public int refCnt() { 26 | return refCnt; 27 | } 28 | 29 | /** 30 | * 由子类直接使用的不安全操作,该类直接设置缓冲区的引用计数 31 | * @param refCnt 参数 32 | */ 33 | protected final void setRefCnt(int refCnt) { 34 | this.refCnt = refCnt; 35 | } 36 | 37 | @Override 38 | public BaseByteBuffer retain() { 39 | return retain0(1); 40 | } 41 | 42 | @Override 43 | public BaseByteBuffer retain(int increment) { 44 | return retain0(checkPositive(increment, "increment")); 45 | } 46 | 47 | private BaseByteBuffer retain0(int increment) { 48 | for (;;) { 49 | int refCnt = this.refCnt; 50 | final int nextCnt = refCnt + increment; 51 | 52 | //确保不会重复使用(意味着refcnt为0),同时我们遇到一个溢出 53 | if (nextCnt <= increment) { 54 | throw new IllegalReferenceCountException(refCnt, increment); 55 | } 56 | if (refCntUpdater.compareAndSet(this, refCnt, nextCnt)) { 57 | break; 58 | } 59 | } 60 | return this; 61 | } 62 | 63 | @Override 64 | public BaseByteBuffer touch() { 65 | return this; 66 | } 67 | 68 | @Override 69 | public BaseByteBuffer touch(Object hint) { 70 | return this; 71 | } 72 | 73 | @Override 74 | public boolean release() { 75 | return release0(1); 76 | } 77 | 78 | @Override 79 | public boolean release(int decrement) { 80 | return release0(checkPositive(decrement, "decrement")); 81 | } 82 | 83 | private boolean release0(int decrement) { 84 | for (;;) { 85 | int refCnt = this.refCnt; 86 | if (refCnt < decrement) { 87 | throw new IllegalReferenceCountException(refCnt, -decrement); 88 | } 89 | 90 | if (refCntUpdater.compareAndSet(this, refCnt, refCnt - decrement)) { 91 | if (refCnt == decrement) { 92 | deallocate(); 93 | return true; 94 | } 95 | return false; 96 | } 97 | } 98 | } 99 | /** 100 | * 101 | * refCnt()方法是否等于0 102 | */ 103 | protected abstract void deallocate(); 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/BigSQLResult.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import io.mycat.bigmem.console.LocatePolicy; 4 | import io.mycat.bigmem.sqlcache.impl.mmap.MappedSQLResult; 5 | 6 | import java.io.IOException; 7 | import java.util.Iterator; 8 | 9 | import static com.google.common.hash.Hashing.murmur3_32; 10 | 11 | /** 12 | * SQL大结果集缓存 13 | * 14 | * or zagnix 15 | * @version 1.0 16 | * 2016-12-27 18:48 17 | */ 18 | 19 | public class BigSQLResult implements Iterator { 20 | 21 | private ISQLResult sqlResult; 22 | private String cacheDir; 23 | 24 | public BigSQLResult(LocatePolicy locatePolicy, String sql, int pageSize){ 25 | /** 26 | * Core - DirectMemory 27 | * Normal - mmap 28 | */ 29 | this.cacheDir = "sqlcache/"; 30 | String sqlkey = ""+murmur3_32().hashUnencodedChars(sql); 31 | 32 | if (locatePolicy.equals(LocatePolicy.Normal)){ 33 | try { 34 | sqlResult = new MappedSQLResult(cacheDir,sqlkey,pageSize); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | }else if(locatePolicy.equals(LocatePolicy.Core)){ 39 | 40 | } 41 | } 42 | 43 | /** 44 | * 添加一条sql二进制数据到Cache存储中 45 | * @param data 参数 46 | */ 47 | public void put(byte [] data){ 48 | try { 49 | sqlResult.put(data); 50 | } catch (IOException e) { 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | /** 56 | * 数据是否为空 57 | * @return 返回 58 | */ 59 | public boolean isEmpty(){ 60 | return sqlResult.isEmpty(); 61 | } 62 | 63 | /** 64 | * 还有下一条sql结果集? 65 | * @return 返回 66 | */ 67 | public boolean hasNext() { 68 | return !sqlResult.isEmpty(); 69 | } 70 | 71 | /** 72 | * 取下一条sql结果集 73 | * 74 | * @return 返回 75 | */ 76 | public byte[] next() { 77 | try { 78 | return sqlResult.next(); 79 | } catch (IOException e) { 80 | e.printStackTrace(); 81 | } 82 | return null; 83 | } 84 | 85 | /** 86 | * Iterator interface 87 | */ 88 | public void remove() { 89 | //TODO 90 | } 91 | 92 | /** 93 | * 主动将内存映射文件的数据刷到磁盘中 94 | */ 95 | public void flush(){ 96 | sqlResult.flush(); 97 | } 98 | 99 | /** 100 | * sql 结果集大小 101 | * @return 返回 102 | */ 103 | public long size(){ 104 | return sqlResult.size(); 105 | } 106 | 107 | /** 108 | * 从 PageLRUCache中移除Page,并执行unmap操作,并删除对于文件 109 | */ 110 | public void removeAll(){ 111 | try { 112 | sqlResult.removeAll(); 113 | } catch (IOException e) { 114 | e.printStackTrace(); 115 | } 116 | } 117 | 118 | /** 119 | * 从 PageLRUCache中移除Page,并执行unmap操作,但不删除文件 120 | * 下次运行时候可以读取文件内容 121 | */ 122 | public void recycle(){ 123 | try { 124 | sqlResult.recycle(); 125 | } catch (IOException e) { 126 | e.printStackTrace(); 127 | } 128 | } 129 | 130 | /** 131 | * 复位读位置为0,从头开始读取sql结果集 132 | */ 133 | public void reset(){ 134 | sqlResult.reset(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/MyCatBufferPage.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.nio.ByteBuffer; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | /** 11 | * Mycat Buffer Page 抽象类 12 | * 13 | * or zagnix 14 | * @version 1.0 15 | * 2016-12-27 18:49 16 | */ 17 | 18 | public abstract class MyCatBufferPage implements IBufferPage { 19 | private final static Logger logger = 20 | LoggerFactory.getLogger(MyCatBufferPage.class); 21 | 22 | protected volatile boolean dirty = false; 23 | protected volatile boolean recycled = false; 24 | 25 | /** 26 | * Thread Local Buffer Page 27 | */ 28 | protected ThreadLocalByteBuffer threadLocalByteBuffer; 29 | 30 | /** 31 | * Page 上次访问时间 32 | */ 33 | protected AtomicLong lastAccessedTimestamp; 34 | 35 | /** 36 | * Page 访问引用计数 37 | */ 38 | protected AtomicLong refCount = new AtomicLong(0); 39 | 40 | 41 | /** 42 | * 缓存时间 43 | */ 44 | protected long cacheTTL = 0L; 45 | 46 | public MyCatBufferPage(ByteBuffer byteBuffer,long cacheTTL){ 47 | this.lastAccessedTimestamp = new AtomicLong(System.currentTimeMillis()); 48 | this.threadLocalByteBuffer = new ThreadLocalByteBuffer(byteBuffer); 49 | this.cacheTTL = cacheTTL; 50 | } 51 | 52 | 53 | /** 54 | * Page 是 '脏页' 55 | * @return 返回 56 | */ 57 | 58 | public boolean isDirty() { 59 | return dirty; 60 | } 61 | 62 | 63 | /** 64 | * 设置 Page 是否 是 ‘脏页’ 65 | * @param dirty 参数 66 | */ 67 | public void setDirty(boolean dirty) { 68 | this.dirty = dirty; 69 | } 70 | 71 | /** 72 | * Page 是否被 unmap了 73 | * @return 返回 74 | */ 75 | public boolean isRecycled() { 76 | return recycled; 77 | } 78 | 79 | public void setRecycled(boolean recycled) { 80 | this.recycled = recycled; 81 | } 82 | 83 | public ThreadLocalByteBuffer getThreadLocalByteBuffer() { 84 | return threadLocalByteBuffer; 85 | } 86 | 87 | public void setThreadLocalByteBuffer(ThreadLocalByteBuffer threadLocalByteBuffer) { 88 | this.threadLocalByteBuffer = threadLocalByteBuffer; 89 | } 90 | 91 | public AtomicLong getLastAccessedTimestamp() { 92 | return lastAccessedTimestamp; 93 | } 94 | 95 | public void setLastAccessedTimestamp(AtomicLong lastAccessedTimestamp) { 96 | this.lastAccessedTimestamp = lastAccessedTimestamp; 97 | } 98 | 99 | public AtomicLong getRefCount() { 100 | return refCount; 101 | } 102 | 103 | public void setRefCount(AtomicLong refCount) { 104 | this.refCount = refCount; 105 | } 106 | 107 | public long getCacheTTL() { 108 | return cacheTTL; 109 | } 110 | 111 | public void setCacheTTL(long cacheTTL) { 112 | this.cacheTTL = cacheTTL; 113 | } 114 | 115 | 116 | /** 117 | * Thread Local ByteBuffer 118 | */ 119 | protected static class ThreadLocalByteBuffer extends ThreadLocal { 120 | private ByteBuffer byteBuffer; 121 | 122 | public ThreadLocalByteBuffer(ByteBuffer src) { 123 | byteBuffer = src; 124 | } 125 | 126 | public ByteBuffer getByteBuffer() { 127 | return byteBuffer; 128 | } 129 | 130 | public void setByteBuffer(ByteBuffer byteBuffer) { 131 | this.byteBuffer = byteBuffer; 132 | } 133 | 134 | 135 | @Override 136 | protected synchronized ByteBuffer initialValue() { 137 | ByteBuffer bbuffer = byteBuffer.duplicate(); 138 | return bbuffer; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/internal/ObjectUtil.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util.internal; 2 | 3 | /** 4 | * 5 | * 一种有用的实用方法工具类 6 | */ 7 | public final class ObjectUtil { 8 | 9 | private ObjectUtil() { 10 | } 11 | 12 | /** 13 | * Checks that the given argument is not null. If it is, throws {@link NullPointerException}. 14 | * Otherwise, returns the argument. 15 | * @param arg 参数 16 | * @param text 参数 17 | * @param 参数泛型与返回泛型 18 | * @return 参数 19 | */ 20 | public static T checkNotNull(T arg, String text) { 21 | if (arg == null) { 22 | throw new NullPointerException(text); 23 | } 24 | return arg; 25 | } 26 | 27 | /** 28 | * Checks that the given argument is strictly positive. If it is, throws {@link IllegalArgumentException}. 29 | * Otherwise, returns the argument. 30 | * @param i 参数 31 | * @param name 参数 32 | * @return 参数 33 | */ 34 | public static int checkPositive(int i, String name) { 35 | if (i <= 0) { 36 | throw new IllegalArgumentException(name + ": " + i + " (expected: > 0)"); 37 | } 38 | return i; 39 | } 40 | 41 | /** 42 | * Checks that the given argument is strictly positive. If it is, throws {@link IllegalArgumentException}. 43 | * Otherwise, returns the argument. 44 | * @param i 参数 45 | * @param name 参数 46 | * @return 参数 47 | */ 48 | public static long checkPositive(long i, String name) { 49 | if (i <= 0) { 50 | throw new IllegalArgumentException(name + ": " + i + " (expected: > 0)"); 51 | } 52 | return i; 53 | } 54 | 55 | /** 56 | * Checks that the given argument is positive or zero. If it is, throws {@link IllegalArgumentException}. 57 | * Otherwise, returns the argument. 58 | * @param i 参数 59 | * @param name 参数 60 | * @return 参数 61 | */ 62 | public static int checkPositiveOrZero(int i, String name) { 63 | if (i < 0) { 64 | throw new IllegalArgumentException(name + ": " + i + " (expected: >= 0)"); 65 | } 66 | return i; 67 | } 68 | 69 | /** 70 | * Checks that the given argument is positive or zero. If it is, throws {@link IllegalArgumentException}. 71 | * Otherwise, returns the argument. 72 | * @param i 参数 73 | * @param name 参数 74 | * @return 参数 75 | */ 76 | public static long checkPositiveOrZero(long i, String name) { 77 | if (i < 0) { 78 | throw new IllegalArgumentException(name + ": " + i + " (expected: >= 0)"); 79 | } 80 | return i; 81 | } 82 | 83 | /** 84 | * Checks that the given argument is neither null nor empty. 85 | * If it is, throws {@link NullPointerException} or {@link IllegalArgumentException}. 86 | * Otherwise, returns the argument. 87 | * @param array 参数 88 | * @param name 参数 89 | * @param 参数与返回泛型 90 | * @return 返回 91 | */ 92 | public static T[] checkNonEmpty(T[] array, String name) { 93 | checkNotNull(array, name); 94 | checkPositive(array.length, name + ".length"); 95 | return array; 96 | } 97 | 98 | /** 99 | * Resolves a possibly null Integer to a primitive int, using a default value. 100 | * @param wrapper the wrapper 101 | * @param defaultValue the default value 102 | * @return the primitive value 103 | */ 104 | public static int intValue(Integer wrapper, int defaultValue) { 105 | return wrapper != null ? wrapper.intValue() : defaultValue; 106 | } 107 | 108 | /** 109 | * Resolves a possibly null Long to a primitive long, using a default value. 110 | * @param wrapper the wrapper 111 | * @param defaultValue the default value 112 | * @return the primitive value 113 | */ 114 | public static long longValue(Long wrapper, long defaultValue) { 115 | return wrapper != null ? wrapper.longValue() : defaultValue; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/recycle/impl/MarkMovePageRecycleImpl.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.recycle.impl; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Set; 7 | 8 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 9 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageBase; 10 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageMoveInf; 11 | import io.mycat.bigmem.chunkpageallot.recycle.MemoryPageClearUpInf; 12 | 13 | /** 14 | * 使用标记-移动的算法进行内存块的回收 15 | * or kk 16 | * 2017年1月3日 17 | * @version 0.0.1 18 | */ 19 | public class MarkMovePageRecycleImpl implements MemoryPageClearUpInf { 20 | 21 | @Override 22 | public void pageClearUp(BufferPageBase page) { 23 | // 检查当前是否已经实现了内存页的整理接口 24 | if (page instanceof BufferPageMoveInf) { 25 | // 找出前buffer中所有已经分配出去的内存对象信息 26 | BufferPageMoveInf movePage = (BufferPageMoveInf) page; 27 | 28 | Set bufferList = movePage.getSliceMemory(); 29 | 30 | // 未使用的首个内存索引 31 | int notUseIndexStart = 0; 32 | 33 | // 已经使用内存块 34 | List useBuffer = new ArrayList<>(1); 35 | 36 | // 找到第一个未使用内存块信息,以及未使用的内存后,第一个已经使用的内存 37 | notUseIndexStart = this.getNotUseIndex(bufferList, notUseIndexStart, page, useBuffer); 38 | 39 | if (!useBuffer.isEmpty()) { 40 | MycatBufferBase useBufferBase = useBuffer.remove(0); 41 | // 进行首次的内存的移动 42 | ((BufferPageMoveInf) page).memoryCopy(useBufferBase, notUseIndexStart); 43 | notUseIndexStart = notUseIndexStart + useBufferBase.limit() / page.getChunkSize(); 44 | 45 | // 从引用开始遍历 46 | Iterator bufferIter = bufferList.iterator(); 47 | while (bufferIter.hasNext()) { 48 | MycatBufferBase useItem = bufferIter.next(); 49 | 50 | if (useItem.address() > useBufferBase.address()) { 51 | ((BufferPageMoveInf) page).memoryCopy(useItem, notUseIndexStart); 52 | notUseIndexStart += useItem.limit() / page.getChunkSize(); 53 | } 54 | } 55 | 56 | } else { 57 | 58 | } 59 | 60 | } 61 | } 62 | 63 | /** 64 | * 获取已经使用索引编号信息 65 | * @param bufferList 所有引用对象 66 | * @param index 进行内存遍历的首个索引 67 | * @param notUseIndexStart 未使用索引号,从0开始遍历 68 | * @param page 内存页信息 69 | * @param useBuffer 找到的引用对象信息 70 | * @return 未使用的索引号 71 | */ 72 | private int getNotUseIndex(Set bufferList, int notUseIndexStart, BufferPageBase page, 73 | List useBuffer) { 74 | 75 | // 获取最基本的内存地址 76 | long baseAddress = page.getBuffer().address(); 77 | int chunkSize = page.getChunkSize(); 78 | 79 | if (null != bufferList && !bufferList.isEmpty()) { 80 | 81 | // 从引用开始遍历 82 | Iterator bufferIter = bufferList.iterator(); 83 | while (bufferIter.hasNext()) { 84 | MycatBufferBase useItem = bufferIter.next(); 85 | 86 | // 如果按顺序的内存地址与集合中相同,说明当前块已经使用 87 | if ((notUseIndexStart * chunkSize + baseAddress) == useItem.address()) { 88 | // 跳转至下一个内存块的开始处 89 | notUseIndexStart += useItem.limit() / chunkSize; 90 | continue; 91 | } 92 | // 找到空余内存块后的第一块内存块的信息 93 | else { 94 | useBuffer.add(useItem); 95 | break; 96 | } 97 | 98 | } 99 | } 100 | 101 | return notUseIndexStart; 102 | } 103 | 104 | private void printBuffer(Set bufferList) { 105 | for (MycatBufferBase mycatBufferBase : bufferList) { 106 | System.out.println(mycatBufferBase.address()); 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/test/java/io/mycat/bigmem/sqlcache/testBigSQLResultCache.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | 4 | import io.mycat.bigmem.console.LocatePolicy; 5 | import io.mycat.bigmem.util.Utils; 6 | import org.junit.After; 7 | import org.junit.Assert; 8 | import org.junit.Test; 9 | 10 | import java.io.IOException; 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | import static com.google.common.hash.Hashing.murmur3_32; 16 | import static org.junit.Assert.*; 17 | 18 | //TODO 待完善测试用例 19 | public class testBigSQLResultCache { 20 | private BigSQLResult sqlResultCache; 21 | 22 | @Test 23 | public void simpleTest() throws IOException { 24 | for(int i = 1; i <= 2; i++) { 25 | 26 | sqlResultCache = new BigSQLResult(LocatePolicy.Normal, "select * from t",16*1024*1024); 27 | assertNotNull(sqlResultCache); 28 | 29 | for(int j = 1; j <= 3; j++) { 30 | assertTrue(sqlResultCache.size() == 0L); 31 | assertTrue(sqlResultCache.isEmpty()); 32 | 33 | assertNull(sqlResultCache.next()); 34 | 35 | sqlResultCache.put("hello".getBytes()); 36 | assertTrue(sqlResultCache.size() == 1L); 37 | assertTrue(sqlResultCache.hasNext()); 38 | assertEquals("hello", new String(sqlResultCache.next())); 39 | assertNull(sqlResultCache.next()); 40 | 41 | sqlResultCache.put("world".getBytes()); 42 | sqlResultCache.flush(); 43 | assertTrue(sqlResultCache.size() == 1L); 44 | assertTrue(sqlResultCache.hasNext()); 45 | assertEquals("world", new String(sqlResultCache.next())); 46 | assertNull(sqlResultCache.next()); 47 | } 48 | sqlResultCache.recycle(); 49 | } 50 | } 51 | 52 | 53 | @Test 54 | public void testSQLResultCache(){ 55 | long ROWS = 10000; 56 | //long ROWS = 10000*10000; 57 | //long ROWS = 100000*100000; 58 | Map sqlResultCacheMap = new HashMap(); 59 | 60 | String sql = "select * from table1"; 61 | String sqlkey = ""+murmur3_32().hashUnencodedChars(sql); 62 | 63 | /** 64 | * sql results back list 65 | */ 66 | 67 | ArrayList backList = new ArrayList(); 68 | 69 | 70 | /** 71 | * 使用内存映射Cache,存放SQL结果集 72 | */ 73 | 74 | BigSQLResult sqlResultCache 75 | = new BigSQLResult(LocatePolicy.Normal,sqlkey,16*1024*1024); 76 | 77 | for (int i = 0; i < ROWS ; i++) { 78 | byte[] rows = Utils.randomString(1024).getBytes(); 79 | backList.add(rows); 80 | 81 | /** 82 | * 使用内存映射Cache,存放SQL结果集 83 | */ 84 | sqlResultCache.put(rows); 85 | } 86 | sqlResultCacheMap.put(sqlkey,sqlResultCache); 87 | 88 | 89 | 90 | /** 91 | * 验证内存映射Cache,存放SQL结果集 92 | */ 93 | BigSQLResult sqlResCache = sqlResultCacheMap.get(sqlkey); 94 | 95 | Assert.assertEquals(backList.size(),sqlResCache.size()); 96 | for (int i = 0; i this.limit) 113 | throw new BufferOverflowException(); 114 | return this.putPosition++; 115 | } 116 | 117 | /** 118 | * 将获取的指针加1 119 | * 方法描述 120 | * @return 121 | * 2016年12月23日 122 | */ 123 | private long addGetPos() { 124 | if (this.getPosition > this.limit) 125 | throw new BufferOverflowException(); 126 | return this.getPosition++; 127 | } 128 | 129 | @Override 130 | public MycatBuffer putByte(byte b) { 131 | 132 | unsafe.putByte(getIndex(this.addPutPos()), b); 133 | 134 | return this; 135 | } 136 | 137 | @Override 138 | public byte get() { 139 | 140 | return unsafe.getByte(getIndex(this.addGetPos())); 141 | 142 | } 143 | 144 | @Override 145 | public void commitOp() { 146 | 147 | } 148 | 149 | @Override 150 | public void beginOp() throws InterruptedException { 151 | 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/alloctor/impl/ChunkDirectMemoryImpl.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.alloctor.impl; 2 | 3 | import io.mycat.bigmem.chunkpageallot.alloctor.ChunkMemoryAllotInf; 4 | import io.mycat.bigmem.chunkpageallot.buffer.DirectMemAddressInf; 5 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 6 | import io.mycat.bigmem.chunkpageallot.buffer.impl.DirectMycatBufferImpl; 7 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageBase; 8 | import io.mycat.bigmem.chunkpageallot.bufferpage.impl.DirectBufferPage; 9 | 10 | /** 11 | * 进行直接不可移动的大内存的分配操作 12 | * or liujun 13 | * 2016年12月29日 14 | */ 15 | public class ChunkDirectMemoryImpl implements ChunkMemoryAllotInf { 16 | 17 | /** 18 | * 内存池对象信息 19 | * pool 20 | */ 21 | private BufferPageBase[] POOL; 22 | 23 | /** 24 | * 每个chunk的大小 25 | * CHUNK_SIZE 26 | */ 27 | private int CHUNK_SIZE; 28 | 29 | /** 30 | * 初始化标识 31 | */ 32 | private boolean initFlag; 33 | 34 | @Override 35 | public void allotorInit(int memSize, int chunkSize, short poolSize) { 36 | if (!initFlag) { 37 | CHUNK_SIZE = chunkSize; 38 | // 进行每个内存页的初始化 39 | POOL = new DirectBufferPage[poolSize]; 40 | // 进行每个chunk的页面的分配内存操作 41 | for (int i = 0; i < poolSize; i++) { 42 | POOL[i] = new DirectBufferPage(new DirectMycatBufferImpl(memSize), CHUNK_SIZE); 43 | } 44 | // 标识初始化完成 45 | initFlag = true; 46 | } else { 47 | throw new RuntimeException("ChunkDirectMemoryImpl init already!"); 48 | } 49 | } 50 | 51 | @Override 52 | public MycatBufferBase allocMem(int size) { 53 | 54 | if (!initFlag) { 55 | throw new RuntimeException("ChunkDirectMemoryImpl memory not init ,please invoke allotorInit"); 56 | } 57 | 58 | // 计算需要的chunk大小 59 | int needChunk = size % CHUNK_SIZE == 0 ? size / CHUNK_SIZE : size / CHUNK_SIZE + 1; 60 | // 取得内存页信息 61 | BufferPageBase page = null; 62 | for (BufferPageBase pageMemory : POOL) { 63 | if (pageMemory.checkNeedChunk(needChunk)) { 64 | page = pageMemory; 65 | break; 66 | } 67 | } 68 | 69 | // 如果能找合适的内存空间,则进行分配 70 | if (null != page) { 71 | // 针对当前的chunk进行内存的分配操作 72 | MycatBufferBase buffer = page.alloactionMemory(needChunk); 73 | return buffer; 74 | } 75 | return null; 76 | } 77 | 78 | @Override 79 | public boolean recyleMem(MycatBufferBase buffer) { 80 | 81 | // 验证当前的buffer再进行回收 82 | if (null != buffer && buffer instanceof DirectMycatBufferImpl) { 83 | 84 | if (buffer.limit() < buffer.capacity()) { 85 | 86 | // 计算chunk归还的数量 87 | int chunkNum = (int) (buffer.capacity() - buffer.limit()) / CHUNK_SIZE; 88 | 89 | // 获得内存buffer 90 | DirectMemAddressInf thisNavBuf = (DirectMemAddressInf) buffer; 91 | // attachment对象在buf.slice();的时候将attachment对象设置为总的buff对象 92 | DirectMemAddressInf parentBuf = (DirectMemAddressInf) thisNavBuf.getAttach(); 93 | 94 | int chunkAdd = buffer.limit() % CHUNK_SIZE == 0 ? (int) buffer.limit() / CHUNK_SIZE 95 | : (int) buffer.limit() / CHUNK_SIZE + 1; 96 | // 已经使用的地址减去父类最开始的地址,即为所有已经使用的地址,除以chunkSize得到chunk当前开始的地址,得到整块内存开始的地址 97 | int startChunk = (int) ((thisNavBuf.address() - parentBuf.address()) / CHUNK_SIZE) + chunkAdd; 98 | 99 | boolean recyProc = false; 100 | 101 | for (BufferPageBase pageMemory : POOL) { 102 | if ((recyProc = pageMemory.recycleBuffer((MycatBufferBase) parentBuf, startChunk, 103 | chunkNum)) == true) { 104 | break; 105 | } 106 | } 107 | 108 | if (!recyProc) { 109 | System.out.println("memory recycle fail"); 110 | } 111 | } else { 112 | System.out.println("not memory recycle"); 113 | } 114 | 115 | return true; 116 | } 117 | 118 | return false; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/alloctor/impl/ChunkFileMapMemoryImpl.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.alloctor.impl; 2 | 3 | import java.io.IOException; 4 | 5 | import io.mycat.bigmem.chunkpageallot.alloctor.ChunkMemoryAllotInf; 6 | import io.mycat.bigmem.chunkpageallot.buffer.DirectMemAddressInf; 7 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 8 | import io.mycat.bigmem.chunkpageallot.buffer.impl.MapFileBufferImp; 9 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageBase; 10 | import io.mycat.bigmem.chunkpageallot.bufferpage.impl.FileMapBufferPage; 11 | 12 | /** 13 | * 进行直接可移动的大内存的分配操作 14 | * or liujun 15 | * 2016年12月29日 16 | */ 17 | public class ChunkFileMapMemoryImpl implements ChunkMemoryAllotInf { 18 | 19 | /** 20 | * 内存池对象信息 21 | * pool 22 | */ 23 | private BufferPageBase[] POOL; 24 | 25 | /** 26 | * 每个chunk的大小 27 | * CHUNK_SIZE 28 | */ 29 | private int CHUNK_SIZE; 30 | 31 | /** 32 | * 初始化标识 33 | */ 34 | private boolean initFlag; 35 | 36 | @Override 37 | public void allotorInit(int memSize, int chunkSize, short poolSize) { 38 | CHUNK_SIZE = chunkSize; 39 | // 进行每个内存页的初始化 40 | POOL = new FileMapBufferPage[poolSize]; 41 | try { 42 | // 进行每个chunk的页面的分配内存操作,每个mapfile文件默认为128M 43 | for (int i = 0; i < poolSize; i++) { 44 | POOL[i] = new FileMapBufferPage(new MapFileBufferImp(memSize), CHUNK_SIZE); 45 | } 46 | } catch (IOException e) { 47 | e.printStackTrace(); 48 | throw new RuntimeException("ChunkFileMapMemoryImpl allotorInit exception", e); 49 | } 50 | // 标识初始化完成 51 | initFlag = true; 52 | } 53 | 54 | @Override 55 | public MycatBufferBase allocMem(int size) { 56 | 57 | if (!initFlag) { 58 | throw new RuntimeException("ChunkDirectMemoryImpl memory not init ,please invoke allotorInit"); 59 | } 60 | 61 | // 计算需要的chunk大小 62 | int needChunk = size % CHUNK_SIZE == 0 ? size / CHUNK_SIZE : size / CHUNK_SIZE + 1; 63 | // 取得内存页信息 64 | BufferPageBase page = null; 65 | for (BufferPageBase pageMemory : POOL) { 66 | if (pageMemory.checkNeedChunk(needChunk)) { 67 | page = pageMemory; 68 | break; 69 | } 70 | } 71 | 72 | // 如果能找合适的内存空间,则进行分配 73 | if (null != page) { 74 | // 针对当前的chunk进行内存的分配操作 75 | MycatBufferBase buffer = page.alloactionMemory(needChunk); 76 | return buffer; 77 | } 78 | return null; 79 | } 80 | 81 | @Override 82 | public boolean recyleMem(MycatBufferBase buffer) { 83 | 84 | // 验证当前的buffer再进行回收 85 | if (null != buffer && buffer instanceof MapFileBufferImp) { 86 | 87 | if (buffer.limit() < buffer.capacity()) { 88 | 89 | // 计算chunk归还的数量 90 | int chunkNum = (int) (buffer.capacity() - buffer.limit()) / CHUNK_SIZE; 91 | 92 | // 获得内存buffer 93 | DirectMemAddressInf thisNavBuf = (DirectMemAddressInf) buffer; 94 | // attachment对象在buf.slice();的时候将attachment对象设置为总的buff对象 95 | DirectMemAddressInf parentBuf = (DirectMemAddressInf) thisNavBuf.getAttach(); 96 | 97 | int chunkAdd = buffer.limit() % CHUNK_SIZE == 0 ? (int) buffer.limit() / CHUNK_SIZE 98 | : (int) buffer.limit() / CHUNK_SIZE + 1; 99 | // 已经使用的地址减去父类最开始的地址,即为所有已经使用的地址,除以chunkSize得到chunk当前开始的地址,得到整块内存开始的地址 100 | int startChunk = (int) ((thisNavBuf.address() - parentBuf.address()) / CHUNK_SIZE) + chunkAdd; 101 | 102 | boolean recyProc = false; 103 | 104 | for (BufferPageBase pageMemory : POOL) { 105 | if ((recyProc = pageMemory.recycleBuffer((MycatBufferBase) parentBuf, startChunk, 106 | chunkNum)) == true) { 107 | break; 108 | } 109 | } 110 | 111 | if (!recyProc) { 112 | System.out.println("memory recycle fail"); 113 | } 114 | } else { 115 | System.out.println("not memory recycle"); 116 | } 117 | 118 | return true; 119 | } 120 | 121 | return false; 122 | 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/alloctor/MycatMemoryAllocator.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.alloctor; 2 | 3 | import java.io.IOException; 4 | import java.util.Set; 5 | import java.util.TreeSet; 6 | 7 | import io.mycat.bigmem.chunkpageallot.MemoryAllocatorInf; 8 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 9 | import io.mycat.bigmem.chunkpageallot.console.ChunkMemoryAllotEnum; 10 | 11 | /** 12 | * java 内存池的实现 13 | * 源文件名:MemoryPool.java 14 | * 文件版本:1.0.0 15 | * 创建作者:liujun 16 | * 创建日期:2016年12月19日 17 | * 修改作者:liujun 18 | * 修改日期:2016年12月19日 19 | * 文件描述:TODO 20 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 21 | */ 22 | public class MycatMemoryAllocator implements MemoryAllocatorInf { 23 | 24 | /** 25 | * 存储级别的map 26 | */ 27 | private static Set MEMORY_LEVEL = new TreeSet<>((o1, o2) -> { 28 | if (o1.getLevel() < o2.getLevel()) { 29 | return 1; 30 | } else if (o1.getLevel() > o2.getLevel()) { 31 | return -1; 32 | } 33 | return 0; 34 | }); 35 | 36 | /** 37 | * 用来构建内存池对象信息 38 | * @throws IOException 异常信息 39 | */ 40 | public MycatMemoryAllocator() throws IOException { 41 | int msize = 1024 * 1024; 42 | 43 | for (int i = 0; i < ChunkMemoryAllotEnum.values().length; i++) { 44 | MEMORY_LEVEL.add(ChunkMemoryAllotEnum.values()[i]); 45 | } 46 | 47 | // 构建文件映射的相关初始化 48 | ChunkMemoryAllotEnum.MEMORY_MAPFILE.getChunkAllot().allotorInit(msize * 128, 4096, (short) 1); 49 | // 可移动的内存文件块的构建 50 | ChunkMemoryAllotEnum.MEMORY_DIRECT_MOVE.getChunkAllot().allotorInit(msize * 256, 4096, (short) 1); 51 | // 进行不可移动的内存块的构建 52 | ChunkMemoryAllotEnum.MEMORY_DIRECT.getChunkAllot().allotorInit(msize * 16, 4096, (short) 1); 53 | } 54 | 55 | /** 56 | * 获取最高级别,也就是最先匹配的级别 57 | * @param allocFlag 58 | * @param minlevel 59 | * @return 60 | */ 61 | private ChunkMemoryAllotEnum memoryMatchlevel(int allocFlag, int index) { 62 | 63 | ChunkMemoryAllotEnum chunkAllot = null; 64 | 65 | for (ChunkMemoryAllotEnum chunkMemoryAllotEnum : MEMORY_LEVEL) { 66 | // 首次需要匹配上最优的内存内存操作 67 | if (index == 0) { 68 | // 检查是否有当前的级别 69 | if ((chunkMemoryAllotEnum.getLevel() & allocFlag) == chunkMemoryAllotEnum.getLevel()) { 70 | chunkAllot = chunkMemoryAllotEnum; 71 | break; 72 | } 73 | } else { 74 | // 按级别选择最优的内存 75 | if (chunkMemoryAllotEnum.getMoveBit() < index 76 | && (chunkMemoryAllotEnum.getLevel() & allocFlag) == chunkMemoryAllotEnum.getLevel()) { 77 | chunkAllot = chunkMemoryAllotEnum; 78 | } 79 | } 80 | } 81 | 82 | return chunkAllot; 83 | } 84 | 85 | /** 86 | * 进行内存分配操作 87 | * 方法描述 88 | * @param size 需要的内存大小,最好CHUNK_SIZE的倍数,以方便 内存的回收利用 89 | * @return 90 | * 2016年12月19日 91 | */ 92 | public MycatBufferBase allocMem(int allocFlag, int size) { 93 | 94 | MycatBufferBase mycatBuffer = null; 95 | 96 | // 首次为0匹配上最想要的内存 97 | int index = 0; 98 | 99 | ChunkMemoryAllotEnum allot = null; 100 | while ((allot = this.memoryMatchlevel(allocFlag, index)) != null) { 101 | // 进行内存分配 102 | mycatBuffer = allot.getChunkAllot().allocMem(size); 103 | if (mycatBuffer == null) { 104 | index = allot.getMoveBit(); 105 | continue; 106 | } else { 107 | break; 108 | } 109 | } 110 | 111 | return mycatBuffer; 112 | } 113 | 114 | /** 115 | * 进行内存的归还操作 116 | * 方法描述 117 | * @param buffer 118 | * 2016年12月19日 119 | */ 120 | public void recyleMem(MycatBufferBase buffer) { 121 | if (null != buffer) { 122 | for (ChunkMemoryAllotEnum chunkMemoryAllotEnum : MEMORY_LEVEL) { 123 | boolean rcyle = chunkMemoryAllotEnum.getChunkAllot().recyleMem(buffer); 124 | 125 | // 如果已经回收,则停止遍历 126 | if (rcyle) { 127 | break; 128 | } 129 | } 130 | 131 | // 进行内存的回收操作 132 | // buffer.getMemoryAllotEnum().getChunkAllot().recyleMem(buffer.getMycatBuffer()); 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/buffer/MycatBufferBase.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.buffer; 2 | 3 | import java.io.IOException; 4 | 5 | import io.mycat.bigmem.chunkpageallot.buffer.impl.DirectMycatBufferImpl; 6 | import io.mycat.bigmem.chunkpageallot.buffer.impl.MapFileBufferImp; 7 | import io.mycat.bigmem.console.LocatePolicy; 8 | 9 | /** 10 | * 基本的buffer的父类信息 11 | * 源文件名:MycatBufferBase.java 12 | * 文件版本:1.0.0 13 | * 创建作者:Think 14 | * 创建日期:2016年12月27日 15 | * 修改作者:Think 16 | * 修改日期:2016年12月27日 17 | * 文件描述:TODO 18 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 19 | */ 20 | public abstract class MycatBufferBase implements MycatBuffer, DirectMemAddressInf { 21 | 22 | /** 23 | * 当前写入的指针位置 24 | * position 25 | */ 26 | protected int putPosition; 27 | 28 | /** 29 | * 当前读取指针的位置 30 | * getPosition 31 | */ 32 | protected int getPosition; 33 | 34 | /** 35 | * 当前的的容量 36 | * limit 37 | */ 38 | protected int limit; 39 | 40 | /** 41 | * 容量信息 42 | * capacity 43 | */ 44 | protected int capacity; 45 | 46 | /** 47 | * 内存映射地址信息,在被交换后可以更改 48 | * addr 49 | */ 50 | protected long address; 51 | 52 | /** 53 | * 当前附着的对象 54 | * att 55 | */ 56 | protected Object att; 57 | 58 | /** 59 | * 获取当前的读取指针 60 | * 方法描述 61 | * @return 62 | * 2016年12月27日 63 | */ 64 | public int getPosition() { 65 | return this.getPosition; 66 | } 67 | 68 | /** 69 | * 设置当前的读取指针 70 | * 方法描述 71 | * @param getPosition 72 | * 2016年12月27日 73 | */ 74 | public void getPosition(int getPosition) { 75 | this.getPosition = getPosition; 76 | } 77 | 78 | /** 79 | * 获取当前的容量 80 | * 方法描述 81 | * @return 82 | * 2016年12月27日 83 | */ 84 | public int limit() { 85 | return this.limit; 86 | } 87 | 88 | /** 89 | * 设置当前的容量 90 | * 方法描述 91 | * @param limit 92 | * 2016年12月27日 93 | */ 94 | public void limit(int limit) { 95 | this.limit = limit; 96 | } 97 | 98 | /** 99 | * 获取写入的指针 100 | * 方法描述 101 | * @return 102 | * 2016年12月27日 103 | */ 104 | public int putPosition() { 105 | return this.putPosition; 106 | } 107 | 108 | /** 109 | * 设置写入的指针 110 | * 方法描述 111 | * @param position 112 | * 2016年12月27日 113 | */ 114 | public void putPosition(int position) { 115 | this.putPosition = position; 116 | } 117 | 118 | /** 119 | * 获取容量信息 120 | * 方法描述 121 | * @return 122 | * 2016年12月27日 123 | */ 124 | public int capacity() { 125 | return this.capacity; 126 | } 127 | 128 | /** 129 | * 获取容量信息 130 | * @param capacity 容量 131 | */ 132 | public void capacity(int capacity) { 133 | this.capacity = capacity; 134 | } 135 | 136 | // /** 137 | // * 根据指定的策略信息以获取相应的容量信息 138 | // * @param policy 139 | // * @param capcation 140 | // * @return 141 | // * @throws IOException 142 | // */ 143 | // public static MycatBufferBase getMyCatBuffer(LocatePolicy policy, int 144 | // capcation) throws IOException { 145 | // // 检查是否使用直接内存进行缓存 146 | // if (policy.equals(LocatePolicy.Core)) { 147 | // return new DirectMycatBufferImpl(capcation); 148 | // } else if (policy.equals(LocatePolicy.Normal)) { 149 | // return new MapFileBufferImp(capcation); 150 | // } 151 | // 152 | // return null; 153 | // } 154 | 155 | /** 156 | * 获取地址信息 157 | */ 158 | public long address() { 159 | return this.address; 160 | } 161 | 162 | /** 163 | * 设置内存地址信息 164 | * @param address 地址信息 165 | */ 166 | public void address(long address) { 167 | this.address = address; 168 | } 169 | 170 | /* 171 | * (non-Javadoc) 172 | * 173 | * @see 174 | * io.mycat.bigmem.chunkpageallot.buffer.DirectMemAddressInf#getAttach() 175 | */ 176 | public Object getAttach() { 177 | return this.att; 178 | } 179 | 180 | /** 181 | * 内存可以被管理器移动,首次访问(一个begin 并且 commit操作之后)之前, 用户需要先要调用beginOp(),即完整用法如下 Buf.beginOp(); Read or write 182 | Buf.commitOp(); 183 | * @throws InterruptedException 异常 184 | */ 185 | public abstract void beginOp() throws InterruptedException; 186 | 187 | /** 188 | * 当前操作完成,事要进行内存整理 189 | */ 190 | public abstract void commitOp(); 191 | 192 | } 193 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/MemoryAllocator.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | import io.mycat.bigmem.util.UnsafeUtil; 4 | 5 | import java.nio.ByteBuffer; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | /** 14 | * allocator , recycle and gc all kind of buffers 15 | * 16 | * or shenli 17 | * 18 | */ 19 | public class MemoryAllocator { 20 | 21 | private final static Logger LOGGER = LoggerFactory.getLogger(MemoryAllocator.class); 22 | ByteBuffer buffer; 23 | /** 24 | * 暂不支持MAX_ORDER的设置, 默认为11 25 | */ 26 | private static final int DEFAULT_MAX_ORDER = 11; 27 | 28 | /** 29 | * 小于4096则算法无法支持 30 | */ 31 | private static final int MIN_PAGE_SIZE = 4096; 32 | 33 | /** 34 | * 暂不支持DEFAULT_PAGE_SIZE的设置, 默认为8192 35 | */ 36 | private static final int DEFAULT_PAGE_SIZE = 8192; 37 | 38 | /** 39 | * maxNumArenas占用的内存量不能超过系统总内存的50% maxNumArenas包括公共和独占的 40 | * 1个Arena内默认最小有3个Chunk:tiny, small and other 41 | */ 42 | private static final int MAX_NUM_ARENAS; 43 | 44 | private static final int DEFAULT_NUM_PUBLIC_ARENAS; 45 | 46 | private static final int DEFAULT_NUM_PRIVATE_ARENAS; 47 | 48 | static { 49 | 50 | /** 51 | * defaultChunkSize = 16MB 52 | */ 53 | final int defaultChunkSize = DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER; 54 | 55 | MAX_NUM_ARENAS = (int) UnsafeUtil 56 | .maxDirectMemory() / 2 / 3/ defaultChunkSize; 57 | 58 | final Runtime runtime = Runtime.getRuntime(); 59 | /** 60 | * 公共Arena最小数量 https://github.com/netty/netty/issues/3888 61 | */ 62 | final int defaultMinNumPublicArena = runtime.availableProcessors() * 2; 63 | 64 | DEFAULT_NUM_PUBLIC_ARENAS = Math.max(0, 65 | (int) Math.min(defaultMinNumPublicArena, MAX_NUM_ARENAS)); 66 | 67 | DEFAULT_NUM_PRIVATE_ARENAS = MAX_NUM_ARENAS - DEFAULT_NUM_PUBLIC_ARENAS; 68 | 69 | if (LOGGER.isDebugEnabled()) { 70 | LOGGER.debug("-Dio.mycat.allocator.defaultNumPublicArenas: {}", 71 | DEFAULT_NUM_PUBLIC_ARENAS); 72 | LOGGER.debug("-Dio.mycat.allocator.defaultNumPrivateArenas: {}", 73 | DEFAULT_NUM_PRIVATE_ARENAS); 74 | } 75 | } 76 | 77 | public static final MemoryAllocator CURRENT = new MemoryAllocator(); 78 | 79 | private final Arena[] publicArenas; 80 | private final List privateArenas = Collections.synchronizedList(new ArrayList()); 81 | 82 | private MemoryAllocator() 83 | { 84 | this(DEFAULT_NUM_PUBLIC_ARENAS, DEFAULT_NUM_PRIVATE_ARENAS); 85 | } 86 | 87 | private MemoryAllocator(int nPublicArena, int nPrivateArena) 88 | { 89 | if (nPublicArena > 0) { 90 | publicArenas = new Arena[nPublicArena]; 91 | for (int i = 0; i < publicArenas.length; i ++) { 92 | Arena arena = new DirectArena(DEFAULT_PAGE_SIZE, (int)(DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER), DEFAULT_MAX_ORDER); 93 | publicArenas[i] = arena; 94 | } 95 | }else 96 | { 97 | publicArenas = null; 98 | } 99 | } 100 | 101 | /** 102 | * 申请绑定一个Private Arena。适用于内存需求量大,希望独占Arena,但是所需capacity会动态变化的情况。 绑定后, 103 | * 此Arena不能分配其他内存分配请求,也不会与Thread绑定。 104 | * 105 | * 106 | * @return privateIdx, -1则表示绑定失败 107 | */ 108 | public int allocatePrivate() { 109 | int privateIdx = -1; 110 | if(validateCapacity()) 111 | { 112 | Arena arena = new DirectArena(DEFAULT_PAGE_SIZE, (int)(DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER), DEFAULT_MAX_ORDER);; 113 | if(privateArenas.add(arena)) 114 | { 115 | privateIdx = privateArenas.indexOf(arena); 116 | return privateIdx; 117 | } 118 | } 119 | return privateIdx; 120 | } 121 | 122 | /** 123 | * 清除Private Arena 124 | * @param privateIdx 参数 125 | */ 126 | public void freePrivate(int privateIdx) { 127 | // Arena arena = privateArenas.get(privateIdx); 128 | 129 | } 130 | 131 | public BaseByteBuffer directBuffer(int capacity) { 132 | //暂时简单取余数 133 | int remainder = (int)Thread.currentThread().getId() % publicArenas.length; 134 | return publicArenas[remainder].allocateBuffer(capacity); 135 | } 136 | 137 | /** 138 | * 在private上分配buff 139 | * @param privateIdx 参数 140 | * @param capacity 参数 141 | * @return 返回 142 | */ 143 | public BaseByteBuffer directBuffer(int privateIdx, int capacity) { 144 | return privateArenas.get(privateIdx).allocateBuffer(capacity); 145 | } 146 | 147 | private boolean validateCapacity() 148 | { 149 | return true; 150 | } 151 | // 152 | // public void recycle(DirectByteBuffer theBuf) ; 153 | 154 | public static void main(String[] args) { 155 | MemoryAllocator.CURRENT.directBuffer(10000); 156 | int index = MemoryAllocator.CURRENT.allocatePrivate(); 157 | MemoryAllocator.CURRENT.directBuffer(index, 10000000); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/UnsafeHelper.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Modifier; 5 | 6 | import sun.misc.Unsafe; 7 | 8 | public class UnsafeHelper { 9 | 10 | private static final Unsafe unsafe = createUnsafe(); 11 | 12 | private static Unsafe createUnsafe() { 13 | try { 14 | Field field = Unsafe.class.getDeclaredField("theUnsafe"); 15 | field.setAccessible(true); 16 | return (Unsafe) field.get(null); 17 | } catch (Exception e) { 18 | throw new RuntimeException("Can't use unsafe", e); 19 | } 20 | } 21 | 22 | public static Unsafe getUnsafe() { 23 | return unsafe; 24 | } 25 | 26 | private static long roundUpTo8(final long number) { 27 | return ((number + 7) / 8) * 8; 28 | } 29 | 30 | /** 31 | * Returns the size of the header for an instance of this class (in bytes). 32 | * 33 | * More information http://www.codeinstructions.com/2008/12/java-objects-memory-structure.html 34 | * and http://stackoverflow.com/a/17348396/88646 35 | * 36 | *
 37 |      * ,------------------+------------------+------------------ +---------------.
 38 |      * |    mark word(8)  | klass pointer(4) |  array size (opt) |    padding    |
 39 |      * `------------------+------------------+-------------------+---------------'
 40 |      * 
41 | * 42 | * @param clazz 参数 43 | * @return 返回 44 | */ 45 | public static long headerSize(Class clazz) { 46 | // TODO Should be calculated based on the platform 47 | // TODO maybe unsafe.addressSize() would help? 48 | long len = 12; // JVM_64 has a 12 byte header 8 + 4 (with compressed 49 | // pointers on) 50 | if (clazz.isArray()) { 51 | len += 4; 52 | } 53 | return len; 54 | } 55 | 56 | /** 57 | * Returns the offset of the first field in the range [headerSize, sizeOf]. 58 | * 59 | * @param clazz 参数 60 | * @return 参数 61 | */ 62 | public static long firstFieldOffset(Class clazz) { 63 | long minSize = roundUpTo8(headerSize(clazz)); 64 | 65 | // Find the min offset for all the classes, up the class hierarchy. 66 | while (clazz != Object.class) { 67 | for (Field f : clazz.getDeclaredFields()) { 68 | if ((f.getModifiers() & Modifier.STATIC) == 0) { 69 | long offset = unsafe.objectFieldOffset(f); 70 | if (offset < minSize) { 71 | minSize = offset; 72 | } 73 | } 74 | } 75 | clazz = clazz.getSuperclass(); 76 | } 77 | 78 | return minSize; 79 | } 80 | 81 | public static long sizeOf(Object obj) { 82 | Class clazz = obj.getClass(); 83 | 84 | long len = sizeOf(clazz); 85 | 86 | if (clazz.isArray()) { 87 | // TODO Do extra work 88 | // TODO move into sizeof(Object) 89 | // (8) first longs and doubles; then 90 | // (4) ints and floats; then 91 | // (2) chars and shorts; then 92 | // (1) bytes and booleans, and last the 93 | // (4-8) references. 94 | Object[] array = (Object[]) obj; 95 | len += array.length * 8; 96 | } 97 | 98 | return len; 99 | } 100 | 101 | /** 102 | * Returns the size of an instance of this class (in bytes). 103 | * Instances include a header + all fields + padded to 8 bytes. 104 | * If this is an array, it does not include the size of the elements. 105 | * 106 | * @param clazz 参数 107 | * @return 参数 108 | */ 109 | public static long sizeOf(Class clazz) { 110 | long maxSize = headerSize(clazz); 111 | 112 | while (clazz != Object.class) { 113 | for (Field f : clazz.getDeclaredFields()) { 114 | if ((f.getModifiers() & Modifier.STATIC) == 0) { 115 | long offset = unsafe.objectFieldOffset(f); 116 | if (offset > maxSize) { 117 | // Assume 1 byte of the field width. This is ok as it 118 | // gets padded out at the end 119 | maxSize = offset + 1; 120 | } 121 | } 122 | } 123 | clazz = clazz.getSuperclass(); 124 | } 125 | 126 | // The whole class always pads to a 8 bytes boundary, so we round up to 127 | // 8 bytes. 128 | return roundUpTo8(maxSize); 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/Subpage.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | /** 3 | * 4 | *or zhangwy : 2016年12月28日 上午6:51:00 5 | **/ 6 | public class Subpage { 7 | private Chunk chunk; /*属于哪个chunk*/ 8 | private int memoryMapIdx; /*chunk中的memoryIdx*/ 9 | private long runOffset; /*地址偏移*/ 10 | private long pageSize; /*pageSize*/ 11 | private int elememtSize; /*分配的元素多大*/ 12 | 13 | Subpage next; /*前指针*/ 14 | Subpage prev;/*后指针*/ 15 | 16 | private BitSet bitMap; /*使用位图*/ 17 | private int aviableNum; /*可分配的个数*/ 18 | private int maxNum; /*最多可分配的个数*/ 19 | 20 | /*作为头指针的初始化*/ 21 | public Subpage(int size, int pageSize) { 22 | this.memoryMapIdx = -1; 23 | this.chunk = null; 24 | this.elememtSize = size; 25 | this.pageSize = pageSize; 26 | this.bitMap = null; 27 | this.prev = this; 28 | this.next = this; 29 | } 30 | /*作为chunk的初始化*/ 31 | public Subpage(Chunk chunk,int memoryMapIdx, long pageSize, int size) { 32 | this.memoryMapIdx = memoryMapIdx; 33 | this.chunk = chunk; 34 | this.pageSize = pageSize; 35 | initSubpage(size); 36 | } 37 | 38 | /** 39 | * 初始化一个subpage页面 40 | * @param size 参数 41 | */ 42 | public void initSubpage(int size) { 43 | this.elememtSize = size; 44 | if(elememtSize != 0) { 45 | maxNum = aviableNum =(int)(pageSize / elememtSize); 46 | bitMap = new BitSet(aviableNum); 47 | } 48 | addPool(); 49 | } 50 | 51 | private void addPool() { 52 | Subpage header = this.chunk.getArena().findSubpagePoolHead(elememtSize); 53 | this.next = header.next; 54 | if(header.next != null) { 55 | header.next.prev = this; 56 | } 57 | header.next = this; 58 | this.prev = header; 59 | } 60 | 61 | private void removePool() { 62 | Subpage header = this.chunk.getArena().findSubpagePoolHead(elememtSize); 63 | prev.next = next; 64 | if(next != null){ 65 | next.prev = prev; 66 | } 67 | next = null; 68 | prev = null; 69 | 70 | } 71 | /*分配一个elementSize的大小*/ 72 | public long allocate() { 73 | if(elememtSize == 0 ) toHandle(0); 74 | if(aviableNum <= 0) return -1; 75 | long bitMapId = bitMap.findFree(); 76 | long handle = toHandle(bitMapId); 77 | bitMap.set(bitMapId); 78 | aviableNum -- ; 79 | /*完全分配完了,从链表中移除*/ 80 | if(aviableNum == 0) { 81 | removePool(); 82 | } 83 | return handle; 84 | } 85 | /*返回当前的chunk是否正在使用, 86 | * true: 正在使用, 87 | * flase: 不在使用了,可以回收了*/ 88 | public boolean free(long bitMapId) { 89 | if(elememtSize == 0) return true; 90 | bitMap.free(bitMapId); 91 | /*有空闲的,加入到链表,继续分配*/ 92 | if(aviableNum ++ == 0) { 93 | addPool(); 94 | } 95 | 96 | if(aviableNum != maxNum) { 97 | return true; 98 | } else { 99 | // Subpage not in use (numAvail == maxNumElems) 100 | if (prev == next) { 101 | // Do not remove if this subpage is the only one left in the pool. 102 | return true; 103 | } 104 | //将subpage整块移除 105 | removePool(); 106 | return false; 107 | } 108 | 109 | } 110 | /**/ 111 | private long toHandle(long bitmapIdx) { 112 | return 0x4000000000000000L | (long) bitmapIdx << 32 | memoryMapIdx; 113 | } 114 | /** 115 | * @return the chunk 116 | */ 117 | public Chunk getChunk() { 118 | return chunk; 119 | } 120 | /** 121 | * @return the elememtSize 122 | */ 123 | public int getElememtSize() { 124 | return elememtSize; 125 | } 126 | 127 | @Override 128 | public String toString() { 129 | return String.valueOf('(') + memoryMapIdx + ": " + (maxNum - aviableNum) + '/' + maxNum + 130 | ", offset: " + runOffset + ", length: " + pageSize + ", elememtSize: " + elememtSize + ')'; 131 | } 132 | 133 | public static void main(String[] args) { 134 | 135 | System.out.println(Integer.toBinaryString(0xffffffff)); 136 | System.out.println(Integer.toBinaryString(0xffffffff >>>1)); 137 | System.out.println(0xffffffff); 138 | System.out.println(-1>>>1); 139 | System.out.println(-1 >>1); 140 | 141 | // int normalizedCapacity = 0x7fffffff; 142 | // normalizedCapacity --; 143 | // normalizedCapacity |= normalizedCapacity >>> 1; 144 | // System.out.println(Integer.toBinaryString(normalizedCapacity)); 145 | // normalizedCapacity |= normalizedCapacity >>> 2; 146 | // System.out.println(Integer.toBinaryString(normalizedCapacity)); 147 | // normalizedCapacity |= normalizedCapacity >>> 4; 148 | // System.out.println(Integer.toBinaryString(normalizedCapacity)); 149 | // normalizedCapacity |= normalizedCapacity >>> 8; 150 | // System.out.println(Integer.toBinaryString(normalizedCapacity)); 151 | // normalizedCapacity |= normalizedCapacity >>> 16; 152 | // System.out.println(Integer.toBinaryString(normalizedCapacity)); 153 | // normalizedCapacity ++; 154 | // System.out.println(Integer.toBinaryString(normalizedCapacity)); 155 | // if (normalizedCapacity < 0) { 156 | // normalizedCapacity >>>= 1; 157 | // } 158 | // System.out.println(normalizedCapacity); 159 | } 160 | } 161 | 162 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | io.mycat.bigmem 5 | mycat-bigmemory 6 | 0.0.1-RELEASE 7 | mycat-bigmemory 8 | https://github.com/MyCATApache/Mycat-BigMemoryAPI 9 | mycat big memory is a framework of java memory management,pure java implementation,high performance,etc.. 10 | 11 | 12 | UTF-8 13 | UTF-8 14 | 15 | 16 | 17 | 18 | 19 | junit 20 | junit 21 | 4.4 22 | test 23 | 24 | 25 | com.google.guava 26 | guava 27 | 18.0 28 | 29 | 30 | log4j 31 | log4j 32 | 1.2.17 33 | compile 34 | 35 | 36 | 37 | org.slf4j 38 | slf4j-api 39 | 1.7.12 40 | compile 41 | 42 | 43 | org.slf4j 44 | slf4j-log4j12 45 | 1.7.12 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | The Apache Software License, Version 2.0 55 | http://www.apache.org/licenses/LICENSE-2.0.txt 56 | 57 | 58 | 59 | 60 | 61 | mycat 62 | 546064298@qq.com 63 | 64 | 65 | 66 | 67 | 68 | scm:git:https://github.com/MyCATApache/Mycat-BigMemoryAPI.git 69 | scm:git:https://github.com/MyCATApache/Mycat-BigMemoryAPI.git 70 | https://github.com/MyCATApache/Mycat-BigMemoryAPI.git 71 | 72 | 73 | 74 | 75 | 76 | mycat-bigmemory 77 | 78 | 79 | src/main/resources 80 | true 81 | 82 | 83 | 84 | 85 | 86 | org.apache.maven.plugins 87 | maven-compiler-plugin 88 | 89 | 1.8 90 | 1.8 91 | 92 | 93 | 94 | 95 | 96 | org.apache.maven.plugins 97 | maven-javadoc-plugin 98 | 2.10.4 99 | 100 | UTF-8 101 | true 102 | UTF-8 103 | UTF-8 104 | 105 | 106 | 107 | attach-javadocs 108 | 109 | jar 110 | 111 | 112 | 113 | 114 | 115 | 116 | org.apache.maven.plugins 117 | maven-source-plugin 118 | 3.0.1 119 | 120 | 121 | attach-sources 122 | 123 | jar 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | release 136 | 137 | 138 | 139 | 140 | org.apache.maven.plugins 141 | maven-source-plugin 142 | 2.2.1 143 | 144 | 145 | package 146 | 147 | jar-no-fork 148 | 149 | 150 | 151 | 152 | 153 | 154 | org.apache.maven.plugins 155 | maven-gpg-plugin 156 | 157 | 158 | sign-artifacts 159 | verify 160 | 161 | sign 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | oss 171 | https://oss.sonatype.org/content/repositories/snapshots/ 172 | 173 | 174 | oss 175 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/buffer/ChunkList.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.buffer; 2 | 3 | import io.mycat.bigmem.util.StringUtil; 4 | 5 | /** 6 | * 7 | *or zhangwy : 2016年12月28日 上午6:50:37 8 | **/ 9 | public class ChunkList { 10 | private final Arena arena; 11 | private ChunkList preList; 12 | private final ChunkList nextList; 13 | 14 | private final int minUsage; 15 | private final int maxUsage; 16 | private Chunk head; 17 | 18 | /** 19 | * 初始化Chunk使用率的链表 20 | * @param arena 参数 21 | * @param nextList 参数 22 | * @param minUsage 参数 23 | * @param maxUsage 参数 24 | */ 25 | public ChunkList(Arena arena, ChunkList nextList, int minUsage, int maxUsage) { 26 | this.arena = arena; 27 | this.nextList = nextList; 28 | this.minUsage = minUsage; 29 | this.maxUsage = maxUsage; 30 | } 31 | 32 | public void setPre(ChunkList preList) { 33 | this.preList = preList; 34 | } 35 | 36 | /** 37 | * 返回当前chunk是否仍然在使用 38 | * @param chunk 参数 39 | * @param handle 参数 40 | * @return 返回 41 | */ 42 | public boolean free(Chunk chunk, long handle) { 43 | chunk.free(handle); 44 | if (chunk.usage() < minUsage) { 45 | remove(chunk); 46 | return move0(chunk); 47 | } 48 | return true; 49 | } 50 | 51 | /** 52 | * 判断之前是否还有prelist,即还未到到达q000,比q000还小即使用率为0,可以将当前chunk进行释放 53 | * @param chunk 参数 54 | * @return 55 | */ 56 | private boolean move0(Chunk chunk) { 57 | if (preList == null) { 58 | // 不插入了,直接返回 59 | return false; 60 | } 61 | return preList.move(chunk); 62 | } 63 | 64 | /** 65 | * 判断当前的chunk使用率是否小于 chunkList的最小使用率, 66 | *如果小于, 67 | * 判断前一个使用率是否存在,存在比较是否插入,不存在移除当前chunk 68 | *,如果大于, 69 | * 进行插入. 70 | * @param chunk 参数 71 | * @return 返回 72 | */ 73 | private boolean move(Chunk chunk) { 74 | if (chunk.usage() < minUsage) { 75 | return move0(chunk); 76 | } 77 | add0(chunk); 78 | return true; 79 | } 80 | 81 | /** 82 | * 分配一个normalSize的byteBuffer 83 | * @param byteBuffer 参数 84 | * @param capacity 参数 85 | * @param normalSize 参数 86 | * @return 返回 87 | */ 88 | public boolean allocate(BaseByteBuffer byteBuffer, int capacity, int normalSize) { 89 | if (head == null) 90 | return false; 91 | Chunk cur = head; 92 | while (cur != null) { 93 | long handle = cur.allocate(normalSize); 94 | if (handle > 0) { 95 | cur.initBuf(byteBuffer, handle, capacity); 96 | if (cur.usage() >= maxUsage) { 97 | remove(cur); 98 | addChunk(cur); 99 | } 100 | return true; 101 | } 102 | cur = cur.next; 103 | } 104 | return false; 105 | } 106 | 107 | /** 108 | * 分配一个normalSize的 的handle 109 | * @param capacity 参数 110 | * @param normalSize 参数 111 | * @return 返回 112 | */ 113 | public Handle allocateHandle(int capacity, int normalSize) { 114 | if (head == null) 115 | return null; 116 | Chunk cur = head; 117 | while (cur != null) { 118 | long handle = cur.allocate(normalSize); 119 | if (handle > 0) { 120 | Handle handleObj = new Handle(handle, cur, normalSize); 121 | if (cur.usage() >= maxUsage) { 122 | remove(cur); 123 | addChunk(cur); 124 | } 125 | return handleObj; 126 | } 127 | cur = cur.next; 128 | } 129 | return null; 130 | } 131 | 132 | /** 133 | * 链表添加一个chunk,主要跟maxUsage进行比较 134 | * @param cur 参数 135 | */ 136 | public void addChunk(Chunk cur) { 137 | if (cur.usage() >= maxUsage) { 138 | nextList.addChunk(cur); 139 | return; 140 | } 141 | add0(cur); 142 | } 143 | 144 | /** 145 | * 将chunk加入当前使用率的链表中。 146 | * @param cur 参数 147 | */ 148 | private void add0(Chunk cur) { 149 | cur.parent = this; 150 | if (head == null) { 151 | head = cur; 152 | cur.next = null; 153 | cur.prev = null; 154 | } else { 155 | cur.next = head; 156 | head.prev = cur; 157 | cur.prev = null; 158 | head = cur; 159 | } 160 | } 161 | 162 | /** 163 | * 将chunk从链表中移除 164 | * @param cur 参数 165 | */ 166 | private void remove(Chunk cur) { 167 | if (head == cur) { 168 | head = cur.next; 169 | if (head != null) { 170 | // 将头指针.prev 向null 171 | head.prev = null; 172 | } 173 | } else { 174 | Chunk next = cur.next; 175 | cur.prev.next = next; 176 | if (next != null) { 177 | next.prev = cur.prev; 178 | } 179 | } 180 | } 181 | 182 | /* 183 | * (non-Javadoc) 184 | * 185 | * @see java.lang.Object#toString() 186 | */ 187 | @Override 188 | public String toString() { 189 | StringBuilder sb = new StringBuilder(""); 190 | Chunk next = head; 191 | while (next != null) { 192 | sb.append(next); 193 | sb.append(StringUtil.NEWLINE); 194 | next = next.next; 195 | } 196 | 197 | return sb.toString(); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/CacheImp.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.*; 8 | import java.util.concurrent.*; 9 | import java.util.concurrent.locks.Lock; 10 | import java.util.concurrent.locks.ReadWriteLock; 11 | import java.util.concurrent.locks.ReentrantReadWriteLock; 12 | 13 | 14 | /** 15 | * ICache实现类 16 | * 17 | * or zagnix 18 | * @version 1.0 19 | * 2016-12-30 16:53 20 | */ 21 | 22 | public class CacheImp implements ICache { 23 | 24 | private final static Logger logger 25 | = LoggerFactory.getLogger(CacheImp.class); 26 | 27 | public static final long DEFAULT_TTL = 5 * 1000; 28 | public static final int ACCESS_COUNT = 500; 29 | private static final int REMOVE_ACTION = 1; 30 | private static final int RELOAD_ACTION = 2; 31 | 32 | private final Map cacheMap; 33 | private final Map> cacheKeyers; 34 | 35 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); 36 | private final Lock readLock = lock.readLock(); 37 | private final Lock writeLock = lock.writeLock(); 38 | 39 | 40 | /** 41 | * 异步线程,按照cache规则生效 42 | * 1.缓存时间到期,进行del 43 | * 2.如果在缓存时间内,访问次数超过N次,重新从DB后台load数据,更新Value 44 | */ 45 | private static final ThreadFactory threadFactory = 46 | new ThreadFactoryBuilder().setDaemon(true).setNameFormat("async-op-cache ").build(); 47 | private static final ScheduledExecutorService scheduleAtFixedRate = 48 | new ScheduledThreadPoolExecutor(1,threadFactory); 49 | private final Set> keysToDel = new HashSet>(); 50 | private final Set> keysToReload= new HashSet>(); 51 | 52 | 53 | public CacheImp(){ 54 | cacheMap = new ConcurrentHashMap(); 55 | cacheKeyers = new ConcurrentHashMap>(); 56 | 57 | scheduleAtFixedRate.scheduleAtFixedRate(new Runnable() { 58 | @Override 59 | public void run() { 60 | keysToDel.clear(); 61 | Set keySets = cacheKeyers.keySet(); 62 | 63 | long currentTime = System.currentTimeMillis(); 64 | for (K key:keySets) { 65 | Keyer k = cacheKeyers.get(key); 66 | long diff = currentTime-k.getLastAccessTime(); 67 | if (diff>k.getCacheTTL()){ 68 | keysToDel.add(k); 69 | }else if (diff<=k.getCacheTTL() && k.getRefCount().get()>=k.getAccessCount()){ 70 | keysToReload.add(k); 71 | } 72 | } 73 | 74 | /** 75 | * key 失效,回调remove接口 76 | */ 77 | for (Keyer key:keysToDel) { 78 | cacheMap.remove(key.getKey()); 79 | if(key.getRemoveKeyListener() !=null){ 80 | key.getRemoveKeyListener().removeNotify(key.getKey(),key.getValue()); 81 | } 82 | cacheKeyers.remove(key.getKey()); 83 | } 84 | 85 | 86 | /** 87 | * 回调用户reload接口 88 | */ 89 | for (Keyer key:keysToReload) { 90 | /** 91 | * reload 设计为异步加载 92 | */ 93 | if(key.getiDataLoader() !=null){ 94 | key.getiDataLoader().reload(key); 95 | } 96 | } 97 | } 98 | },0,DEFAULT_TTL, TimeUnit.MILLISECONDS); 99 | } 100 | 101 | /** 102 | * put (k,v) to map 103 | * 104 | * @param key 参数 105 | * @param value 参数 106 | * @param keyer 参数 107 | */ 108 | @Override 109 | public void put(K key, V value,Keyer keyer) { 110 | cacheMap.put(key,value); 111 | cacheKeyers.put(key,keyer); 112 | } 113 | 114 | /** 115 | * get value 116 | * 117 | * @param key 参数 118 | * @return 返回 119 | */ 120 | @Override 121 | public V get(K key) { 122 | 123 | try { 124 | readLock.lock(); 125 | Keyer keyer = cacheKeyers.get(key); 126 | 127 | if (keyer != null){ 128 | keyer.setLastAccessTime(System.currentTimeMillis()); 129 | keyer.getRefCount().decrementAndGet(); 130 | } 131 | 132 | return cacheMap.get(key); 133 | 134 | }finally { 135 | readLock.unlock(); 136 | } 137 | 138 | 139 | } 140 | 141 | /** 142 | * remove key 143 | * 144 | * @param key 参数 145 | */ 146 | @Override 147 | public void remove(K key) { 148 | Keyer keyer = cacheKeyers.get(key); 149 | 150 | if (keyer.getRemoveKeyListener()!=null){ 151 | keyer.getRemoveKeyListener(). 152 | removeNotify(keyer.getKey(),keyer.getValue()); 153 | } 154 | cacheKeyers.remove(key); 155 | cacheMap.remove(key); 156 | } 157 | 158 | 159 | /** 160 | * remove all map's element 161 | */ 162 | @Override 163 | public void removeALL() { 164 | for (K key:cacheKeyers.keySet()) { 165 | Keyer keyer = cacheKeyers.get(key); 166 | if (keyer.getRemoveKeyListener()!=null){ 167 | keyer.getRemoveKeyListener().removeNotify(keyer.getKey(),keyer.getValue()); 168 | } 169 | } 170 | cacheKeyers.clear(); 171 | cacheMap.clear(); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/impl/mmap/MappedMemFileBufferPage.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache.impl.mmap; 2 | 3 | import io.mycat.bigmem.sqlcache.MyCatBufferPage; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.IOException; 8 | import java.lang.reflect.Method; 9 | import java.nio.ByteBuffer; 10 | import java.nio.MappedByteBuffer; 11 | import java.security.AccessController; 12 | import java.security.PrivilegedAction; 13 | 14 | /** 15 | * 内存映射文件实现data存储 16 | * 17 | * or zagnix 18 | * @version 1.0 19 | * 2016-12-27 18:52 20 | */ 21 | 22 | public class MappedMemFileBufferPage extends MyCatBufferPage { 23 | private final static Logger logger = 24 | LoggerFactory.getLogger(MappedMemFileBufferPage.class); 25 | private String pageName = null; 26 | private long pageIndex = 0L; 27 | private static Method mappedByteBufferCleaner = null; 28 | private static Method mappedByteBufferCleanerClean = null; 29 | 30 | static { 31 | try { 32 | mappedByteBufferCleaner = 33 | Class.forName("java.nio.DirectByteBuffer").getMethod("cleaner"); 34 | mappedByteBufferCleaner.setAccessible(true); 35 | mappedByteBufferCleanerClean = 36 | Class.forName("sun.misc.Cleaner").getMethod("clean"); 37 | mappedByteBufferCleanerClean.setAccessible(true); 38 | } catch (NoSuchMethodException e) { 39 | e.printStackTrace(); 40 | } catch (ClassNotFoundException e) { 41 | e.printStackTrace(); 42 | } 43 | } 44 | 45 | 46 | /** 47 | * 创建 一个MappedByteBufferPage对象 48 | * 49 | * @param mappedByteBuffer 参数 50 | * @param file 参数 51 | * @param index 参数 52 | * @param cacheTTL 参数 53 | */ 54 | public MappedMemFileBufferPage(MappedByteBuffer mappedByteBuffer, String file, long index, long cacheTTL){ 55 | super(mappedByteBuffer.load(),cacheTTL); 56 | this.pageName = file; 57 | this.pageIndex = index; 58 | } 59 | 60 | 61 | /** 62 | * 63 | * @param position 参数 64 | * @param length 参数 65 | * @return 参数 66 | */ 67 | public byte[] getBytes(int position, int length) { 68 | ByteBuffer buf = this.getLocalByteBuffer(position); 69 | byte[] data = new byte[length]; 70 | buf.get(data); 71 | return data; 72 | } 73 | 74 | /** 75 | * ByteBuffer slice from Thread Local 参数 76 | * @param position 参数 77 | * @param limit 参数 78 | * @return 参数 79 | */ 80 | public ByteBuffer slice(int position, int limit) { 81 | ByteBuffer buffer = this.threadLocalByteBuffer.get(); 82 | buffer.limit(position+limit); 83 | buffer.position(position); 84 | return buffer.slice(); 85 | } 86 | 87 | /** 88 | * ByteBuffer from Thread Local 89 | * 90 | * @param position 参数 91 | * @return 参数 92 | */ 93 | public ByteBuffer getLocalByteBuffer(int position) { 94 | ByteBuffer buf = this.threadLocalByteBuffer.get(); 95 | buf.position(position); 96 | return buf; 97 | } 98 | 99 | 100 | /** 101 | * 将pageName的数据刷入磁盘 102 | */ 103 | public void flush() { 104 | synchronized(this) { 105 | if (this.recycled) return; 106 | if (dirty) { 107 | MappedByteBuffer mappedByteBuffer = 108 | (MappedByteBuffer)threadLocalByteBuffer.getByteBuffer(); 109 | mappedByteBuffer.force(); 110 | dirty = false; 111 | } 112 | } 113 | 114 | } 115 | 116 | /** 117 | * 返回 页 号 118 | * @return 参数 119 | */ 120 | public long getPageIndex() { 121 | return this.pageIndex; 122 | } 123 | 124 | /** 125 | * 设置 页 为 dirty 126 | * @param dirty 参数 127 | */ 128 | public void setDirty(boolean dirty) { 129 | this.dirty = dirty; 130 | } 131 | 132 | /** 133 | * 回收页,关闭文件pageName 134 | * @throws IOException 参数 135 | */ 136 | public void recycle() throws IOException{ 137 | 138 | synchronized(this) { 139 | if (this.recycled) return; 140 | flush(); 141 | MappedByteBuffer srcBuf = 142 | (MappedByteBuffer)threadLocalByteBuffer.getByteBuffer(); 143 | unmap(srcBuf); 144 | this.threadLocalByteBuffer = null; 145 | this.recycled = true; 146 | } 147 | 148 | } 149 | 150 | /** 151 | * 解文件内存映射 152 | * 153 | * @param buffer 参数 154 | */ 155 | private void unmap(final MappedByteBuffer buffer) { 156 | if(buffer == null) 157 | return; 158 | 159 | AccessController.doPrivileged(new PrivilegedAction() { 160 | public Object run() { 161 | try { 162 | if (mappedByteBufferCleaner != null && 163 | mappedByteBufferCleanerClean != null && 164 | buffer.isDirect()) { 165 | Object cleaner = mappedByteBufferCleaner.invoke(buffer); 166 | mappedByteBufferCleanerClean.invoke(cleaner); 167 | } 168 | } catch (Exception e) { 169 | logger.error(e.getMessage()); 170 | } 171 | return null; 172 | } 173 | }); 174 | } 175 | 176 | 177 | public boolean isRecycled() { 178 | return false; 179 | } 180 | 181 | public String getPageName() { 182 | return pageName; 183 | } 184 | 185 | public void setPageName(String pageName) { 186 | this.pageName = pageName; 187 | } 188 | 189 | public void setPageIndex(long pageIndex) { 190 | this.pageIndex = pageIndex; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /doc/BigResultCache.uml: -------------------------------------------------------------------------------- 1 | 2 | 3 | JAVA 4 | 5 | 6 | io.mycat.bigmem.sqlcache.impl.directmem.DirectMemorySQLResult 7 | io.mycat.bigmem.sqlcache.PageLRUCache 8 | io.mycat.bigmem.sqlcache.ISQLResult 9 | io.mycat.bigmem.sqlcache.IBufferPageFactory 10 | io.mycat.bigmem.sqlcache.MyCatBufferPage 11 | io.mycat.bigmem.sqlcache.impl.directmem.DirectMemoryFactory 12 | io.mycat.bigmem.sqlcache.impl.mmap.MappedSQLResult 13 | io.mycat.bigmem.sqlcache.IBufferPage 14 | io.mycat.bigmem.sqlcache.impl.mmap.MappedMemFileBufferPage 15 | io.mycat.bigmem.sqlcache.BigSQLResult 16 | io.mycat.bigmem.sqlcache.impl.mmap.MappedBufferPageFactory 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | io.mycat.bigmem.sqlcache.impl.directmem.DirectMemorySQLResult 94 | io.mycat.bigmem.sqlcache.PageLRUCache 95 | io.mycat.bigmem.sqlcache.ISQLResult 96 | io.mycat.bigmem.sqlcache.IBufferPageFactory 97 | io.mycat.bigmem.sqlcache.MyCatBufferPage 98 | io.mycat.bigmem.sqlcache.impl.directmem.DirectMemoryFactory 99 | io.mycat.bigmem.sqlcache.impl.mmap.MappedSQLResult 100 | io.mycat.bigmem.sqlcache.IBufferPage 101 | io.mycat.bigmem.sqlcache.impl.mmap.MappedBufferPageFactory 102 | io.mycat.bigmem.sqlcache.impl.mmap.MappedMemFileBufferPage 103 | io.mycat.bigmem.sqlcache.BigSQLResult 104 | 105 | 106 | Methods 107 | 108 | All 109 | private 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/bufferpage/impl/DirectBufferPage.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.bufferpage.impl; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageBase; 5 | 6 | /** 7 | * 缓冲内存页的数据 8 | * 源文件名:BufferPage.java 9 | * 文件版本:1.0.0 10 | * 创建作者:liujun 11 | * 创建日期:2016年12月27日 12 | * 修改作者:liujun 13 | * 修改日期:2016年12月27日 14 | * 文件描述:TODO 15 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 16 | */ 17 | public class DirectBufferPage extends BufferPageBase { 18 | 19 | /** 20 | * 构造方法 21 | * @param buffer 参数 22 | * @param chunkSize 参数 23 | */ 24 | public DirectBufferPage(MycatBufferBase buffer, int chunkSize) { 25 | // 进行父类的引用 26 | super(buffer, chunkSize); 27 | } 28 | 29 | /** 30 | * 检查当前内存页能否满足内存数据的分配要求 31 | * 方法描述 32 | * @param chunkNum 参数 33 | * @return 1,可分配 0,不能 34 | * 2016年12月19日 35 | */ 36 | public boolean checkNeedChunk(int chunkNum) { 37 | // 仅在未锁定的情况下,才进行检查 38 | if (!isLock.get()) { 39 | // 如果当前可分配的内存块满足要求 40 | if (this.canUseChunkNum >= chunkNum) { 41 | return true; 42 | } 43 | } 44 | return false; 45 | } 46 | 47 | /** 48 | * 获得chunk的buffer信息 49 | * 方法描述 50 | * @param needChunkSize 参数 51 | * @return 返回 52 | * 2016年12月19日 53 | */ 54 | public MycatBufferBase alloactionMemory(int needChunkSize) { 55 | // 如果当前的可分配的内在块小于需要内存块,则返回 56 | if (canUseChunkNum < needChunkSize) { 57 | return null; 58 | } 59 | 60 | // 如果当前不能加锁成功,则返回为null 61 | if (!isLock.compareAndSet(false, true)) { 62 | return null; 63 | } 64 | 65 | try { 66 | 67 | int startIndex = -1; 68 | int endIndex = 0; 69 | // 找到当前连续未使用的内存块 70 | for (int i = 0; i < chunkCount; i++) { 71 | if (memUseSet.get(i) == false) { 72 | if (startIndex == -1) { 73 | startIndex = i; 74 | endIndex = 1; 75 | // 只需要1时,进不需再进行遍历 76 | if (needChunkSize == 1) { 77 | break; 78 | } 79 | } else { 80 | if (++endIndex == needChunkSize) { 81 | break; 82 | } 83 | } 84 | } 85 | // 如果已经使用,则标识当前已经使用,则从已经使用的位置开始 86 | else { 87 | startIndex = -1; 88 | endIndex = 0; 89 | } 90 | } 91 | 92 | // 如果找到适合的内存块大小 93 | if (endIndex == needChunkSize) { 94 | // 将这一批数据标识为已经使用 95 | int needChunkEnd = startIndex + needChunkSize; 96 | memUseSet.set(startIndex, needChunkEnd); 97 | 98 | // 标识开始与结束号 99 | buffer.putPosition(startIndex * chunkSize); 100 | buffer.limit(needChunkEnd * chunkSize); 101 | 102 | // 进行数据进行匹配分段操作 103 | MycatBufferBase bufferResult = buffer.slice(); 104 | 105 | // 当前可使用的,为之前的结果前去当前的需要的, 106 | canUseChunkNum = canUseChunkNum - needChunkSize; 107 | 108 | return bufferResult; 109 | 110 | } else { 111 | return null; 112 | } 113 | 114 | } finally { 115 | isLock.set(false); 116 | } 117 | } 118 | 119 | /** 120 | * 进行内存的归还操作,以便后面再使用 121 | * 方法描述 122 | * @param parentBuffer 参数 123 | * @param chunkStart 参数 124 | * @param chunkNum 参数 125 | * @return 返回 126 | * 2016年12月19日 127 | */ 128 | public boolean recycleBuffer(MycatBufferBase parentBuffer, int chunkStart, int chunkNum) { 129 | if (this.buffer == parentBuffer) { 130 | // 如果加锁失败,则执行其他代码 131 | if (!isLock.compareAndSet(false, true)) { 132 | Thread.yield(); 133 | } 134 | 135 | try { 136 | int endChunkNum = chunkStart + chunkNum; 137 | // 将当前指定的内存块归还 138 | memUseSet.clear(chunkStart, endChunkNum); 139 | 140 | // 引用对象的容量进行重新标识 141 | parentBuffer.capacity(parentBuffer.limit()); 142 | 143 | // 归还了内存,则需要将可使用的内存加上归还的内存 144 | this.canUseChunkNum = canUseChunkNum + chunkNum; 145 | 146 | } finally { 147 | isLock.set(false); 148 | } 149 | 150 | return true; 151 | 152 | } 153 | 154 | return false; 155 | } 156 | 157 | // public static void main(String[] args) { 158 | // MycatMovableBufer buffer = new DirectMycatBufferImpl(2048); 159 | // 160 | // UnsafeDirectBufferPage page = new UnsafeDirectBufferPage(buffer, 256); 161 | // 162 | // buffer.beginOp(); 163 | // 164 | // MycatBuffer buffer1 = page.alloactionMemory(4); 165 | // MycatBuffer buffer2 = page.alloactionMemory(4); 166 | // 167 | // buffer.commitOp(); 168 | // // // 获得内存buffer 169 | // // sun.nio.ch.DirectBuffer thisNavBuf = (sun.nio.ch.DirectBuffer) 170 | // // bufferItem2; 171 | // // // attachment对象在buf.slice();的时候将attachment对象设置为总的buff对象 172 | // // sun.nio.ch.DirectBuffer parentBuf = (sun.nio.ch.DirectBuffer) 173 | // // thisNavBuf.attachment(); 174 | // // // 175 | // // 已经使用的地址减去父类最开始的地址,即为所有已经使用的地址,除以chunkSize得到chunk当前开始的地址,得到整块内存开始的地址 176 | // // int startChunk = (int) ((page - parentBuf.address()) / 256); 177 | // // 178 | // // // 归还当前buffer2的内存 179 | // // page.recycleBuffer(parentBuf, startChunk, 2); 180 | // // 181 | // // System.out.println(bufferItem); 182 | // // System.out.println(bufferItem2); 183 | // // System.out.println(bufferItem3); 184 | // 185 | // } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/mempool/PoolBuddyChunk.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.mempool; 2 | 3 | /** 4 | * 伙伴算法实现,最小分配单元是页, 5 | * 可以连续分配多个页,回收时候可以合并多个页 6 | * Created by znix on 2017/1/4. 7 | */ 8 | public class PoolBuddyChunk { 9 | 10 | private T memory; 11 | private final int chunkSize; 12 | private final int maxOrder; 13 | private final int pageSize; 14 | private final int pageShifts; 15 | private final int log2ChunkSize; 16 | 17 | private final int maxSubpageAllocs; 18 | private final byte[] memoryMap; 19 | private final byte[] depthMap; 20 | 21 | /** Used to mark memory as unusable */ 22 | private final byte unusable; 23 | 24 | private int freeBytes; 25 | 26 | private final int subpageOverflowMask; 27 | 28 | 29 | public PoolBuddyChunk(final int chunkSize,final int maxOrder,final int pageSize){ 30 | this.chunkSize = chunkSize; 31 | this.maxOrder = maxOrder; 32 | this.pageSize = pageSize; 33 | this.pageShifts = log2(pageSize); 34 | this.log2ChunkSize = log2(chunkSize); 35 | this.maxSubpageAllocs = 1 << maxOrder; 36 | this.unusable = (byte) (maxOrder+1); 37 | this.memoryMap = new byte[maxSubpageAllocs]; 38 | this.depthMap = new byte[maxSubpageAllocs]; 39 | this.freeBytes = chunkSize; 40 | this.subpageOverflowMask = ~(pageSize-1); 41 | 42 | int memoryMapIndex = 1; 43 | for (int d = 0; d <=maxOrder ; ++d) { 44 | int depth = 1 << d; 45 | for (int i = 0; i < depth; i++) { 46 | memoryMap[memoryMapIndex] = (byte)d; 47 | depthMap[memoryMapIndex] = (byte)d; 48 | memoryMapIndex++; 49 | } 50 | } 51 | } 52 | 53 | 54 | long allocate(int remCapacity){ 55 | 56 | if ((remCapacity&subpageOverflowMask)!=0){ 57 | return allocateRun(remCapacity); 58 | } 59 | 60 | return -1L; 61 | } 62 | 63 | /** 64 | * 分配内存remCapacity大小,remCapacity满足pageSize的倍数 65 | * 66 | * @param remCapacity 67 | * @return 68 | */ 69 | long allocateRun(int remCapacity){ 70 | /** 71 | * 平衡二叉树深度为d满足请求remCapacity大小内存, 72 | */ 73 | int d = maxOrder - (log2(remCapacity) - pageShifts); 74 | 75 | int id = allocateNode(d); 76 | 77 | if(id < 0){ 78 | return -1; 79 | } 80 | freeBytes -= runLength(id); 81 | return id; 82 | } 83 | 84 | /** 85 | * 通过 handle free分配的内存 86 | * @param handle 87 | */ 88 | private void free(long handle){ 89 | int memoryMapIdx = (int) handle; 90 | freeBytes += runLength(memoryMapIdx); 91 | setValue(memoryMapIdx, depth(memoryMapIdx)); 92 | updateParentsFree(memoryMapIdx); 93 | } 94 | 95 | /** 96 | * 递归更新其父节点id对应memoryMap数组下标的值 97 | * @param id 98 | */ 99 | private void updateParentsFree(int id) { 100 | int logChild = depth(id) + 1; 101 | while (id > 1) { 102 | int parentId = id >>> 1; 103 | byte val1 = value(id); 104 | byte val2 = value(id ^ 1); 105 | logChild -= 1; // in first iteration equals log, subsequently reduce 1 from logChild as we traverse up 106 | 107 | if (val1 == logChild && val2 == logChild) { 108 | setValue(parentId, (byte) (logChild - 1)); 109 | } else { 110 | byte val = val1 < val2 ? val1 : val2; 111 | setValue(parentId, val); 112 | } 113 | 114 | id = parentId; 115 | } 116 | } 117 | 118 | /** 119 | * 计算下标id的根节点下,内存大小 120 | * 可能包含连续多个页。 121 | * @param id 122 | * @return 123 | */ 124 | private int runLength(int id) { 125 | return 1 <<(log2ChunkSize - depth(id)); 126 | } 127 | 128 | 129 | /** 130 | * 根据id,返回depthMap数组对应的值 131 | * @param id 132 | * @return 133 | */ 134 | private byte depth(int id) { 135 | return depthMap[id]; 136 | } 137 | 138 | /** 139 | * 计算val的log2的值 140 | * @param val 141 | * @return 142 | */ 143 | private static int log2(int val) { 144 | return Integer.SIZE - 1 - Integer.numberOfLeadingZeros(val); 145 | } 146 | 147 | /** 148 | * 返回数组memoryMap下标id,对应的值 149 | * @param id 150 | * @return 151 | */ 152 | private byte value(int id) { 153 | return memoryMap[id]; 154 | } 155 | 156 | /** 157 | * 从平衡二叉树深度d开始,找到满足要求的树节点(子节点或者叶子节点) 158 | * @param d 159 | * @return 160 | */ 161 | private int allocateNode(int d){ 162 | int id = 1; 163 | byte val = value(id); 164 | 165 | int initval= -(1 << d); 166 | 167 | /** 168 | * 说明chunk已经分配完成,无法继续分配了。 169 | */ 170 | if (val > d){ 171 | return -1; 172 | } 173 | 174 | 175 | while (val < d || (id & initval) ==0){ 176 | id <<= 1; 177 | val = value(id); 178 | 179 | if (val > d){ 180 | /** 181 | * 右子节点 182 | */ 183 | id ^=1; 184 | val = value(id); 185 | } 186 | } 187 | byte value = value(id); 188 | setValue(id,unusable); 189 | updateParentsAlloc(id); 190 | return id; 191 | } 192 | 193 | 194 | /** 195 | * 节点id,递归更新父节点memoryMap的值 196 | * @param id 197 | */ 198 | private void updateParentsAlloc(int id) { 199 | while (id > 1) { 200 | int parentId = id >>> 1; 201 | byte val1 = value(id); 202 | byte val2 = value(id ^ 1); 203 | byte val = val1 < val2 ? val1 : val2; 204 | setValue(parentId, val); 205 | id = parentId; 206 | } 207 | } 208 | 209 | /** 210 | * 设置memoryMap数组下标id的对应值为val 211 | * 212 | * @param id 213 | * @param val 214 | */ 215 | private void setValue(int id, byte val) { 216 | memoryMap[id] = val; 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/util/ByteUtil.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.util; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.ByteOrder; 5 | 6 | import sun.misc.Unsafe; 7 | 8 | public class ByteUtil { 9 | //public static Unsafe UnsafeUtil = getUnsafe(); 10 | 11 | public static boolean UNALIGNED = UnsafeUtil.getUnaligned(); 12 | private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; 13 | private static Unsafe UNSAFE = UnsafeUtil.getUnsafe(); 14 | 15 | 16 | public static void main(String[] args) { 17 | 18 | } 19 | 20 | public static byte getByte(long address) { 21 | return UNSAFE.getByte(address); 22 | } 23 | 24 | public static char makeChar(byte b1, byte b0) { 25 | return (char)((b1 << 8) | (b0 & 0xff)); 26 | } 27 | 28 | public static short getShort(long address) { 29 | if (UNALIGNED) { 30 | return UNSAFE.getShort(address); 31 | } else if (BIG_ENDIAN) { 32 | return (short) (getByte(address) << 8 | getByte(address + 1) & 0xff); 33 | } else { 34 | return (short) (getByte(address + 1) << 8 | getByte(address) & 0xff); 35 | } 36 | } 37 | 38 | public static int getInt(long address) { 39 | if (UNALIGNED) { 40 | return UNSAFE.getInt(address); 41 | } else if (BIG_ENDIAN) { 42 | return getByte(address) << 24 | 43 | (getByte(address + 1) & 0xff) << 16 | 44 | (getByte(address + 2) & 0xff) << 8 | 45 | getByte(address + 3) & 0xff; 46 | } else { 47 | return getByte(address + 3) << 24 | 48 | (getByte(address + 2) & 0xff) << 16 | 49 | (getByte(address + 1) & 0xff) << 8 | 50 | getByte(address) & 0xff; 51 | } 52 | } 53 | 54 | public static long getLong(long address) { 55 | if (UNALIGNED) { 56 | return UNSAFE.getLong(address); 57 | } else if (BIG_ENDIAN) { 58 | return (long) getByte(address) << 56 | 59 | ((long) getByte(address + 1) & 0xff) << 48 | 60 | ((long) getByte(address + 2) & 0xff) << 40 | 61 | ((long) getByte(address + 3) & 0xff) << 32 | 62 | ((long) getByte(address + 4) & 0xff) << 24 | 63 | ((long) getByte(address + 5) & 0xff) << 16 | 64 | ((long) getByte(address + 6) & 0xff) << 8 | 65 | (long) getByte(address + 7) & 0xff; 66 | } else { 67 | return (long) getByte(address + 7) << 56 | 68 | ((long) getByte(address + 6) & 0xff) << 48 | 69 | ((long) getByte(address + 5) & 0xff) << 40 | 70 | ((long) getByte(address + 4) & 0xff) << 32 | 71 | ((long) getByte(address + 3) & 0xff) << 24 | 72 | ((long) getByte(address + 2) & 0xff) << 16 | 73 | ((long) getByte(address + 1) & 0xff) << 8 | 74 | (long) getByte(address) & 0xff; 75 | } 76 | } 77 | 78 | public static void putOrderedObject(Object object, long address, Object value) { 79 | UNSAFE.putOrderedObject(object, address, value); 80 | } 81 | 82 | public static void putByte(long address, byte value) { 83 | UNSAFE.putByte(address, value); 84 | } 85 | 86 | public static void putShort(long address, short value) { 87 | if (UNALIGNED) { 88 | UNSAFE.putShort(address, value); 89 | } else if (BIG_ENDIAN) { 90 | putByte(address, (byte) (value >>> 8)); 91 | putByte(address + 1, (byte) value); 92 | } else { 93 | putByte(address + 1, (byte) (value >>> 8)); 94 | putByte(address, (byte) value); 95 | } 96 | } 97 | 98 | public static void putInt(long address, int value) { 99 | if (UNALIGNED) { 100 | UNSAFE.putInt(address, value); 101 | } else if (BIG_ENDIAN) { 102 | putByte(address, (byte) (value >>> 24)); 103 | putByte(address + 1, (byte) (value >>> 16)); 104 | putByte(address + 2, (byte) (value >>> 8)); 105 | putByte(address + 3, (byte) value); 106 | } else { 107 | putByte(address + 3, (byte) (value >>> 24)); 108 | putByte(address + 2, (byte) (value >>> 16)); 109 | putByte(address + 1, (byte) (value >>> 8)); 110 | putByte(address, (byte) value); 111 | } 112 | } 113 | 114 | public static void putLong(long address, long value) { 115 | if (UNALIGNED) { 116 | UNSAFE.putLong(address, value); 117 | } else if (BIG_ENDIAN) { 118 | putByte(address, (byte) (value >>> 56)); 119 | putByte(address + 1, (byte) (value >>> 48)); 120 | putByte(address + 2, (byte) (value >>> 40)); 121 | putByte(address + 3, (byte) (value >>> 32)); 122 | putByte(address + 4, (byte) (value >>> 24)); 123 | putByte(address + 5, (byte) (value >>> 16)); 124 | putByte(address + 6, (byte) (value >>> 8)); 125 | putByte(address + 7, (byte) value); 126 | } else { 127 | putByte(address + 7, (byte) (value >>> 56)); 128 | putByte(address + 6, (byte) (value >>> 48)); 129 | putByte(address + 5, (byte) (value >>> 40)); 130 | putByte(address + 4, (byte) (value >>> 32)); 131 | putByte(address + 3, (byte) (value >>> 24)); 132 | putByte(address + 2, (byte) (value >>> 16)); 133 | putByte(address + 1, (byte) (value >>> 8)); 134 | putByte(address, (byte) value); 135 | } 136 | } 137 | 138 | public static void copyMemory(long srcAddress, long destAddress, long bytes) { 139 | UnsafeUtil.copyMemory(srcAddress, destAddress, bytes); 140 | 141 | } 142 | 143 | public static int addressSize() { 144 | return UNSAFE.addressSize(); 145 | } 146 | 147 | public static long allocateMemory(long size) { 148 | return UNSAFE.allocateMemory(size); 149 | } 150 | 151 | public static void freeMemory(long address) { 152 | UNSAFE.freeMemory(address); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/bufferpage/impl/FileMapBufferPage.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.bufferpage.impl; 2 | 3 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 4 | import io.mycat.bigmem.chunkpageallot.buffer.MycatMovableBufer; 5 | import io.mycat.bigmem.chunkpageallot.bufferpage.BufferPageBase; 6 | 7 | /** 8 | * 缓冲内存页的数据 9 | * 源文件名:BufferPage.java 10 | * 文件版本:1.0.0 11 | * 创建作者:liujun 12 | * 创建日期:2016年12月27日 13 | * 修改作者:liujun 14 | * 修改日期:2016年12月27日 15 | * 文件描述:TODO 16 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 17 | */ 18 | public class FileMapBufferPage extends BufferPageBase { 19 | 20 | /** 21 | * 构造方法 22 | * @param buffer 参数 23 | * @param chunkSize 参数 24 | */ 25 | public FileMapBufferPage(MycatBufferBase buffer, int chunkSize) { 26 | // 进行父类的引用 27 | super(buffer, chunkSize); 28 | } 29 | 30 | /** 31 | * 检查当前内存页能否满足内存数据的分配要求 32 | * 方法描述 33 | * @param chunkNum 参数 34 | * @return 1,可分配 0,不能 35 | * 2016年12月19日 36 | */ 37 | public boolean checkNeedChunk(int chunkNum) { 38 | // 仅在未锁定的情况下,才进行检查 39 | if (!isLock.get()) { 40 | // 如果当前可分配的内存块满足要求 41 | if (this.canUseChunkNum >= chunkNum) { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | /** 49 | * 获得chunk的buffer信息 50 | * 方法描述 51 | * @param needChunkSize 参数 52 | * @return 53 | * 2016年12月19日 54 | */ 55 | public MycatBufferBase alloactionMemory(int needChunkSize) { 56 | // 如果当前的可分配的内在块小于需要内存块,则返回 57 | if (canUseChunkNum < needChunkSize) { 58 | return null; 59 | } 60 | 61 | // 如果当前不能加锁成功,则返回为null 62 | if (!isLock.compareAndSet(false, true)) { 63 | return null; 64 | } 65 | 66 | try { 67 | 68 | int startIndex = -1; 69 | int endIndex = 0; 70 | // 找到当前连续未使用的内存块 71 | for (int i = 0; i < chunkCount; i++) { 72 | if (memUseSet.get(i) == false) { 73 | if (startIndex == -1) { 74 | startIndex = i; 75 | endIndex = 1; 76 | // 只需要1时,进不需再进行遍历 77 | if (needChunkSize == 1) { 78 | break; 79 | } 80 | } else { 81 | if (++endIndex == needChunkSize) { 82 | break; 83 | } 84 | } 85 | } 86 | // 如果已经使用,则标识当前已经使用,则从已经使用的位置开始 87 | else { 88 | startIndex = -1; 89 | endIndex = 0; 90 | } 91 | } 92 | 93 | // 如果找到适合的内存块大小 94 | if (endIndex == needChunkSize) { 95 | // 将这一批数据标识为已经使用 96 | int needChunkEnd = startIndex + needChunkSize; 97 | memUseSet.set(startIndex, needChunkEnd); 98 | 99 | MycatMovableBufer moveBuffer = null; 100 | 101 | // 检查当前对象是否实现了可移动接口 102 | if (buffer instanceof MycatMovableBufer) { 103 | moveBuffer = (MycatMovableBufer) buffer; 104 | 105 | // 标识为不可移动 106 | try { 107 | moveBuffer.beginOp(); 108 | 109 | // 标识开始与结束号 110 | buffer.putPosition(startIndex * chunkSize); 111 | buffer.limit(needChunkEnd * chunkSize); 112 | 113 | // 进行数据进行匹配分段操作 114 | MycatBufferBase bufferResult = buffer.slice(); 115 | 116 | // 当前可使用的,为之前的结果前去当前的需要的, 117 | canUseChunkNum = canUseChunkNum - needChunkSize; 118 | 119 | return bufferResult; 120 | } catch (InterruptedException e) { 121 | // TODO Auto-generated catch block 122 | e.printStackTrace(); 123 | } finally { 124 | // 标识当前操作完成 125 | moveBuffer.commitOp(); 126 | } 127 | } 128 | 129 | } else { 130 | return null; 131 | } 132 | 133 | } finally { 134 | isLock.set(false); 135 | } 136 | 137 | return null; 138 | } 139 | 140 | /** 141 | * 进行内存的归还操作,以便后面再使用 142 | * 方法描述 143 | * @param parentBuffer 参数 144 | * @param chunkStart 参数 145 | * @param chunkNum 参数 146 | * @return 返回 147 | * 2016年12月19日 148 | */ 149 | public boolean recycleBuffer(MycatBufferBase parentBuffer, int chunkStart, int chunkNum) { 150 | if (this.buffer == parentBuffer) { 151 | // 如果加锁失败,则执行其他代码 152 | if (!isLock.compareAndSet(false, true)) { 153 | Thread.yield(); 154 | } 155 | 156 | try { 157 | int endChunkNum = chunkStart + chunkNum; 158 | // 将当前指定的内存块归还 159 | memUseSet.clear(chunkStart, endChunkNum); 160 | 161 | // 归还了内存,则需要将可使用的内存加上归还的内存 162 | this.canUseChunkNum = canUseChunkNum + chunkNum; 163 | 164 | } finally { 165 | isLock.set(false); 166 | } 167 | 168 | return true; 169 | 170 | } 171 | 172 | return false; 173 | } 174 | 175 | // public static void main(String[] args) { 176 | // MycatMovableBufer buffer = new DirectMycatBufferImpl(2048); 177 | // 178 | // UnsafeDirectBufferPage page = new UnsafeDirectBufferPage(buffer, 256); 179 | // 180 | // buffer.beginOp(); 181 | // 182 | // MycatBuffer buffer1 = page.alloactionMemory(4); 183 | // MycatBuffer buffer2 = page.alloactionMemory(4); 184 | // 185 | // buffer.commitOp(); 186 | // // // 获得内存buffer 187 | // // sun.nio.ch.DirectBuffer thisNavBuf = (sun.nio.ch.DirectBuffer) 188 | // // bufferItem2; 189 | // // // attachment对象在buf.slice();的时候将attachment对象设置为总的buff对象 190 | // // sun.nio.ch.DirectBuffer parentBuf = (sun.nio.ch.DirectBuffer) 191 | // // thisNavBuf.attachment(); 192 | // // // 193 | // // 已经使用的地址减去父类最开始的地址,即为所有已经使用的地址,除以chunkSize得到chunk当前开始的地址,得到整块内存开始的地址 194 | // // int startChunk = (int) ((page - parentBuf.address()) / 256); 195 | // // 196 | // // // 归还当前buffer2的内存 197 | // // page.recycleBuffer(parentBuf, startChunk, 2); 198 | // // 199 | // // System.out.println(bufferItem); 200 | // // System.out.println(bufferItem2); 201 | // // System.out.println(bufferItem3); 202 | // 203 | // } 204 | 205 | } 206 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/sqlcache/PageLRUCache.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.sqlcache; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.io.IOException; 7 | import java.util.*; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.locks.Lock; 11 | import java.util.concurrent.locks.ReadWriteLock; 12 | import java.util.concurrent.locks.ReentrantReadWriteLock; 13 | 14 | /** 15 | * 通过LRU机制 Cache Buffer Page,提供高访问速度 16 | * or zagnix 17 | * 2016-12-02 14:37 18 | */ 19 | 20 | public class PageLRUCache { 21 | private final static Logger logger = LoggerFactory.getLogger(PageLRUCache.class); 22 | 23 | public static final long DEFAULT_TTL = 5 * 1000; 24 | 25 | private final Map map; 26 | 27 | private final ReadWriteLock lock = new ReentrantReadWriteLock(); 28 | 29 | private final Lock readLock = lock.readLock(); 30 | private final Lock writeLock = lock.writeLock(); 31 | 32 | /** 33 | * 异步线程 34 | */ 35 | private static final ExecutorService executorService 36 | = Executors.newCachedThreadPool(); 37 | 38 | private final Set toDisk = new HashSet(); 39 | 40 | public PageLRUCache() { 41 | map = new HashMap(); 42 | } 43 | 44 | /** 45 | * 向Cache添加一个page,会触发Page Sweep操作 46 | * @param key 参数 47 | * @param value 参数 48 | * @param ttlInMilliSeconds 参数 49 | */ 50 | public void put(Long key, MyCatBufferPage value, long ttlInMilliSeconds) { 51 | Collection values = null; 52 | try { 53 | writeLock.lock(); 54 | values = pageSweep(); 55 | if (values != null && values.contains(value)) { 56 | values.remove(value); 57 | } 58 | value.getLastAccessedTimestamp().set(System.currentTimeMillis()); 59 | map.put(key, value); 60 | } finally { 61 | writeLock.unlock(); 62 | } 63 | 64 | 65 | if (values != null && values.size() > 0) { 66 | executorService.execute(new Task(values)); 67 | } 68 | } 69 | 70 | public void put(Long key,MyCatBufferPage value) { 71 | this.put(key, value, DEFAULT_TTL); 72 | } 73 | 74 | 75 | /** 76 | * 根据Page Index 得到对应的 Page 77 | * 同时会设置该Page的访问时间,和引用计数+1 78 | * @param key 参数 79 | * @return 返回 80 | */ 81 | public MyCatBufferPage get(final Long key) { 82 | try { 83 | readLock.lock(); 84 | MyCatBufferPage value = map.get(key); 85 | if (value != null) { 86 | value.getLastAccessedTimestamp().set(System.currentTimeMillis()); 87 | value.getRefCount().incrementAndGet(); 88 | } 89 | return map.get(key); 90 | } finally { 91 | readLock.unlock(); 92 | } 93 | } 94 | 95 | /** 96 | * 将上次访问时间超过Cache TTL 和 引用数=0的Page 97 | * 存放到collection中,供put调用时候,异步从内存 98 | * 中刷到磁盘上 99 | * @return 返回 100 | */ 101 | 102 | private Collection pageSweep() { 103 | Collection values = null; 104 | toDisk.clear(); 105 | Set keys = map.keySet(); 106 | long currentTimeMillis = System.currentTimeMillis(); 107 | 108 | for(Long key: keys) { 109 | MyCatBufferPage v = map.get(key); 110 | if (v.getRefCount().get() <= 0 111 | && (currentTimeMillis - v.getLastAccessedTimestamp().get()) > v.getCacheTTL()) { 112 | toDisk.add(key); 113 | } 114 | } 115 | 116 | if (toDisk.size() > 0) { 117 | values = new HashSet(); 118 | for(Long key : toDisk) { 119 | MyCatBufferPage v = map.remove(key); 120 | values.add(v); 121 | } 122 | } 123 | 124 | return values; 125 | } 126 | 127 | /** 128 | * 引用计数减1 129 | * @param key 参数 130 | */ 131 | 132 | public void release(final Long key) { 133 | try { 134 | readLock.lock(); 135 | MyCatBufferPage value = map.get(key); 136 | if (value != null) { 137 | value.getRefCount().decrementAndGet(); 138 | } 139 | } finally { 140 | readLock.unlock(); 141 | } 142 | } 143 | 144 | /** 145 | * 缓存page的大小 146 | * @return 返回 147 | */ 148 | public int size() { 149 | try { 150 | readLock.lock(); 151 | return map.size(); 152 | } finally { 153 | readLock.unlock(); 154 | } 155 | } 156 | 157 | 158 | /** 159 | * 将所有缓存在内存中Page 数据,刷到磁盘中去 160 | * @throws IOException 异常 161 | */ 162 | public void removeAll() throws IOException { 163 | try { 164 | writeLock.lock(); 165 | Collection values = map.values(); 166 | if (values != null && values.size() > 0) { 167 | for(MyCatBufferPage v : values) { 168 | v.recycle(); 169 | } 170 | } 171 | map.clear(); 172 | } finally { 173 | writeLock.unlock(); 174 | } 175 | 176 | } 177 | 178 | 179 | /** 180 | * 将index Page 数据,刷到磁盘中去 181 | * @param key 参数 182 | * @return 返回 183 | * @throws IOException 异常 184 | */ 185 | 186 | public MyCatBufferPage remove(final Long key) throws IOException { 187 | try { 188 | writeLock.lock(); 189 | MyCatBufferPage value = map.remove(key); 190 | if (value != null) { 191 | value.recycle(); 192 | } 193 | return value; 194 | } finally { 195 | writeLock.unlock(); 196 | } 197 | } 198 | 199 | 200 | 201 | 202 | public Collection getValues() { 203 | try { 204 | readLock.lock(); 205 | return map.values(); 206 | } finally { 207 | readLock.unlock(); 208 | } 209 | } 210 | 211 | 212 | /** 213 | * 异步操作task,负责将内存中的页数据,刷到磁盘中 214 | */ 215 | private static class Task implements Runnable { 216 | Collection values; 217 | public Task(Collection values) { 218 | this.values = values; 219 | } 220 | public void run() { 221 | for(MyCatBufferPage v : values) { 222 | try { 223 | if (v != null) { 224 | v.recycle(); 225 | } 226 | } catch (IOException e) { 227 | } 228 | } 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/chunkpageallot/buffer/impl/DirectMycatBufferMoveImpl.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem.chunkpageallot.buffer.impl; 2 | 3 | import java.nio.BufferOverflowException; 4 | import java.nio.ByteBuffer; 5 | import java.util.concurrent.Semaphore; 6 | 7 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBuffer; 8 | import io.mycat.bigmem.chunkpageallot.buffer.MycatBufferBase; 9 | import io.mycat.bigmem.chunkpageallot.buffer.MycatMovableBufer; 10 | import io.mycat.bigmem.chunkpageallot.console.BufferException; 11 | import io.mycat.bigmem.util.UnsafeHelper; 12 | import sun.misc.Unsafe; 13 | 14 | /** 15 | * 进行直接内存的操作 16 | * 源文件名:DirectMycatBufferImpl.java 17 | * 文件版本:1.0.0 18 | * 创建作者:liujun 19 | * 创建日期:2016年12月22日 20 | * 修改作者:liujun 21 | * 修改日期:2016年12月22日 22 | * 文件描述:TODO 23 | * 版权所有:Copyright 2016 zjhz, Inc. All Rights Reserved. 24 | */ 25 | public class DirectMycatBufferMoveImpl extends MycatBufferBase implements MycatMovableBufer { 26 | 27 | /** 28 | * 用来进行自己内存管理的对象 29 | * unsafe 30 | */ 31 | private Unsafe unsafe; 32 | 33 | /** 34 | * 是否进行内存整理标识,默认为true,即允许进行整理 35 | * clearFlag 36 | */ 37 | private volatile boolean clearFlag = true; 38 | 39 | /** 40 | * 用来控制队列的访问,同一时间,不能被多个线程同同时操作队列 41 | * lock 42 | */ 43 | private Semaphore accessReq = new Semaphore(1); 44 | 45 | /** 46 | * 构造方法,进行内存容量的分配操作 47 | * 构造方法 48 | * @param memorySize 内存容量信息 49 | */ 50 | public DirectMycatBufferMoveImpl(int memorySize) { 51 | // // 获得首地址信息 52 | unsafe = UnsafeHelper.getUnsafe(); 53 | // 进行内存分配 54 | address = unsafe.allocateMemory(memorySize); 55 | // 设置所有的内存地址都为0 56 | unsafe.setMemory(address, memorySize, (byte) 0); 57 | // 设置limit以及空量信息 58 | this.limit = memorySize; 59 | // 设置容量 60 | this.capacity = memorySize; 61 | } 62 | 63 | public DirectMycatBufferMoveImpl(DirectMycatBufferMoveImpl dirbuffer, int position, int limit, long address) { 64 | this.putPosition = position; 65 | this.limit = limit; 66 | // 设置容量 67 | this.capacity = limit; 68 | this.address = address; 69 | this.att = dirbuffer; 70 | this.unsafe = dirbuffer.unsafe; 71 | } 72 | 73 | private long getIndex(long offset) { 74 | if (limit < offset) 75 | throw new BufferOverflowException(); 76 | return address + offset; 77 | } 78 | 79 | @Override 80 | public void setByte(int offset, byte value) { 81 | 82 | // 验证当前是否在进行内存整理 83 | checkClearFlag(); 84 | 85 | unsafe.putByte(getIndex(offset), value); 86 | } 87 | 88 | @Override 89 | public byte getByte(int offset) { 90 | 91 | // 验证当前是否在进行内存整理 92 | checkClearFlag(); 93 | 94 | // 仅允许同一线程操作 95 | return unsafe.getByte(getIndex(offset)); 96 | } 97 | 98 | @Override 99 | public void copyTo(ByteBuffer buffer) { 100 | 101 | // 验证当前是否在进行内存整理 102 | checkClearFlag(); 103 | 104 | if (buffer.capacity() < this.limit) { 105 | throw new BufferOverflowException(); 106 | } 107 | // 获取当前堆外的内存的地址 108 | long buffAddress = ((sun.nio.ch.DirectBuffer) buffer).address(); 109 | // 进行内存的拷贝 110 | unsafe.copyMemory(null, address, null, buffAddress, this.limit); 111 | } 112 | 113 | @Override 114 | public void recycleUnuse() { 115 | // 验证当前是否在进行内存整理 116 | checkClearFlag(); 117 | // 修改当前的标识 118 | this.limit = this.putPosition; 119 | } 120 | 121 | @Override 122 | public MycatBufferBase slice() { 123 | 124 | // 验证当前是否在进行内存整理 125 | checkClearFlag(); 126 | 127 | int currPosition = this.putPosition; 128 | int cap = this.limit - currPosition; 129 | long address = this.address + currPosition; 130 | // 生新新的引用对象 131 | return new DirectMycatBufferMoveImpl(this, 0, cap, address); 132 | } 133 | 134 | /** 135 | * 将添加的指针加1 136 | * 方法描述 137 | * @return 138 | * 2016年12月23日 139 | */ 140 | private long addPutPos() { 141 | if (this.putPosition >= this.limit) 142 | throw new BufferOverflowException(); 143 | return this.putPosition++; 144 | } 145 | 146 | /** 147 | * 将获取的指针加1 148 | * 方法描述 149 | * @return 150 | * 2016年12月23日 151 | */ 152 | private long addGetPos() { 153 | if (this.getPosition > this.limit) 154 | throw new BufferOverflowException(); 155 | return this.getPosition++; 156 | } 157 | 158 | @Override 159 | public MycatBuffer putByte(byte b) { 160 | 161 | // 验证当前内存整理标识 162 | checkClearFlag(); 163 | 164 | unsafe.putByte(getIndex(this.addPutPos()), b); 165 | 166 | return this; 167 | } 168 | 169 | @Override 170 | public byte get() { 171 | 172 | // 验证当前内存整理标识 173 | checkClearFlag(); 174 | 175 | return unsafe.getByte(getIndex(this.addGetPos())); 176 | 177 | } 178 | 179 | /** 180 | * 进行内存整理的标识验证 181 | * 方法描述 182 | * 2016年12月27日 183 | */ 184 | private void checkClearFlag() { 185 | // 仅当不进行整理时,才能进行操作 186 | if (clearFlag) { 187 | throw new BufferException("DirectMycatBufferImpl exception,please invoke beginOp"); 188 | } 189 | } 190 | 191 | public void beginOp() throws InterruptedException { 192 | accessReq.acquire(); 193 | // 标识当前正在进行内存操作,不能整理内存 194 | clearFlag = false; 195 | } 196 | 197 | @Override 198 | public void commitOp() { 199 | // 内存整理完毕可以进行内存整理 200 | clearFlag = true; 201 | // 访问结束,释放语可 202 | accessReq.release(); 203 | } 204 | 205 | @Override 206 | public void limit(int limit) { 207 | 208 | // 验证当前内存整理标识 209 | checkClearFlag(); 210 | 211 | this.limit = limit; 212 | } 213 | 214 | @Override 215 | public void putPosition(int position) { 216 | 217 | // 验证当前内存整理标识 218 | checkClearFlag(); 219 | 220 | this.putPosition = position; 221 | } 222 | 223 | public void getPosition(int getPosition) { 224 | 225 | // 验证当前内存整理标识 226 | checkClearFlag(); 227 | 228 | this.getPosition = getPosition; 229 | } 230 | 231 | @Override 232 | public boolean getClearFlag() { 233 | return this.clearFlag; 234 | } 235 | 236 | @Override 237 | public void memoryCopy(long srcAddress, long targerAddress, int length) { 238 | 239 | // 验证当前内存整理标识 240 | checkClearFlag(); 241 | 242 | // 进行堆外的内存的拷贝操作 243 | unsafe.copyMemory(null, srcAddress, null, targerAddress, length); 244 | 245 | } 246 | 247 | } 248 | -------------------------------------------------------------------------------- /src/main/java/io/mycat/bigmem/MyCatBigSqlResultsCache.java: -------------------------------------------------------------------------------- 1 | package io.mycat.bigmem; 2 | 3 | import com.google.common.util.concurrent.*; 4 | 5 | import io.mycat.bigmem.console.LocatePolicy; 6 | import io.mycat.bigmem.sqlcache.*; 7 | import io.mycat.bigmem.util.Utils; 8 | 9 | import java.util.concurrent.Callable; 10 | import java.util.concurrent.Executors; 11 | 12 | import static com.google.common.hash.Hashing.murmur3_32; 13 | 14 | /** 15 | * Cache SQL 大结果集 对外接口 16 | * 17 | * or zagnix 18 | * @version 1.0 19 | * 2016-12-30 10:51 20 | */ 21 | 22 | public class MyCatBigSqlResultsCache { 23 | 24 | private final CacheImp sqlResultCacheImp; 25 | 26 | private final static MyCatBigSqlResultsCache INSTANCE = new MyCatBigSqlResultsCache(); 27 | 28 | private MyCatBigSqlResultsCache(){ 29 | sqlResultCacheImp = new CacheImp(); 30 | } 31 | 32 | /** 33 | * 将sql结果集缓存起来 34 | * 35 | * @param sql sql语句 36 | * @param bigSQLResult sql结果集缓存 37 | * @param cache 缓存时间 38 | * @param accesCount 在缓存时间内,被访问的次数 39 | * @param loader 结果集load or reload 接口 40 | * @param listener key被移除时,调用的接口 41 | */ 42 | public void cacheSQLResult(String sql, BigSQLResult bigSQLResult, long cache, long accesCount, 43 | IDataLoader loader, IRemoveKeyListener listener){ 44 | /** 45 | * TODO 46 | */ 47 | String key = "" + murmur3_32().hashUnencodedChars(sql); 48 | 49 | Keyer keyer = new Keyer(); 50 | keyer.setSql(sql); 51 | keyer.setKey(key); 52 | keyer.setValue(bigSQLResult); 53 | keyer.setCacheTTL(cache); 54 | keyer.setAccessCount(accesCount); 55 | keyer.setRemoveKeyListener(listener); 56 | keyer.setiDataLoader(loader); 57 | sqlResultCacheImp.put(key,bigSQLResult,keyer); 58 | } 59 | 60 | 61 | /** 62 | * 获取sql语句,已经缓存的结果集 63 | * 64 | * @param sql sql 语句 65 | * @return 返回 66 | */ 67 | public BigSQLResult getSQLResult(String sql){ 68 | /** 69 | * TODO 70 | */ 71 | String key = "" + murmur3_32().hashUnencodedChars(sql); 72 | return sqlResultCacheImp.get(key); 73 | } 74 | 75 | 76 | 77 | /** 78 | * 获取sql语句,已经缓存的结果集 79 | * 80 | * @param sql sql 语句 81 | */ 82 | public void remove(String sql){ 83 | /** 84 | * TODO 85 | */ 86 | String key = "" + murmur3_32().hashUnencodedChars(sql); 87 | sqlResultCacheImp.remove(key); 88 | } 89 | 90 | 91 | 92 | /** 93 | * 对外对象实例 94 | * @return 返回 95 | */ 96 | public static MyCatBigSqlResultsCache getInstance() { 97 | return INSTANCE; 98 | } 99 | 100 | 101 | public static void main(String [] args){ 102 | 103 | String sql = "select * from table"; 104 | 105 | BigSQLResult sqlResultCache = 106 | new BigSQLResult(LocatePolicy.Normal,sql,32*1024*1024); 107 | 108 | long ROWS = 10000; 109 | 110 | 111 | /** 模拟从后端DB拉取数据 */ 112 | for (int i = 0; i < ROWS ; i++) { 113 | byte[] rows = Utils.randomString(1024).getBytes(); 114 | 115 | /** 116 | * 使用内存映射Cache,存放SQL结果集 117 | */ 118 | sqlResultCache.put(rows); 119 | } 120 | 121 | 122 | MyCatBigSqlResultsCache.getInstance().cacheSQLResult(sql,sqlResultCache,300,5000, 123 | new IDataLoader() { 124 | 125 | /** 126 | * 根据sql,异步从后台DB reload数据,替换旧值 127 | * @param keyer 128 | * @return 129 | */ 130 | @Override 131 | public BigSQLResult reload(Keyer keyer) { 132 | ListeningExecutorService executor = 133 | MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); 134 | 135 | final ListenableFuture listenableFuture = executor 136 | .submit(new Callable() { 137 | @Override 138 | public BigSQLResult call() throws Exception { 139 | String sql = keyer.getSql(); 140 | String sqlkey = keyer.getLastAccessTime() +"_"+murmur3_32().hashUnencodedChars(sql); 141 | BigSQLResult sqlResultCache 142 | = new BigSQLResult(LocatePolicy.Normal,sqlkey,32*1024*1024); 143 | 144 | /**模拟从后端DB拉取数据*/ 145 | for (int i = 0; i < ROWS ; i++) { 146 | byte[] rows = Utils.randomString(1024).getBytes(); 147 | 148 | /** 149 | * 使用内存映射Cache,存放SQL结果集 150 | */ 151 | sqlResultCache.put(rows); 152 | } 153 | return sqlResultCache; 154 | } 155 | }); 156 | 157 | Futures.addCallback(listenableFuture, new FutureCallback() { 158 | @Override 159 | public void onSuccess(BigSQLResult bigSQLResult) { 160 | if(bigSQLResult!=null && bigSQLResult.hasNext()){ 161 | 162 | BigSQLResult oldSqlResult= 163 | MyCatBigSqlResultsCache.getInstance().getSQLResult(keyer.getSql()); 164 | 165 | if (oldSqlResult != null){ 166 | oldSqlResult.removeAll(); 167 | } 168 | 169 | /**替换旧的值*/ 170 | MyCatBigSqlResultsCache.getInstance(). 171 | sqlResultCacheImp.put(keyer.getKey(),bigSQLResult,keyer); 172 | } 173 | } 174 | 175 | @Override 176 | public void onFailure(Throwable t) { 177 | //TODO 178 | } 179 | } 180 | ); 181 | 182 | return null; 183 | } 184 | 185 | 186 | }, new IRemoveKeyListener() { 187 | 188 | /** 189 | * key 失效,做清理工作 190 | * 191 | * @param key 192 | * @param value 193 | */ 194 | @Override 195 | public void removeNotify(String key, BigSQLResult value) { 196 | if (value !=null){ 197 | value.removeAll(); 198 | } 199 | 200 | System.out.println("key :" + key); 201 | } 202 | }); 203 | 204 | /** 205 | * 访问Cache 206 | */ 207 | BigSQLResult bigSQLResult = 208 | MyCatBigSqlResultsCache.getInstance().getSQLResult(sql); 209 | 210 | 211 | bigSQLResult.reset(); 212 | 213 | while (bigSQLResult.hasNext()){ 214 | 215 | byte[] data = bigSQLResult.next(); 216 | //TODO 217 | System.out.println("String :" + new String(data)); 218 | 219 | } 220 | 221 | 222 | MyCatBigSqlResultsCache.getInstance().remove(sql); 223 | 224 | try { 225 | Thread.sleep(1); 226 | } catch (InterruptedException e) { 227 | e.printStackTrace(); 228 | } 229 | 230 | } 231 | 232 | } 233 | --------------------------------------------------------------------------------