diff --git a/orm/src/main/java/com/zfoo/orm/lpmap/FileHeapMap.java b/orm/src/main/java/com/zfoo/orm/lpmap/FileHeapMap.java new file mode 100644 index 00000000..7ddbae16 --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/lpmap/FileHeapMap.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.orm.lpmap; + +import com.zfoo.protocol.IPacket; +import com.zfoo.protocol.ProtocolManager; +import com.zfoo.protocol.buffer.ByteBufUtils; +import com.zfoo.protocol.registration.IProtocolRegistration; +import com.zfoo.protocol.registration.ProtocolAnalysis; +import com.zfoo.protocol.util.FileUtils; +import com.zfoo.protocol.util.IOUtils; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.util.ReferenceCountUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; + +/** + * @author jaysunxiao + * @version 3.0 + */ +public class FileHeapMap implements LpMap { + + private File file; + + private IProtocolRegistration protocolRegistration; + + private HeapMap heapMap; + + public FileHeapMap(File file, int initialCapacity, Class clazz) { + this.file = file; + var protocolId = ProtocolAnalysis.getProtocolIdByClass(clazz); + protocolRegistration = ProtocolManager.getProtocol(protocolId); + heapMap = new HeapMap<>(initialCapacity); + + load(); + } + + + @Override + public long insert(V packet) { + return heapMap.insert(packet); + } + + @Override + public V put(long key, V packet) { + return heapMap.put(key, packet); + } + + @Override + public V delete(long key) { + return heapMap.delete(key); + } + + @Override + public V get(long key) { + return heapMap.get(key); + } + + private void load() { + FileInputStream fileInputStream = null; + FileChannel fileChannel = null; + ByteBuf buffer = null; + try { + fileInputStream = FileUtils.openInputStream(file); + fileChannel = fileInputStream.getChannel(); + + buffer = ByteBufAllocator.DEFAULT.ioBuffer(1000); + buffer.writeBytes(fileChannel, 0L, (int) file.length()); + + var size = ByteBufUtils.readLong(buffer); + for (int i = 0; i < size; i++) { + var key = ByteBufUtils.readLong(buffer); + var value = (V) protocolRegistration.read(buffer); + put(key, value); + } + } catch (IOException e) { + IOUtils.closeIO(fileChannel, fileInputStream); + ReferenceCountUtil.release(buffer); + } + } + + public void save() { + FileOutputStream fileOutputStream = null; + ByteBuf buffer = null; + try { + fileOutputStream = FileUtils.openOutputStream(file, false); + buffer = ByteBufAllocator.DEFAULT.heapBuffer(1000); + + // 写入长度 + ByteBufUtils.writeLong(buffer, heapMap.map.size()); + buffer.readBytes(fileOutputStream, buffer.readableBytes()); + + for (var entry : heapMap.map.entries()) { + buffer.clear(); + + var key = entry.key(); + var value = entry.value(); + ByteBufUtils.writeLong(buffer, key); + protocolRegistration.write(buffer, value); + + buffer.readBytes(fileOutputStream, buffer.readableBytes()); + } + } catch (IOException e) { + IOUtils.closeIO(fileOutputStream); + ReferenceCountUtil.release(buffer); + } + } +} diff --git a/orm/src/main/java/com/zfoo/orm/lpmap/HeapMap.java b/orm/src/main/java/com/zfoo/orm/lpmap/HeapMap.java new file mode 100644 index 00000000..f9294d40 --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/lpmap/HeapMap.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.orm.lpmap; + +import com.zfoo.protocol.IPacket; +import io.netty.util.collection.LongObjectHashMap; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author jaysunxiao + * @version 3.0 + */ +public class HeapMap implements LpMap { + + protected LongObjectHashMap map; + + /** + * 没有被使用的key + */ + protected Queue freeKeyQueue = new LinkedList<>(); + + protected long index = 0; + + public HeapMap(int initialCapacity) { + map = new LongObjectHashMap<>(initialCapacity); + } + + @Override + public long insert(V packet) { + if (freeKeyQueue.isEmpty()) { + map.put(++index, packet); + return index; + } else { + var freeKey = freeKeyQueue.poll(); + map.put(freeKey, packet); + return freeKey; + } + } + + @Override + public V put(long key, V packet) { + checkKey(key); + if (key <= index) { + return map.put(key, packet); + } else { + for (var i = index + 1; i < key; i++) { + freeKeyQueue.add(i); + } + index = key; + map.put(key, packet); + return null; + } + } + + @Override + public V delete(long key) { + checkKey(key); + if (key > index) { + return null; + } else { + var previousValue = map.remove(key); + freeKeyQueue.add(key); + return previousValue; + } + } + + @Override + public V get(long key) { + checkKey(key); + return map.get(key); + } +} diff --git a/orm/src/main/java/com/zfoo/orm/lpmap/LpMap.java b/orm/src/main/java/com/zfoo/orm/lpmap/LpMap.java new file mode 100644 index 00000000..610adc8b --- /dev/null +++ b/orm/src/main/java/com/zfoo/orm/lpmap/LpMap.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.orm.lpmap; + +import com.zfoo.protocol.IPacket; +import com.zfoo.protocol.exception.RunException; + +/** + * 类型固定的map,key为long,value为IPacket + * 其中long必须大于0,value可以为null + * + * @author jaysunxiao + * @version 3.0 + */ +public interface LpMap { + + /** + * 插入一条数据,返回一个自增的key,效率比较高 + */ + long insert(V packet); + + /** + * @param packet the previous value associated with key, or null if there was no mapping for key. + */ + V put(long key, V packet); + + /** + * @return 返回被删除的那个值 + */ + V delete(long key); + + V get(long key); + + default void checkKey(long key) { + if (key <= 0) { + throw new RunException("key[{}]不能为负数", key); + } + } + +} diff --git a/orm/src/test/java/com/zfoo/orm/lpmap/FileHeapMapTest.java b/orm/src/test/java/com/zfoo/orm/lpmap/FileHeapMapTest.java new file mode 100644 index 00000000..693ce071 --- /dev/null +++ b/orm/src/test/java/com/zfoo/orm/lpmap/FileHeapMapTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.orm.lpmap; + +import com.zfoo.orm.lpmap.model.MyPacket; +import com.zfoo.protocol.ProtocolManager; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.util.Set; + +/** + * @author jaysunxiao + * @version 3.0 + */ +@Ignore +public class FileHeapMapTest { + + @Test + public void test() { + ProtocolManager.initProtocol(Set.of(MyPacket.class)); + + var map = new FileHeapMap(new File("myPacket.db"), 10, MyPacket.class); + var myPacket = new MyPacket(); + myPacket.setA(9999); + + var key = map.insert(myPacket); + Assert.assertEquals(key, 1L); + + var packet = map.put(1, myPacket); + Assert.assertEquals(packet, myPacket); + + packet = map.put(3, myPacket); + Assert.assertNull(packet); + + key = map.insert(myPacket); + Assert.assertEquals(key, 2L); + + packet = map.delete(4); + Assert.assertNull(packet); + + packet = map.delete(3); + Assert.assertEquals(packet, myPacket); + + packet = map.delete(2); + Assert.assertEquals(packet, myPacket); + + map.put(1, myPacket); + map.put(2, myPacket); + map.put(3, myPacket); + map.put(4, myPacket); + map.put(5, myPacket); + map.save(); + } + + + @Test + public void readTest() { + ProtocolManager.initProtocol(Set.of(MyPacket.class)); + var map = new FileHeapMap(new File("myPacket.db"), 10, MyPacket.class); + } +} diff --git a/orm/src/test/java/com/zfoo/orm/lpmap/HeapMapTest.java b/orm/src/test/java/com/zfoo/orm/lpmap/HeapMapTest.java new file mode 100644 index 00000000..46a9c058 --- /dev/null +++ b/orm/src/test/java/com/zfoo/orm/lpmap/HeapMapTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.orm.lpmap; + +import com.zfoo.orm.lpmap.model.MyPacket; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +/** + * @author jaysunxiao + * @version 3.0 + */ +@Ignore +public class HeapMapTest { + + @Test + public void test() { + var map = new HeapMap(10); + var myPacket = new MyPacket(); + + var key = map.insert(myPacket); + Assert.assertEquals(key, 1L); + + var packet = map.put(1, myPacket); + Assert.assertEquals(packet, myPacket); + + packet = map.put(3, myPacket); + Assert.assertNull(packet); + + key = map.insert(myPacket); + Assert.assertEquals(key, 2L); + + packet = map.delete(4); + Assert.assertNull(packet); + + packet = map.delete(3); + Assert.assertEquals(packet, myPacket); + + packet = map.delete(2); + Assert.assertEquals(packet, myPacket); + } + +} diff --git a/orm/src/test/java/com/zfoo/orm/lpmap/model/MyPacket.java b/orm/src/test/java/com/zfoo/orm/lpmap/model/MyPacket.java new file mode 100644 index 00000000..4d1c9be7 --- /dev/null +++ b/orm/src/test/java/com/zfoo/orm/lpmap/model/MyPacket.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The zfoo Authors + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and limitations under the License. + */ + +package com.zfoo.orm.lpmap.model; + +import com.zfoo.protocol.IPacket; + +/** + * @author jaysunxiao + * @version 3.0 + */ +public class MyPacket implements IPacket { + + public static final transient short PROTOCOL_ID = 1; + + private int a; + + @Override + public short protocolId() { + return PROTOCOL_ID; + } + + public int getA() { + return a; + } + + public void setA(int a) { + this.a = a; + } +} diff --git a/protocol/src/main/java/com/zfoo/protocol/ProtocolManager.java b/protocol/src/main/java/com/zfoo/protocol/ProtocolManager.java index f33c7c3e..223127c4 100644 --- a/protocol/src/main/java/com/zfoo/protocol/ProtocolManager.java +++ b/protocol/src/main/java/com/zfoo/protocol/ProtocolManager.java @@ -63,7 +63,7 @@ public class ProtocolManager { public static IProtocolRegistration getProtocol(short protocolId) { var protocol = protocols[protocolId]; - AssertionUtils.notNull(protocol, "[protocolId:{}]协议不存在", protocolId); + AssertionUtils.notNull(protocol, "[protocolId:{}]协议不存在,可能没有注册该协议或者协议号错误", protocolId); return protocol; } diff --git a/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java b/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java index 4749500d..a3bff3cf 100644 --- a/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java +++ b/protocol/src/main/java/com/zfoo/protocol/registration/ProtocolAnalysis.java @@ -494,7 +494,7 @@ public class ProtocolAnalysis { throw new RunException("[type:{}]类型不正确", type); } - private static short getProtocolIdByClass(Class clazz) { + public static short getProtocolIdByClass(Class clazz) { var protocolIdField = ReflectionUtils.getFieldByNameInPOJOClass(clazz, PROTOCOL_ID); ReflectionUtils.makeAccessible(protocolIdField); return (short) ReflectionUtils.getField(protocolIdField, null);