());
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