mirror of
https://gitee.com/BDWare/common
synced 2025-01-10 01:44:16 +00:00
fix: binarySearch bugs in TimeSerialIndex
feat: support multi tag time index util
This commit is contained in:
parent
7032dd3b28
commit
2ce57c111e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
/build/
|
/build/
|
||||||
|
/testoutput/
|
||||||
*/build/*
|
*/build/*
|
||||||
# Compiled class file
|
# Compiled class file
|
||||||
*.class
|
*.class
|
||||||
|
@ -10,6 +10,7 @@ public enum Permission {
|
|||||||
RocksDB,
|
RocksDB,
|
||||||
MongoDB,
|
MongoDB,
|
||||||
BDWareTimeSeriesDB,
|
BDWareTimeSeriesDB,
|
||||||
|
MultiTagIndexDB,
|
||||||
SM2,
|
SM2,
|
||||||
AES,
|
AES,
|
||||||
Ledger,
|
Ledger,
|
||||||
|
@ -18,6 +18,7 @@ import java.util.*;
|
|||||||
public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
||||||
private static final Logger LOGGER = LogManager.getLogger(MultiIndexTimeRocksDBUtil.class);
|
private static final Logger LOGGER = LogManager.getLogger(MultiIndexTimeRocksDBUtil.class);
|
||||||
private final Map<String, TimeSerialIndex> secondaryIndex;
|
private final Map<String, TimeSerialIndex> secondaryIndex;
|
||||||
|
static String primaryKey = "_DB_primary_";
|
||||||
public String dbPath;
|
public String dbPath;
|
||||||
public String tableName;
|
public String tableName;
|
||||||
Random random = new Random();
|
Random random = new Random();
|
||||||
@ -42,7 +43,7 @@ public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
|||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
options.setCreateIfMissing(true);
|
options.setCreateIfMissing(true);
|
||||||
File lockFile = new File(file, "LOCK");
|
File lockFile = new File(file, "LOCK");
|
||||||
File timeIndex = new File(dbPath + "/" + tableName + "/DB.primary.timeindex");
|
File timeIndex = new File(dbPath + "/" + tableName + "/" + primaryIndex + ".timeindex");
|
||||||
LOGGER.trace("create directory " + file.getAbsolutePath() + ": " + file.mkdirs());
|
LOGGER.trace("create directory " + file.getAbsolutePath() + ": " + file.mkdirs());
|
||||||
LOGGER.trace("delete file" + lockFile.getAbsolutePath() + ": " + lockFile.delete());
|
LOGGER.trace("delete file" + lockFile.getAbsolutePath() + ": " + lockFile.delete());
|
||||||
try {
|
try {
|
||||||
@ -51,8 +52,16 @@ public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
|||||||
} catch (RocksDBException e) {
|
} catch (RocksDBException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryIndex = new TimeSerialIndex(timeIndex.getAbsolutePath());
|
primaryIndex = new TimeSerialIndex(timeIndex.getAbsolutePath());
|
||||||
|
secondaryIndex.put(primaryKey, primaryIndex);
|
||||||
|
for (File f : timeIndex.getParentFile().listFiles()) {
|
||||||
|
if (!f.getName().endsWith(".timeindex")) continue;
|
||||||
|
if (f.getName().equals(timeIndex.getName())) continue;
|
||||||
|
TimeSerialIndex index =
|
||||||
|
new TimeSerialIndex(f.getAbsolutePath());
|
||||||
|
secondaryIndex.putIfAbsent(f.getName().substring(0,
|
||||||
|
f.getName().length() - ".timeindex".length()), index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void put(String label, String val) {
|
public synchronized void put(String label, String val) {
|
||||||
@ -141,8 +150,13 @@ public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
|||||||
|
|
||||||
public long size(String label) {
|
public long size(String label) {
|
||||||
try {
|
try {
|
||||||
TimeSerialIndex index = getIndex(label);
|
if (label == null || label.length() == 0) {
|
||||||
if (index != null) return index.size();
|
return primaryIndex.size();
|
||||||
|
}
|
||||||
|
if (secondaryIndex.containsKey(label)) {
|
||||||
|
TimeSerialIndex index = getIndex(label);
|
||||||
|
return index.size();
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -152,17 +166,23 @@ public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
|||||||
public List<JsonObject> queryByOffset(String label, long offset, int count) {
|
public List<JsonObject> queryByOffset(String label, long offset, int count) {
|
||||||
List<JsonObject> ret = new ArrayList<>();
|
List<JsonObject> ret = new ArrayList<>();
|
||||||
TimeSerialIndex index = getIndex(label);
|
TimeSerialIndex index = getIndex(label);
|
||||||
List<Long> data = index.request(offset, count);
|
List<TimeSerialIndex.IndexEntry> data = index.requestIndexEntry(offset, count);
|
||||||
for (Long l : data) {
|
for (TimeSerialIndex.IndexEntry entry : data) {
|
||||||
try {
|
try {
|
||||||
String t = new String(db.get(longToByte(l)));
|
String t = new String(db.get(longToByte(entry.value)));
|
||||||
JsonObject jo;
|
JsonObject jo;
|
||||||
if (!t.isEmpty()) {
|
if (!t.isEmpty()) {
|
||||||
jo = JsonUtil.parseStringAsJsonObject(t);
|
try {
|
||||||
|
jo = JsonUtil.parseStringAsJsonObject(t);
|
||||||
|
} catch (Exception e) {
|
||||||
|
jo = new JsonObject();
|
||||||
|
jo.addProperty("data", t);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
jo = new JsonObject();
|
jo = new JsonObject();
|
||||||
}
|
}
|
||||||
jo.addProperty("key", l.toString());
|
jo.addProperty("key", entry.value);
|
||||||
|
jo.addProperty("timestamp", entry.key);
|
||||||
ret.add(jo);
|
ret.add(jo);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -181,7 +201,7 @@ public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TimeSerialIndex getIndex(String label) {
|
private TimeSerialIndex getIndex(String label) {
|
||||||
if (null == label) {
|
if (null == label || label.length() == 0) {
|
||||||
return primaryIndex;
|
return primaryIndex;
|
||||||
}
|
}
|
||||||
if (secondaryIndex.containsKey(label)) {
|
if (secondaryIndex.containsKey(label)) {
|
||||||
@ -275,6 +295,31 @@ public class MultiIndexTimeRocksDBUtil implements MultiIndexTimeDBUtilIntf {
|
|||||||
// manuellyIndex可参考LenVarTimeIndex写法
|
// manuellyIndex可参考LenVarTimeIndex写法
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getIndexStartWith(String prefix) {
|
||||||
|
List<String> ret = new ArrayList<>();
|
||||||
|
if (prefix == null) {
|
||||||
|
prefix = "";
|
||||||
|
}
|
||||||
|
for (String key : secondaryIndex.keySet()) {
|
||||||
|
if (key.startsWith(prefix))
|
||||||
|
ret.add(key);
|
||||||
|
}
|
||||||
|
ret.remove(primaryKey);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAllIndexKey() {
|
||||||
|
Set<String> data = secondaryIndex.keySet();
|
||||||
|
List<String> ret = new ArrayList<>();
|
||||||
|
ret.addAll(data);
|
||||||
|
ret.remove(primaryKey);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
static class BytesPair {
|
static class BytesPair {
|
||||||
byte[] key, value;
|
byte[] key, value;
|
||||||
|
@ -85,6 +85,39 @@ public class TimeSerialIndex {
|
|||||||
} else return new ArrayList<>();
|
} else return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class IndexEntry {
|
||||||
|
public long key, value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized List<IndexEntry> requestIndexEntry(long offset, int len) {
|
||||||
|
List<IndexEntry> ret = new ArrayList<>();
|
||||||
|
if (offset < 0) offset = 0;
|
||||||
|
if (offset < fileSize) {
|
||||||
|
long pos = 0;
|
||||||
|
try {
|
||||||
|
pos = file.getFilePointer();
|
||||||
|
file.seek(2L * offset * 8L);
|
||||||
|
for (; offset < fileSize && len > 0; len--) {
|
||||||
|
IndexEntry entry = new IndexEntry();
|
||||||
|
entry.key = file.readLong();
|
||||||
|
entry.value = file.readLong();
|
||||||
|
ret.add(entry);
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
file.seek(pos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
file.seek(pos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} else return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
private long getIndex(long offset) {
|
private long getIndex(long offset) {
|
||||||
if (offset < fileSize) {
|
if (offset < fileSize) {
|
||||||
try {
|
try {
|
||||||
@ -109,7 +142,7 @@ public class TimeSerialIndex {
|
|||||||
public synchronized long findNearest(long timeStamp) {
|
public synchronized long findNearest(long timeStamp) {
|
||||||
try {
|
try {
|
||||||
long pos = file.getFilePointer();
|
long pos = file.getFilePointer();
|
||||||
long ret = binarySearch(0L, fileSize + 1, timeStamp);
|
long ret = binarySearch(0L, fileSize, timeStamp);
|
||||||
file.seek(pos);
|
file.seek(pos);
|
||||||
return ret;
|
return ret;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -120,9 +153,14 @@ public class TimeSerialIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long binarySearch(long start, long end, long timeStamp) {
|
private long binarySearch(long start, long end, long timeStamp) {
|
||||||
if (start >= end - 1) return start;
|
if (end <= 0) return end;
|
||||||
|
if (start >= end - 1) {
|
||||||
|
long key = getIndex(end - 1);
|
||||||
|
if (key >= timeStamp) {
|
||||||
|
return end - 1;
|
||||||
|
} else return end;
|
||||||
|
}
|
||||||
long mid = (start + end) / 2;
|
long mid = (start + end) / 2;
|
||||||
if (mid >= end - 1) return mid;
|
|
||||||
long key = getIndex(mid);
|
long key = getIndex(mid);
|
||||||
if (key >= timeStamp) {
|
if (key >= timeStamp) {
|
||||||
return binarySearch(start, mid, timeStamp);
|
return binarySearch(start, mid, timeStamp);
|
||||||
|
51
src/test/java/org/bdware/MultiIndextTimeRocksDBUtilTest.java
Normal file
51
src/test/java/org/bdware/MultiIndextTimeRocksDBUtilTest.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package org.bdware;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.bdware.sc.db.MultiIndexTimeRocksDBUtil;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MultiIndextTimeRocksDBUtilTest {
|
||||||
|
static Logger LOGGER = LogManager.getLogger(MultiIndextTimeRocksDBUtilTest.class);
|
||||||
|
MultiIndexTimeRocksDBUtil util;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
util = new MultiIndexTimeRocksDBUtil("testoutput/timeIndexDB", "defaultTable");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void put() {
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
util.put("abc_123", "ddd " + System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listAll() {
|
||||||
|
List<JsonObject> tt = util.queryByOffset(null, 0, 100);
|
||||||
|
for (int i = 0; i < tt.size(); i++) {
|
||||||
|
long val = tt.get(i).get("timestamp").getAsLong();
|
||||||
|
LOGGER.info(String.format("pre %d cu %d suc %d", util.queryOffset("abc_123", val - 1L),
|
||||||
|
util.queryOffset("abc_123", val), util.queryOffset("abc_123", val + 1L), util.queryOffset("abc_123", val - 1L)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run() {
|
||||||
|
LOGGER.info(util.queryOffset("abc_123", 1641454140657L));
|
||||||
|
LOGGER.info(util.queryOffset("abc_123", 1641454140669L));
|
||||||
|
LOGGER.info(util.queryOffset("abc_123", 1641450028482L));
|
||||||
|
LOGGER.info(util.queryOffset("abc_123", 1641450028483L));
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,17 @@
|
|||||||
package org.bdware.sc;
|
package org.bdware.sc;
|
||||||
|
|
||||||
import org.bdware.bdledger.api.grpc.Client;
|
|
||||||
//import org.bdware.bdledger.api.grpc.pb.QueryOuterClass;
|
|
||||||
import org.bdware.bdledger.api.grpc.pb.QueryProto;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class LedgerUtilTest {
|
public class LedgerUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void query(){
|
public void query(){
|
||||||
String str = "0828c62576606e27ef8d079dea60cadd6eb03351";
|
// String str = "0828c62576606e27ef8d079dea60cadd6eb03351";
|
||||||
Client c = new Client("022.node.internetapi.cn",21121);
|
// Client c = new Client("022.node.internetapi.cn",21121);
|
||||||
QueryProto.GetTransactionByHashResponse syncResult = c.getTransactionByHashSync("default", "5c79fb8d71771615a5c8173b8089cd4841c3adfb");
|
// QueryProto.GetTransactionByHashResponse syncResult = c.getTransactionByHashSync("default", "5c79fb8d71771615a5c8173b8089cd4841c3adfb");
|
||||||
System.out.println(new String(syncResult.getTransaction().getData().toByteArray()));
|
// System.out.println(new String(syncResult.getTransaction().getData().toByteArray()));
|
||||||
System.out.println(syncResult.getTransaction().getData().toByteArray().length);
|
// System.out.println(syncResult.getTransaction().getData().toByteArray().length);
|
||||||
|
// 092:47.107.94.135
|
||||||
// 092:47.107.94.135
|
|
||||||
// 093:120.79.215.187
|
// 093:120.79.215.187
|
||||||
// QueryOuterClass.GetTransactionByHashResponse hash = c.getTransactionByHashSync("test", str);
|
// QueryOuterClass.GetTransactionByHashResponse hash = c.getTransactionByHashSync("test", str);
|
||||||
// String str2 = hash.getTransaction().getFrom().toStringUtf8();
|
// String str2 = hash.getTransaction().getFrom().toStringUtf8();
|
||||||
|
@ -10,7 +10,6 @@ import org.junit.Test;
|
|||||||
import org.zz.gmhelper.BCECUtil;
|
import org.zz.gmhelper.BCECUtil;
|
||||||
import org.zz.gmhelper.SM2KeyPair;
|
import org.zz.gmhelper.SM2KeyPair;
|
||||||
import org.zz.gmhelper.SM2Util;
|
import org.zz.gmhelper.SM2Util;
|
||||||
import sun.misc.BASE64Encoder;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
@ -25,8 +24,8 @@ public class SM2UtilTest {
|
|||||||
String gstr =
|
String gstr =
|
||||||
"09146332716e7767327923056946406e49570e5909146332716e7767327923056946406e49570e59";
|
"09146332716e7767327923056946406e49570e5909146332716e7767327923056946406e49570e59";
|
||||||
byte[] bytes = ByteUtils.fromHexString(gstr);
|
byte[] bytes = ByteUtils.fromHexString(gstr);
|
||||||
String str = new BASE64Encoder().encode(bytes);
|
// String str = new BASE64Encoder().encode(bytes);
|
||||||
System.out.println(str);
|
// System.out.println(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user