├── common ├── src │ ├── test │ │ ├── resources │ │ │ ├── log-console.json │ │ │ ├── log-sqlite.json │ │ │ └── log-file.json │ │ └── java │ │ │ └── cn │ │ │ └── zorcc │ │ │ └── common │ │ │ ├── serde │ │ │ ├── RecordBean.java │ │ │ ├── Bean.java │ │ │ ├── EnumBean.java │ │ │ └── GenerationContext.java │ │ │ ├── metrics │ │ │ └── MetricsTest.java │ │ │ ├── beans │ │ │ ├── Alpha.java │ │ │ ├── Book.java │ │ │ ├── Beta.java │ │ │ └── City.java │ │ │ ├── structure │ │ │ ├── IntHolderTest.java │ │ │ ├── MemApiTest.java │ │ │ ├── TaskQueueTest.java │ │ │ ├── AllocatorTest.java │ │ │ ├── RefTest.java │ │ │ └── IntMapTest.java │ │ │ ├── context │ │ │ ├── AllocatorTest.java │ │ │ ├── ContextTest.java │ │ │ └── MetaTest.java │ │ │ ├── log │ │ │ └── LogTest.java │ │ │ ├── jmh │ │ │ ├── TimeFormatTest.java │ │ │ ├── AtomicTest.java │ │ │ ├── ScopedValueTest.java │ │ │ ├── JmhTest.java │ │ │ ├── MemAccessTest.java │ │ │ └── CompressionTest.java │ │ │ ├── util │ │ │ ├── ResourcesLoadingTest.java │ │ │ └── VectorTest.java │ │ │ ├── json │ │ │ └── JsonTest.java │ │ │ └── network │ │ │ └── RefMapTest.java │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ └── javax.annotation.processing.Processor │ │ └── java │ │ └── cn │ │ └── zorcc │ │ └── common │ │ ├── serde │ │ ├── json │ │ │ ├── JsonKit.java │ │ │ ├── JsonNode.java │ │ │ └── JsonScope.java │ │ ├── Content.java │ │ ├── Serde.java │ │ ├── Accessor.java │ │ ├── Attr.java │ │ ├── RecursiveType.java │ │ ├── Handle.java │ │ ├── Column.java │ │ ├── CodeBlock.java │ │ └── SerdeContext.java │ │ ├── log │ │ ├── LogEventType.java │ │ ├── LogLevel.java │ │ ├── LogHandler.java │ │ ├── TimeResolver.java │ │ ├── MetricsLogEventHandler.java │ │ ├── LogEvent.java │ │ ├── FileLogConfig.java │ │ ├── SqliteLogConfig.java │ │ ├── DefaultTimeResolver.java │ │ └── ConsoleLogConfig.java │ │ ├── access │ │ ├── Getter.java │ │ ├── Access.java │ │ ├── Setter.java │ │ ├── ClassSetter.java │ │ ├── RecordSetter.java │ │ ├── RecordLambdaAccess.java │ │ └── ClassLambdaAccess.java │ │ ├── network │ │ ├── IpType.java │ │ ├── TagMsg.java │ │ ├── SocketAndLoc.java │ │ ├── PollerTask.java │ │ ├── MuxEvent.java │ │ ├── ProtocolWithMutex.java │ │ ├── WriterTask.java │ │ ├── TagWithRef.java │ │ ├── ListenerTask.java │ │ ├── Encoder.java │ │ ├── PollerTaskType.java │ │ ├── WriterTaskType.java │ │ ├── Decoder.java │ │ ├── Loc.java │ │ ├── Socket.java │ │ ├── Mux.java │ │ ├── WriterCallback.java │ │ ├── SocketConfig.java │ │ ├── Handler.java │ │ └── ListenerConfig.java │ │ ├── postgre │ │ ├── PgManager.java │ │ ├── PgStatus.java │ │ ├── PgMsg.java │ │ ├── PgPool.java │ │ ├── PgRowDescription.java │ │ ├── PgDecoder.java │ │ ├── PgEncoder.java │ │ ├── PgMapper.java │ │ ├── PgConfig.java │ │ └── PgProvider.java │ │ ├── sqlite │ │ ├── SqliteMsgType.java │ │ ├── SqliteMetadata.java │ │ ├── SqliteConstants.java │ │ └── SqliteConfig.java │ │ ├── PeerType.java │ │ ├── rpc │ │ ├── RpcMsg.java │ │ ├── RpcEncoder.java │ │ └── RpcDecoder.java │ │ ├── OsType.java │ │ ├── http │ │ ├── HttpMethod.java │ │ ├── HttpCompressionStatus.java │ │ ├── HttpRequest.java │ │ └── HttpResponse.java │ │ ├── structure │ │ ├── ReadBufferSnapshot.java │ │ ├── MemApi.java │ │ └── TaskQueue.java │ │ ├── OldPair.java │ │ ├── database │ │ ├── Page.java │ │ ├── Col.java │ │ ├── Del.java │ │ ├── Filler.java │ │ ├── Table.java │ │ ├── Id.java │ │ ├── Where.java │ │ ├── Base.java │ │ └── Mapper.java │ │ ├── Ordinal.java │ │ ├── RecordInfo.java │ │ ├── exception │ │ ├── AnnoException.java │ │ ├── JsonParseException.java │ │ ├── ServiceException.java │ │ └── FrameworkException.java │ │ ├── ExceptionType.java │ │ ├── Peer.java │ │ ├── metrics │ │ ├── CpuLoadAverage.java │ │ └── Metrics.java │ │ ├── MetaInfo.java │ │ ├── duckdb │ │ ├── DuckdbConfig.java │ │ └── DuckdbConn.java │ │ ├── Format.java │ │ ├── LifeCycle.java │ │ ├── LaunchTest.java │ │ ├── ContextListener.java │ │ ├── Clock.java │ │ ├── DefaultContextListener.java │ │ ├── AbstractLifeCycle.java │ │ ├── json │ │ ├── JsonTypeRef.java │ │ ├── JsonWriterCollectionNode.java │ │ ├── JsonWriterMapNode.java │ │ ├── JsonWriterObjectNode.java │ │ └── JsonWriterRecordNode.java │ │ ├── Seq.java │ │ ├── util │ │ ├── SqlUtil.java │ │ └── ConfigUtil.java │ │ └── bindings │ │ └── SystemBinding.java └── pom.xml ├── mint ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ └── cn.zorcc.common.ContextListener │ │ └── java │ │ └── cn │ │ └── zorcc │ │ └── mint │ │ ├── DiscoveryManager.java │ │ └── MintContextListener.java └── pom.xml ├── gateway ├── src │ └── main │ │ └── java │ │ └── cn │ │ └── zorcc │ │ └── gateway │ │ └── Gateway.java └── pom.xml ├── orm ├── src │ └── main │ │ └── java │ │ └── cn │ │ └── zorcc │ │ └── orm │ │ ├── core │ │ ├── PgBindMsg.java │ │ ├── PgCloseMsg.java │ │ ├── PgParseCompleteMsg.java │ │ ├── PgCommand.java │ │ ├── PgErrorResponseMsg.java │ │ ├── PgHandler.java │ │ ├── PgManager.java │ │ ├── PgVariable.java │ │ └── PgDataType.java │ │ ├── frontend │ │ ├── PgQueryMsg.java │ │ ├── PgPasswordMsg.java │ │ ├── PgAuthSaslResponseMsg.java │ │ ├── PgSyncMsg.java │ │ ├── PgFlushMsg.java │ │ ├── PgTerminateMsg.java │ │ ├── PgStartUpMsg.java │ │ ├── PgParseMsg.java │ │ ├── PgAuthSaslInitialResponseMsg.java │ │ ├── PgDescribeMsg.java │ │ └── PgExecuteMsg.java │ │ └── backend │ │ ├── PgAuthMd5Msg.java │ │ ├── PgCommandCompleteMsg.java │ │ ├── PgAuthSaslFinalMsg.java │ │ ├── PgAuthSaslContinueMsg.java │ │ ├── PgAuthOkMsg.java │ │ ├── PgNoDataMsg.java │ │ ├── PgParameterStatusMsg.java │ │ ├── PgAuthSaslPwdMsg.java │ │ ├── PgBackendKeyDataMsg.java │ │ ├── PgReadyMsg.java │ │ ├── PgAuthClearPwdMsg.java │ │ ├── PgBindCompleteMsg.java │ │ ├── PgCloseCompleteMsg.java │ │ ├── PgDataRowMsg.java │ │ ├── PgEmptyQueryResponseMsg.java │ │ ├── PgRowDescriptionMsg.java │ │ └── PgStatusResponseMsg.java └── pom.xml ├── app ├── src │ └── main │ │ └── java │ │ └── cn │ │ └── zorcc │ │ └── app │ │ └── http │ │ ├── AppHttpMapping.java │ │ ├── anno │ │ ├── Body.java │ │ ├── Req.java │ │ ├── Patch.java │ │ ├── Put.java │ │ ├── Get.java │ │ ├── Post.java │ │ ├── Delete.java │ │ ├── PathVariable.java │ │ ├── HttpMapping.java │ │ ├── Param.java │ │ └── Header.java │ │ ├── AppHttpEvent.java │ │ └── UrlTreeNode.java └── pom.xml ├── .gitignore ├── http ├── src │ └── main │ │ └── java │ │ └── cn │ │ └── zorcc │ │ └── http │ │ ├── HttpEvent.java │ │ ├── WebSocketEvent.java │ │ ├── HttpTools.java │ │ └── HttpConfig.java └── pom.xml ├── json.md ├── network-model.md └── README.md /common/src/test/resources/log-console.json: -------------------------------------------------------------------------------- 1 | { 2 | "console" : { 3 | 4 | } 5 | } -------------------------------------------------------------------------------- /common/src/test/resources/log-sqlite.json: -------------------------------------------------------------------------------- 1 | { 2 | "sqlite" : { 3 | 4 | } 5 | } -------------------------------------------------------------------------------- /common/src/test/resources/log-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "file" : { 3 | "dir" : "C:/workspace/logs" 4 | } 5 | } -------------------------------------------------------------------------------- /mint/src/main/resources/META-INF/services/cn.zorcc.common.ContextListener: -------------------------------------------------------------------------------- 1 | cn.zorcc.mint.MintContextListener -------------------------------------------------------------------------------- /common/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | cn.zorcc.common.serde.SerdeProcessor -------------------------------------------------------------------------------- /gateway/src/main/java/cn/zorcc/gateway/Gateway.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.gateway; 2 | 3 | public class Gateway { 4 | } 5 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgBindMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | public class PgBindMsg { 4 | } 5 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgCloseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | public record PgCloseMsg() { 4 | } 5 | -------------------------------------------------------------------------------- /mint/src/main/java/cn/zorcc/mint/DiscoveryManager.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.mint; 2 | 3 | public final class DiscoveryManager { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/json/JsonKit.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde.json; 2 | 3 | public final class JsonKit { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/json/JsonNode.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde.json; 2 | 3 | public interface JsonNode { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/json/JsonScope.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde.json; 2 | 3 | public final class JsonScope { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgQueryMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgQueryMsg( 4 | String sql 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgAuthMd5Msg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgAuthMd5Msg( 4 | byte[] salt 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgPasswordMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgPasswordMsg( 4 | String password 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/LogEventType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | public enum LogEventType { 4 | Msg, 5 | Flush, 6 | Shutdown 7 | } 8 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgCommandCompleteMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgCommandCompleteMsg( 4 | String tag 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgAuthSaslFinalMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgAuthSaslFinalMsg( 4 | String serverFinalMsg 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgAuthSaslContinueMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgAuthSaslContinueMsg( 4 | String serverFirstMsg 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/Getter.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public interface Getter extends Iterable { 4 | Object getValue(String key); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgAuthSaslResponseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgAuthSaslResponseMsg( 4 | String clientFinalMsg 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgSyncMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgSyncMsg() { 4 | public static final PgSyncMsg INSTANCE = new PgSyncMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgFlushMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgFlushMsg() { 4 | public static final PgFlushMsg INSTANCE = new PgFlushMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/Access.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public interface Access { 4 | Setter createSetter(); 5 | 6 | Getter createGetter(); 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/LogLevel.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | public enum LogLevel { 4 | DEBUG, 5 | TRACE, 6 | INFO, 7 | WARN, 8 | ERROR 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgAuthOkMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgAuthOkMsg() { 4 | public static final PgAuthOkMsg INSTANCE = new PgAuthOkMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgNoDataMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgNoDataMsg() { 4 | public static final PgNoDataMsg INSTANCE = new PgNoDataMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgParameterStatusMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgParameterStatusMsg( 4 | String key, 5 | String value 6 | ) { 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/Setter.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public interface Setter { 4 | void setValue(String key, Object value); 5 | 6 | T construct(); 7 | } 8 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgAuthSaslPwdMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | import java.util.List; 4 | 5 | public record PgAuthSaslPwdMsg( 6 | List mechanisms 7 | ) { 8 | } 9 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgBackendKeyDataMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgBackendKeyDataMsg( 4 | int processId, 5 | int secretKey 6 | ) { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgReadyMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | import cn.zorcc.common.postgre.PgStatus; 4 | 5 | public record PgReadyMsg( 6 | PgStatus status 7 | ) { 8 | } 9 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgTerminateMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgTerminateMsg() { 4 | public static final PgTerminateMsg INSTANCE = new PgTerminateMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/IpType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * IP type enum, currently IPV4 or IPV6 5 | */ 6 | public enum IpType { 7 | IPV4, 8 | IPV6 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgAuthClearPwdMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgAuthClearPwdMsg() { 4 | public static final PgAuthClearPwdMsg INSTANCE = new PgAuthClearPwdMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgBindCompleteMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgBindCompleteMsg() { 4 | public static final PgBindCompleteMsg INSTANCE = new PgBindCompleteMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgParseCompleteMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | public record PgParseCompleteMsg() { 4 | public static final PgParseCompleteMsg INSTANCE = new PgParseCompleteMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgStartUpMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | import cn.zorcc.orm.PgConfig; 4 | 5 | public record PgStartUpMsg( 6 | PgConfig pgConfig 7 | ) { 8 | 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgCloseCompleteMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgCloseCompleteMsg() { 4 | public static final PgCloseCompleteMsg INSTANCE = new PgCloseCompleteMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgParseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgParseMsg( 4 | String name, 5 | String sql, 6 | short len, 7 | int[] objectIds 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgDataRowMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | import java.util.List; 4 | 5 | public record PgDataRowMsg( 6 | short len, 7 | List data 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgCommand.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | /** 4 | * Postgresql send command, see PgCodec for concrete implementation 5 | */ 6 | public enum PgCommand { 7 | SSL, 8 | 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgAuthSaslInitialResponseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | public record PgAuthSaslInitialResponseMsg( 4 | String mechanism, 5 | String clientFirstMsg 6 | ) { 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/TagMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | 5 | public record TagMsg( 6 | MemorySegment tag, 7 | Object msg 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgManager.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | public final class PgManager { 4 | private final PgPool pool = new PgPool(); 5 | 6 | public PgManager() { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/sqlite/SqliteMsgType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.sqlite; 2 | 3 | public enum SqliteMsgType { 4 | Insert_Discovery, 5 | Select_Discovery, 6 | Delete_Discovery, 7 | 8 | Shutdown 9 | } 10 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgEmptyQueryResponseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | public record PgEmptyQueryResponseMsg() { 4 | public static final PgEmptyQueryResponseMsg INSTANCE = new PgEmptyQueryResponseMsg(); 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/PeerType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | /** 4 | * 节点类型 5 | */ 6 | public enum PeerType { 7 | App, 8 | 9 | Gateway, 10 | 11 | Mint, 12 | 13 | Metrics, 14 | 15 | Mq, 16 | } 17 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/serde/RecordBean.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | @Serde 4 | public record RecordBean( 5 | @Attr(values = {"default:2", "json:str"}) 6 | int a, 7 | String b 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/LogHandler.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import cn.zorcc.common.structure.WriteBuffer; 4 | 5 | @FunctionalInterface 6 | public interface LogHandler { 7 | void process(WriteBuffer buffer, LogEvent event); 8 | } 9 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/SocketAndLoc.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * Used as message for accept() return 5 | */ 6 | public record SocketAndLoc( 7 | Socket socket, 8 | Loc loc 9 | ) { 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/rpc/RpcMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.rpc; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | 5 | public record RpcMsg( 6 | int msgType, 7 | int len, 8 | MemorySegment data 9 | ) { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/Content.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | /** 4 | * Represents a line of source code with indent 5 | */ 6 | public record Content( 7 | String value, 8 | int indent 9 | ) { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgErrorResponseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | import cn.zorcc.common.OldPair; 4 | 5 | import java.util.List; 6 | 7 | public record PgErrorResponseMsg( 8 | List> items 9 | ) { 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/OsType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | /** 4 | * Operating system enums, currently supporting Windows, Linux and macOS 5 | */ 6 | public enum OsType { 7 | Windows, 8 | Linux, 9 | MacOS, 10 | Unknown 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgStatus.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | /** 4 | * Postgresql transaction status code 5 | */ 6 | public enum PgStatus { 7 | UNSET, 8 | IDLE, 9 | TRANSACTION_ON, 10 | TRANSACTION_FAIL 11 | } 12 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgRowDescriptionMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | import cn.zorcc.common.postgre.PgRowDescription; 4 | 5 | public record PgRowDescriptionMsg( 6 | short len, 7 | PgRowDescription[] descriptions 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/AppHttpMapping.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http; 2 | 3 | /** 4 | * App HttpMapping接口 5 | */ 6 | public interface AppHttpMapping { 7 | /** 8 | * 注册Http映射实现类 9 | */ 10 | void registerHttpMapping(Object impl); 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/PollerTask.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * Used as poller msg 5 | */ 6 | public record PollerTask( 7 | PollerTaskType type, 8 | Channel channel, 9 | Object msg 10 | ) { 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/http/HttpMethod.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.http; 2 | 3 | /** 4 | * Enum for normally used Http methods 5 | */ 6 | public enum HttpMethod { 7 | Get, 8 | Post, 9 | Put, 10 | Delete, 11 | Patch, 12 | Options 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/structure/ReadBufferSnapshot.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | 5 | public record ReadBufferSnapshot( 6 | MemorySegment segment, 7 | long currentIndex 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/sqlite/SqliteMetadata.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.sqlite; 2 | 3 | public record SqliteMetadata( 4 | String type, 5 | String name, 6 | String tblName, 7 | Integer rootPage, 8 | String sql 9 | ) { 10 | } 11 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/OldPair.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | /** 4 | * TODO refactor 5 | */ 6 | public record OldPair(K k, V v) { 7 | 8 | public static OldPair of(T1 t1, T2 t2) { 9 | return new OldPair<>(t1, t2); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Body.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * http body参数 7 | */ 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface Body { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Req.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 标识该参数为HttpReq 7 | */ 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface Req { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/MuxEvent.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * MuxEvent is a data representation for MuxWait result 5 | * TODO value-based record 6 | */ 7 | public record MuxEvent( 8 | int socket, 9 | int event 10 | ) { 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Patch.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Target({ElementType.METHOD}) 6 | @Retention(RetentionPolicy.RUNTIME) 7 | @Documented 8 | @Inherited 9 | public @interface Patch { 10 | String path() default ""; 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/ProtocolWithMutex.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.structure.Mutex; 4 | 5 | /** 6 | * Used as writer message 7 | */ 8 | public record ProtocolWithMutex( 9 | Protocol protocol, 10 | Mutex mutex 11 | ) { 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | 5 | /** 6 | * Representing a postgresql client-server communicating msg 7 | */ 8 | public record PgMsg( 9 | byte type, 10 | MemorySegment data 11 | ) { 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/WriterTask.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * Used as writer message 5 | */ 6 | public record WriterTask( 7 | WriterTaskType type, 8 | Channel channel, 9 | Object msg, 10 | WriterCallback writerCallback 11 | ) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Put.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * http put请求 7 | */ 8 | @Target({ElementType.METHOD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | @Inherited 12 | public @interface Put { 13 | String path() default ""; 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Page.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Page record from database 7 | */ 8 | public record Page( 9 | long pageNo, 10 | long pageSize, 11 | long totalPage, 12 | long total, 13 | List data 14 | ) { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Get.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | 4 | import java.lang.annotation.*; 5 | 6 | /** 7 | * http get请求 8 | */ 9 | @Target({ElementType.METHOD}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | @Inherited 13 | public @interface Get { 14 | String path() default ""; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Post.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * http post请求 7 | */ 8 | @Target({ElementType.METHOD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | @Inherited 12 | public @interface Post { 13 | String path() default ""; 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Delete.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * http delete请求 7 | */ 8 | @Target({ElementType.METHOD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | @Inherited 12 | public @interface Delete { 13 | String path() default ""; 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/rpc/RpcEncoder.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.rpc; 2 | 3 | import cn.zorcc.common.network.Encoder; 4 | import cn.zorcc.common.structure.WriteBuffer; 5 | 6 | public final class RpcEncoder implements Encoder { 7 | @Override 8 | public void encode(WriteBuffer writeBuffer, Object o) { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/Ordinal.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * Annotation used for determining field sequence 7 | */ 8 | @Target({ElementType.FIELD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface Ordinal { 12 | int sequence() default 0; 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/ClassSetter.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public record ClassSetter( 4 | 5 | ) implements Setter { 6 | @Override 7 | public void setValue(String key, Object value) { 8 | 9 | } 10 | 11 | @Override 12 | public T construct() { 13 | return null; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/RecordSetter.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public record RecordSetter( 4 | 5 | ) implements Setter { 6 | @Override 7 | public void setValue(String key, Object value) { 8 | 9 | } 10 | 11 | @Override 12 | public T construct() { 13 | return null; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/Serde.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * Mark a class as serialization and deserialization compatible 7 | */ 8 | @Target({ElementType.TYPE}) 9 | @Retention(RetentionPolicy.SOURCE) 10 | @Inherited 11 | @Documented 12 | public @interface Serde { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/backend/PgStatusResponseMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.backend; 2 | 3 | import cn.zorcc.common.OldPair; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Could be NoticeResponse or ErrorResponse 9 | */ 10 | public record PgStatusResponseMsg( 11 | boolean isErr, 12 | List> items 13 | ) { 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/RecordInfo.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.function.Function; 5 | 6 | public record RecordInfo( 7 | String fieldName, 8 | Class fieldClass, 9 | Type genericType, 10 | Function getter, 11 | Format format 12 | ) { 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/RecordLambdaAccess.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public class RecordLambdaAccess implements Access { 4 | @Override 5 | public Setter createSetter() { 6 | return null; 7 | } 8 | 9 | @Override 10 | public Getter createGetter() { 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/exception/AnnoException.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.exception; 2 | 3 | 4 | /** 5 | * A dedicated exception to describe what's wrong during the compilation phase 6 | */ 7 | public final class AnnoException extends RuntimeException { 8 | public AnnoException(final String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/http/HttpCompressionStatus.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.http; 2 | 3 | /** 4 | * HttpCompressionStatus is an enum used in HttpResponse for the HttpEncoder to decide whether the content should be compressed 5 | */ 6 | public enum HttpCompressionStatus { 7 | NONE, 8 | GZIP, 9 | DEFLATE, 10 | BROTLI, 11 | ZSTD 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/TagWithRef.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.Ref; 4 | 5 | import java.lang.foreign.MemorySegment; 6 | 7 | public record TagWithRef( 8 | MemorySegment tag, 9 | Ref ref 10 | ) { 11 | public TagWithRef(MemorySegment tag) { 12 | this(tag, new Ref()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/ExceptionType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | public enum ExceptionType { 4 | ANNO, 5 | NATIVE, 6 | WHEEL, 7 | CONTEXT, 8 | CONFIG, 9 | HTTP, 10 | JSON, 11 | SQLITE, 12 | DUCKDB, 13 | NETWORK, 14 | SQL, 15 | POSTGRESQL, 16 | CLUSTER, 17 | AUTH, 18 | FILE, 19 | LOG, 20 | COMPRESS, 21 | MINT 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/Peer.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import cn.zorcc.common.network.Loc; 4 | 5 | /** 6 | * Peer represents a running node's information about it's Net server 7 | */ 8 | public record Peer( 9 | Long appId, 10 | Long nodeId, 11 | Loc loc, 12 | Integer weight, 13 | Long createdAt, 14 | Long modifiedAt 15 | ) { 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/PathVariable.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * http 路径参数 7 | */ 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface PathVariable { 12 | /** 13 | * 是否必须,在缺失时会抛出ServiceException异常 14 | */ 15 | boolean required() default false; 16 | } 17 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/metrics/MetricsTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.metrics; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.lang.foreign.Arena; 6 | 7 | public class MetricsTest { 8 | @Test 9 | public void testLoadAverage() { 10 | try(Arena arena = Arena.ofConfined()) { 11 | System.out.println(Metrics.getLoadAverage(arena)); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Col.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Target({ElementType.FIELD}) 6 | @Retention(RetentionPolicy.RUNTIME) 7 | @Documented 8 | public @interface Col { 9 | 10 | /** 11 | * Column value 12 | */ 13 | String value(); 14 | /** 15 | * Column ordinal 16 | */ 17 | int ordinal() default 0; 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Del.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Target({ElementType.FIELD}) 6 | @Retention(RetentionPolicy.RUNTIME) 7 | @Documented 8 | public @interface Del { 9 | 10 | /** 11 | * Column value 12 | */ 13 | String value(); 14 | /** 15 | * Column ordinal 16 | */ 17 | int ordinal() default 0; 18 | } 19 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/beans/Alpha.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.beans; 2 | 3 | import java.util.List; 4 | 5 | public record Alpha( 6 | int primitiveInt, 7 | Integer normalInt, 8 | int[] intArray, 9 | Integer[] integerArray, 10 | String str, 11 | List list, 12 | List intArrayList, 13 | List integerArrayList 14 | ) { 15 | } 16 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/structure/IntHolderTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | public class IntHolderTest { 6 | @Test 7 | public void testIntHolderLock() { 8 | IntHolder holder = new IntHolder(0); 9 | holder.transform(i -> i + 1, Thread::onSpinWait); 10 | System.out.println(holder.getVolatileValue()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/access/ClassLambdaAccess.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.access; 2 | 3 | public class ClassLambdaAccess implements Access { 4 | public ClassLambdaAccess(Class clazz) { 5 | 6 | } 7 | 8 | @Override 9 | public Setter createSetter() { 10 | return null; 11 | } 12 | 13 | @Override 14 | public Getter createGetter() { 15 | return null; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Filler.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | /** 4 | * Define auto filler operation when using Mapper 5 | */ 6 | public interface Filler { 7 | /** 8 | * Auto filler operation applied when performing insert 9 | */ 10 | void onInsert(); 11 | 12 | /** 13 | * Auto filler operation applied when performing update 14 | */ 15 | void onUpdate(); 16 | } 17 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgDescribeMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | /** 4 | * 5 | * @param type 'S' to describe a prepared statement; or 'P' to describe a portal. 6 | * @param name The name of the prepared statement or portal to describe (an empty string selects the unnamed prepared statement or portal). 7 | */ 8 | public record PgDescribeMsg( 9 | byte type, 10 | String name 11 | ) { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/HttpMapping.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * http请求响应类 9 | */ 10 | @Target({ElementType.TYPE}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | @Inherited 14 | public @interface HttpMapping { 15 | /** 16 | * http url前缀 17 | */ 18 | String prefix() default Constants.EMPTY_STRING; 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgPool.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import cn.zorcc.common.network.Channel; 4 | 5 | import java.util.ArrayDeque; 6 | import java.util.Deque; 7 | import java.util.concurrent.locks.Lock; 8 | import java.util.concurrent.locks.ReentrantLock; 9 | 10 | public final class PgPool { 11 | private final Lock lock = new ReentrantLock(); 12 | private final Deque deque = new ArrayDeque<>(); 13 | } 14 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/frontend/PgExecuteMsg.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.frontend; 2 | 3 | /** 4 | * 5 | * @param portal The name of the portal to execute (an empty string selects the unnamed portal). 6 | * @param maxRowsToReturn Maximum number of rows to return, if portal contains a query that returns rows (ignored otherwise). Zero denotes “no limit”. 7 | */ 8 | public record PgExecuteMsg( 9 | String portal, 10 | int maxRowsToReturn 11 | ) { 12 | } 13 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Table.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | import java.lang.annotation.*; 6 | 7 | @Target({ElementType.TYPE}) 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Documented 10 | public @interface Table { 11 | /** 12 | * The table name in the database, should be a string with underline separated 13 | */ 14 | String name() default Constants.EMPTY_STRING; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Param.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 解析http占位符参数 7 | */ 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface Param { 12 | /** 13 | * 参数值 14 | */ 15 | String value() default ""; 16 | /** 17 | * 是否必须,在缺失时会抛出ServiceException异常 18 | */ 19 | boolean required() default false; 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/TimeResolver.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | import java.time.LocalDateTime; 5 | 6 | /** 7 | * Log time to bytes resolver, offering a better alternative to DateTimeFormatter 8 | * Implement this interface to provide a time-resolver with better performance 9 | */ 10 | @FunctionalInterface 11 | public interface TimeResolver { 12 | MemorySegment format(LocalDateTime time); 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/metrics/CpuLoadAverage.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.metrics; 2 | 3 | /** 4 | * l1 represents average load for last 1 minute 5 | * l2 represents average load for last 5 minute 6 | * l3 represents average load for last 15 minute 7 | */ 8 | public record CpuLoadAverage( 9 | double l1, 10 | double l2, 11 | double l3 12 | ) { 13 | public static final CpuLoadAverage UNSUPPORTED = new CpuLoadAverage(-1d, -1d, -1d); 14 | } 15 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/MetricsLogEventHandler.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * Print log to the remote metrics server 7 | * TODO not implemented yet 8 | */ 9 | public final class MetricsLogEventHandler implements Consumer { 10 | public MetricsLogEventHandler(LogConfig logConfig) { 11 | 12 | } 13 | 14 | @Override 15 | public void accept(LogEvent event) { 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/anno/Header.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http.anno; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 解析http请求头参数 7 | */ 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | public @interface Header { 12 | /** 13 | * Http Header的key值 14 | */ 15 | String value() default ""; 16 | /** 17 | * 是否必须,在缺失时会抛出ServiceException异常 18 | */ 19 | boolean required() default false; 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/ListenerTask.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * Used as message for net thread 7 | */ 8 | public record ListenerTask( 9 | Supplier encoderSupplier, 10 | Supplier decoderSupplier, 11 | Supplier handlerSupplier, 12 | Provider provider, 13 | Loc loc, 14 | Socket socket, 15 | SocketConfig socketConfig 16 | ) { 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgRowDescription.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | /** 4 | * Corresponding to RowDescription in the documentation postgresql message format 5 | */ 6 | public record PgRowDescription( 7 | String fieldName, 8 | int tableOid, 9 | short attr, 10 | int fieldOid, 11 | short typeSize, 12 | int modifier, 13 | short format 14 | ) { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/Accessor.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | 5 | /** 6 | * This record is used in source code generation, all the variable names and functions shouldn't be renamed 7 | */ 8 | public record Accessor ( 9 | MethodHandle getter, 10 | MethodHandle setter, 11 | Column column 12 | ) { 13 | public Accessor(MethodHandle getAccessor, Column column) { 14 | this(getAccessor, null, column); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/serde/Bean.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | @Serde 4 | public class Bean { 5 | @Attr(values = {"default:1", "json:str"}) 6 | private int a; 7 | 8 | // test without attr 9 | private String b; 10 | 11 | public int getA() { 12 | return a; 13 | } 14 | 15 | public void setA(int a) { 16 | this.a = a; 17 | } 18 | 19 | public String getB() { 20 | return b; 21 | } 22 | 23 | public void setB(String b) { 24 | this.b = b; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/serde/EnumBean.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | @Serde 4 | public enum EnumBean { 5 | 6 | Test1(123, "hello"), 7 | Test2(234, "world"); 8 | 9 | @Attr(values = {"default:3", "json:str"}) 10 | private final int a; 11 | private final String b; 12 | 13 | EnumBean(int a, String b) { 14 | this.a = a; 15 | this.b = b; 16 | } 17 | 18 | public int getA() { 19 | return a; 20 | } 21 | 22 | public String getB() { 23 | return b; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Id.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Target({ElementType.FIELD}) 6 | @Retention(RetentionPolicy.RUNTIME) 7 | @Documented 8 | public @interface Id { 9 | /** 10 | * Whether the table 'id' column was auto generated by the database 11 | */ 12 | boolean auto() default true; 13 | 14 | /** 15 | * Column value 16 | */ 17 | String value() default "id"; 18 | 19 | /** 20 | * Column ordinal 21 | */ 22 | int ordinal() default 0; 23 | } 24 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/Attr.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * This annotation is only useful when used on class/record/enum fields with @Serde annotated to provide metadata information without using reflection 7 | */ 8 | @Target({ElementType.FIELD}) 9 | @Retention(RetentionPolicy.SOURCE) 10 | @Inherited 11 | @Documented 12 | public @interface Attr { 13 | /** 14 | * Attribute values, should be separated by ':', for example "json:str" 15 | */ 16 | String[] values() default {}; 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Java template 2 | # Compiled class file 3 | *.class 4 | 5 | # Log file 6 | *.entry 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.nar 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | #idea 27 | .idea/* 28 | */target/* 29 | 30 | #vscode 31 | */.vscode/* 32 | 33 | #log files 34 | *.log 35 | *.db 36 | 37 | #macOS 38 | *.DS_Store 39 | 40 | #JMH tests 41 | *.txt 42 | 43 | -------------------------------------------------------------------------------- /mint/src/main/java/cn/zorcc/mint/MintContextListener.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.mint; 2 | 3 | import cn.zorcc.common.ContextListener; 4 | 5 | public final class MintContextListener implements ContextListener { 6 | 7 | @Override 8 | public void beforeStarted() { 9 | 10 | } 11 | 12 | @Override 13 | public void onLoaded(Object target, Class type) { 14 | // TODO 15 | } 16 | 17 | @Override 18 | public T onRequested(Class type) { 19 | // TODO 20 | return null; 21 | } 22 | 23 | @Override 24 | public void afterStarted() { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/context/AllocatorTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.context; 2 | 3 | import cn.zorcc.common.structure.Allocator; 4 | import cn.zorcc.common.structure.MemApi; 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.lang.foreign.MemorySegment; 9 | 10 | public class AllocatorTest { 11 | @Test 12 | public void testAllocator() { 13 | try(Allocator allocator = Allocator.newDirectAllocator(MemApi.DEFAULT)) { 14 | MemorySegment abc = allocator.allocateFrom("abc"); 15 | Assertions.assertEquals(abc.byteSize(), 4); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/structure/MemApiTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.lang.foreign.MemorySegment; 7 | 8 | public class MemApiTest { 9 | @Test 10 | public void testDefaultMemApi() { 11 | MemorySegment memorySegment = MemApi.DEFAULT.allocateMemory(8L).reinterpret(8L); 12 | try{ 13 | Assertions.assertEquals(memorySegment.byteSize(), 8L); 14 | Assertions.assertTrue(memorySegment.isNative()); 15 | }finally { 16 | MemApi.DEFAULT.freeMemory(memorySegment); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/MetaInfo.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.function.BiConsumer; 5 | import java.util.function.Function; 6 | 7 | public record MetaInfo( 8 | String fieldName, 9 | Class fieldClass, 10 | Type genericType, 11 | Function getter, 12 | BiConsumer setter, 13 | Format format 14 | ) { 15 | 16 | public Object invokeGetter(Object target) { 17 | return getter.apply(target); 18 | } 19 | 20 | public void invokeSetter(Object target, Object field) { 21 | setter.accept(target, field); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/duckdb/DuckdbConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.duckdb; 2 | 3 | import java.util.Map; 4 | 5 | public final class DuckdbConfig { 6 | private Map options; 7 | private String path; 8 | 9 | public Map getOptions() { 10 | return options; 11 | } 12 | 13 | public DuckdbConfig setOptions(Map options) { 14 | this.options = options; 15 | return this; 16 | } 17 | 18 | public String getPath() { 19 | return path; 20 | } 21 | 22 | public DuckdbConfig setPath(String path) { 23 | this.path = path; 24 | return this; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/log/LogTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import cn.zorcc.common.Context; 4 | import org.junit.jupiter.api.Test; 5 | 6 | public class LogTest { 7 | private static final Logger log = new Logger(LogTest.class); 8 | 9 | @Test 10 | public void testLogWithException() { 11 | Context.init(); 12 | for(int i = 0; i < 10; i++) { 13 | log.error("test exception", new RuntimeException()); 14 | } 15 | } 16 | 17 | @Test 18 | public void testLog() { 19 | Context.init(); 20 | for(int i = 0; i < 50; i++) { 21 | log.info(STR."hello , \{i}"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/Format.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * Annotation for helping determine serialization format 7 | * When the @Format annotation is applied to an array or Collection, it will be applied to all the elements. 8 | */ 9 | @Target({ElementType.FIELD}) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Documented 12 | public @interface Format { 13 | /** 14 | * Expected serialization type 15 | */ 16 | Class expectedType() default Void.class; 17 | 18 | /** 19 | * Expected serialization string pattern 20 | */ 21 | String expectedPattern() default Constants.EMPTY_STRING; 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/exception/JsonParseException.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.exception; 2 | 3 | import cn.zorcc.common.Format; 4 | import cn.zorcc.common.structure.ReadBuffer; 5 | 6 | public final class JsonParseException extends RuntimeException { 7 | public JsonParseException(String errMsg) { 8 | super(errMsg); 9 | } 10 | 11 | public JsonParseException(ReadBuffer readBuffer) { 12 | super(STR."Failed to parse json, content : \{readBuffer}, index : \{readBuffer.currentIndex()}"); 13 | } 14 | 15 | public JsonParseException(Format format, Object value) { 16 | super(STR."Failed to parse target format : \{format}, value : \{value}"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/duckdb/DuckdbConn.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.duckdb; 2 | 3 | import cn.zorcc.common.ExceptionType; 4 | import cn.zorcc.common.exception.FrameworkException; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * DuckDB connection implementation 10 | */ 11 | public final class DuckdbConn { 12 | 13 | public DuckdbConn(DuckdbConfig config) { 14 | String path = config.getPath(); 15 | if(path == null || path.isBlank()) { 16 | throw new FrameworkException(ExceptionType.DUCKDB, "Empty path detected"); 17 | } 18 | Map options = config.getOptions(); 19 | if(options == null || options.isEmpty()) { 20 | 21 | }else { 22 | 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/LogEvent.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | 5 | public record LogEvent ( 6 | LogEventType eventType, 7 | long timestamp, 8 | MemorySegment time, 9 | MemorySegment level, 10 | MemorySegment threadName, 11 | MemorySegment className, 12 | MemorySegment throwable, 13 | MemorySegment msg 14 | ){ 15 | public static final LogEvent FLUSH_EVENT = of(LogEventType.Flush); 16 | public static final LogEvent SHUTDOWN_EVENT = of(LogEventType.Shutdown); 17 | private static LogEvent of(LogEventType type) { 18 | return new LogEvent(type, Long.MIN_VALUE, null, null, null, null, null, null); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/RecursiveType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Representing class with generic type information recursively, this class shouldn't be renamed as it's used in source code generation 11 | */ 12 | public record RecursiveType( 13 | Class currentClass, 14 | List recursiveTypes 15 | ) { 16 | public RecursiveType { 17 | if(currentClass == null || recursiveTypes == null) { 18 | throw new FrameworkException(ExceptionType.ANNO, Constants.UNREACHED); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/LifeCycle.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import cn.zorcc.common.exception.FrameworkException; 4 | 5 | /** 6 | * Lifecycle interface for all stateful components 7 | */ 8 | public interface LifeCycle { 9 | /** 10 | * Initialize a component 11 | */ 12 | void init(); 13 | /** 14 | * Shutdown a component 15 | */ 16 | void exit() throws InterruptedException; 17 | 18 | /** 19 | * Shutdown a component with InterruptedException eaten 20 | */ 21 | default void UninterruptibleExit() { 22 | try{ 23 | exit(); 24 | }catch (InterruptedException e) { 25 | throw new FrameworkException(ExceptionType.CONTEXT, "Exit was interrupted"); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/LaunchTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import cn.zorcc.common.log.Logger; 4 | 5 | /** 6 | * For test running from jar purpose only 7 | */ 8 | public class LaunchTest { 9 | private static final Logger log = new Logger(LaunchTest.class); 10 | static class LifeCycleTest extends AbstractLifeCycle { 11 | 12 | @Override 13 | protected void doInit() { 14 | log.info("Init called"); 15 | } 16 | 17 | @Override 18 | protected void doExit() throws InterruptedException { 19 | log.info("Exit called"); 20 | } 21 | } 22 | public static void main(String[] args) { 23 | Context.load(new LifeCycleTest(), LifeCycleTest.class); 24 | Context.init(); 25 | 26 | } 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/beans/Book.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.beans; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | public class Book { 7 | private Long id; 8 | private List names; 9 | private Map> map; 10 | 11 | public Long getId() { 12 | return id; 13 | } 14 | 15 | public void setId(Long id) { 16 | this.id = id; 17 | } 18 | 19 | public List getNames() { 20 | return names; 21 | } 22 | 23 | public void setNames(List names) { 24 | this.names = names; 25 | } 26 | 27 | public Map> getMap() { 28 | return map; 29 | } 30 | 31 | public void setMap(Map> map) { 32 | this.map = map; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/exception/ServiceException.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.exception; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | /** 6 | * TODO refactor 7 | */ 8 | public final class ServiceException extends RuntimeException { 9 | private final String code; 10 | private final String msg; 11 | 12 | public ServiceException(String msg) { 13 | super(msg); 14 | this.msg = msg; 15 | this.code = Constants.ERR; 16 | } 17 | 18 | public ServiceException(String code, String msg) { 19 | super("code : " + code + " rpcMsg : " + msg); 20 | this.code = code; 21 | this.msg = msg; 22 | } 23 | 24 | public String getCode() { 25 | return code; 26 | } 27 | 28 | public String getMsg() { 29 | return msg; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /mint/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | tenet 5 | cn.zorcc 6 | 0.0.1 7 | 8 | 4.0.0 9 | tenet-mint 10 | jar 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | cn.zorcc 19 | tenet-common 20 | ${project.version} 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/ContextListener.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | public interface ContextListener { 4 | /** 5 | * Before the context was initialized, this function would be invoked 6 | */ 7 | void beforeStarted(); 8 | 9 | /** 10 | * After a container was loaded, this function would be invoked 11 | */ 12 | void onLoaded(Object target, Class type); 13 | 14 | /** 15 | * After a non-exist container was requested, this function would be invoked 16 | * The implementation should return Optional.empty() if no auto-registry could be provided 17 | */ 18 | T onRequested(Class type); 19 | 20 | /** 21 | * After all the container was initialized successfully, this function would be invoked 22 | */ 23 | void afterStarted(); 24 | } 25 | -------------------------------------------------------------------------------- /http/src/main/java/cn/zorcc/http/HttpEvent.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.http; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.handler.codec.http.FullHttpRequest; 5 | 6 | /** 7 | * Http服务器接受请求事件 8 | */ 9 | public class HttpEvent { 10 | /** 11 | * Http请求体 12 | */ 13 | private FullHttpRequest fullHttpRequest; 14 | /** 15 | * Http通信Channel 16 | */ 17 | private Channel channel; 18 | 19 | public FullHttpRequest fullHttpRequest() { 20 | return fullHttpRequest; 21 | } 22 | 23 | public void setFullHttpRequest(FullHttpRequest fullHttpRequest) { 24 | this.fullHttpRequest = fullHttpRequest; 25 | } 26 | 27 | public Channel channel() { 28 | return channel; 29 | } 30 | 31 | public void setChannel(Channel channel) { 32 | this.channel = channel; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Where.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | 4 | import java.util.ArrayList; 5 | import java.util.HashSet; 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | public final class Where { 10 | private static final String WHERE = " where "; 11 | private final List args = new ArrayList<>(); 12 | private final StringBuilder sql = new StringBuilder(); 13 | private final Set orderDescParam = new HashSet<>(); 14 | private final Set orderAscParam = new HashSet<>(); 15 | /** 16 | * 下一个语句使用and还是or连接,默认为false,使用and连接,调用or()方法后下一个语句使用or连接 17 | */ 18 | private boolean connectFlag = false; 19 | /** 20 | * 是否为第一个语句 21 | */ 22 | private boolean firstFlag = true; 23 | /** 24 | * 参数索引 25 | */ 26 | private int index; 27 | } 28 | -------------------------------------------------------------------------------- /http/src/main/java/cn/zorcc/http/WebSocketEvent.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.http; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; 5 | 6 | public class WebSocketEvent { 7 | /** 8 | * WebSocket数据帧 9 | */ 10 | private TextWebSocketFrame textWebSocketFrame; 11 | /** 12 | * WebSocket通信channel 13 | */ 14 | private Channel channel; 15 | 16 | public TextWebSocketFrame textWebSocketFrame() { 17 | return textWebSocketFrame; 18 | } 19 | 20 | public void setTextWebSocketFrame(TextWebSocketFrame textWebSocketFrame) { 21 | this.textWebSocketFrame = textWebSocketFrame; 22 | } 23 | 24 | public Channel channel() { 25 | return channel; 26 | } 27 | 28 | public void setChannel(Channel channel) { 29 | this.channel = channel; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/structure/TaskQueueTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import cn.zorcc.common.network.ListenerTask; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class TaskQueueTest { 8 | @Test 9 | public void testTaskQueue() { 10 | TaskQueue queue = new TaskQueue<>(1000); 11 | for(int i = 0; i < 1000; i++) { 12 | queue.offer(new ListenerTask(null, null, null, null, null, null, null)); 13 | } 14 | Iterable elements = queue.elements(); 15 | int count = 0; 16 | while (elements.iterator().hasNext()) { 17 | ListenerTask listenerTask = elements.iterator().next(); 18 | Assertions.assertNull(listenerTask.provider()); 19 | count++; 20 | } 21 | Assertions.assertEquals(count, 1000); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/rpc/RpcDecoder.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.rpc; 2 | 3 | import cn.zorcc.common.network.Decoder; 4 | import cn.zorcc.common.structure.ReadBuffer; 5 | 6 | import java.util.List; 7 | 8 | public final class RpcDecoder implements Decoder { 9 | @Override 10 | public void decode(ReadBuffer readBuffer, List entityList) { 11 | for( ; ; ) { 12 | long currentIndex = readBuffer.currentIndex(); 13 | if(readBuffer.available() < 8) { 14 | return ; 15 | } 16 | int msgType = readBuffer.readInt(); 17 | int len = readBuffer.readInt(); 18 | if(readBuffer.available() < len) { 19 | readBuffer.setReadIndex(currentIndex); 20 | return ; 21 | } 22 | entityList.add(new RpcMsg(msgType, len, readBuffer.readHeapSegment(len))); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/Handle.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * Handle represents a reference for the target serde object, the implementation should be generated by source code at compilation phase 7 | * All the methods shouldn't be renamed 8 | */ 9 | public interface Handle { 10 | 11 | /** 12 | * Create an assigner for the serde target, assigner's value could be filled with Column, then construct a real target 13 | */ 14 | Supplier createAssigner(); 15 | 16 | /** 17 | * Get target column, return null if it doesn't exist 18 | */ 19 | Column col(String columnName); 20 | 21 | /** 22 | * Cet an Enum instance by name, note that this method is only valid for Enum classes, other classes would throw an UnsupportedOperationException 23 | */ 24 | T byName(String name); 25 | } 26 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/structure/AllocatorTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.lang.foreign.MemorySegment; 7 | import java.lang.foreign.ValueLayout; 8 | 9 | public class AllocatorTest { 10 | @Test 11 | public void testHeapAllocator() { 12 | MemorySegment segment = Allocator.HEAP.allocate(ValueLayout.JAVA_INT); 13 | Assertions.assertEquals(segment.address() % 8, 0); 14 | } 15 | 16 | @Test 17 | public void testDirectAllocator() { 18 | try(Allocator allocator = Allocator.newDirectAllocator(MemApi.DEFAULT)) { 19 | for(int i = 0; i < 100; i++) { 20 | MemorySegment segment = allocator.allocate(ValueLayout.JAVA_INT); 21 | Assertions.assertEquals(segment.address() % 8, 0); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/Encoder.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.structure.WriteBuffer; 4 | 5 | /** 6 | * Channel Encoder interface determines how a Java Object should be encoded into the target WriteBuffer 7 | */ 8 | @FunctionalInterface 9 | public interface Encoder { 10 | 11 | /** 12 | * Encode a specific object into a WriteBuffer 13 | * This function would be invoked only in worker's writer thread, developers should take care about not blocking the writer thread by doing time-consuming logic 14 | * Encoder mode is not designed for transferring large data or zero-copy, you should consider other mechanism when you need to deal with large-file-transfer, such as using a separated BIO channel 15 | * If a RuntimeException was thrown in this function, the channel would be closed 16 | */ 17 | void encode(WriteBuffer writeBuffer, Object o); 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/Clock.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | /** 4 | * Helper clock class 5 | * Currently we would just use the JDK implementation for time retrieving, it might be modified in the future 6 | */ 7 | public final class Clock { 8 | 9 | /** 10 | * Never initialize it 11 | */ 12 | private Clock() { 13 | throw new UnsupportedOperationException(); 14 | } 15 | 16 | /** 17 | * Get current milliseconds timestamp 18 | */ 19 | public static long current() { 20 | return System.currentTimeMillis(); 21 | } 22 | 23 | /** 24 | * Get current nanoseconds timestamp 25 | */ 26 | public static long nano() { 27 | return System.nanoTime(); 28 | } 29 | 30 | /** 31 | * Calculates the nanoseconds elapsed since the specified nanosecond timestamp 32 | */ 33 | public static long elapsed(long nano) { 34 | return nano() - nano; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/PollerTaskType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * Poller msg type enum 5 | */ 6 | public enum PollerTaskType { 7 | /** 8 | * Bind a SentryPollerNode to current poller instance 9 | */ 10 | BIND, 11 | /** 12 | * Unbind a SentryPollerNode on timeout, used for client-side application 13 | */ 14 | UNBIND, 15 | /** 16 | * Register a message tag 17 | */ 18 | REGISTER, 19 | /** 20 | * Unregister a message tag 21 | */ 22 | UNREGISTER, 23 | /** 24 | * Force close an underlying channel 25 | */ 26 | CLOSE, 27 | /** 28 | * Indicates that current writer instance has no channel bound to it, it might be a potential exit for the whole application 29 | */ 30 | POTENTIAL_EXIT, 31 | /** 32 | * Tell the poller to shut down all the channel bound to it for exiting the whole application 33 | */ 34 | EXIT, 35 | } 36 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgDecoder.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import cn.zorcc.common.network.Decoder; 4 | import cn.zorcc.common.structure.ReadBuffer; 5 | 6 | import java.lang.foreign.MemorySegment; 7 | import java.util.List; 8 | 9 | public final class PgDecoder implements Decoder { 10 | @Override 11 | public void decode(ReadBuffer readBuffer, List entityList) { 12 | for( ; ; ) { 13 | long currentIndex = readBuffer.currentIndex(); 14 | if (readBuffer.available() < 5) { 15 | return ; 16 | } 17 | byte type = readBuffer.readByte(); 18 | int len = readBuffer.readInt() - 4; 19 | if(readBuffer.available() < len) { 20 | readBuffer.setReadIndex(currentIndex); 21 | return ; 22 | } 23 | MemorySegment data = readBuffer.readHeapSegment(len); 24 | entityList.add(new PgMsg(type, data)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /gateway/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | tenet 5 | cn.zorcc 6 | 0.0.1 7 | 8 | 4.0.0 9 | tenet-gateway 10 | jar 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | cn.zorcc 19 | tenet-common 20 | ${project.version} 21 | 22 | 23 | 24 | cn.zorcc 25 | tenet-http 26 | ${project.version} 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/exception/FrameworkException.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.exception; 2 | 3 | import cn.zorcc.common.ExceptionType; 4 | 5 | /** 6 | * Framework level exception 7 | */ 8 | public final class FrameworkException extends RuntimeException { 9 | 10 | public FrameworkException(ExceptionType exceptionType, String message) { 11 | this(exceptionType, message, null, (Object) null); 12 | } 13 | 14 | public FrameworkException(ExceptionType exceptionType, String message, Throwable throwable) { 15 | this(exceptionType, message, throwable, (Object) null); 16 | } 17 | 18 | public FrameworkException(ExceptionType exceptionType, String message, Object... args) { 19 | this(exceptionType, message, null, args); 20 | } 21 | 22 | public FrameworkException(ExceptionType exceptionType, String message, Throwable throwable, Object... args) { 23 | super(STR."Type : \{exceptionType}, Msg : \{args == null ? message : String.format(message, args)}", throwable); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/DefaultContextListener.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import cn.zorcc.common.log.Logger; 4 | import cn.zorcc.common.log.LoggerConsumer; 5 | import cn.zorcc.common.structure.Wheel; 6 | 7 | /** 8 | * Default implementation for ContextListener, used for test-purpose only 9 | */ 10 | public final class DefaultContextListener implements ContextListener { 11 | private static final Logger log = new Logger(DefaultContextListener.class); 12 | 13 | @Override 14 | public void beforeStarted() { 15 | Context.load(Wheel.wheel(), Wheel.class); 16 | Context.load(new LoggerConsumer(), LoggerConsumer.class); 17 | } 18 | 19 | @Override 20 | public void onLoaded(Object target, Class type) { 21 | log.debug(STR."Container loaded for \{type.getName()}"); 22 | } 23 | 24 | @Override 25 | public T onRequested(Class type) { 26 | return null; 27 | } 28 | 29 | @Override 30 | public void afterStarted() { 31 | log.debug("DefaultContext initialized successfully"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /http/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | tenet 7 | cn.zorcc 8 | 0.0.1 9 | 10 | 4.0.0 11 | tenet-http 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | cn.zorcc 20 | tenet-common 21 | ${project.version} 22 | 23 | 24 | 25 | 26 | io.netty 27 | netty-all 28 | 4.1.93.Final 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgEncoder.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | import cn.zorcc.common.network.Encoder; 7 | import cn.zorcc.common.structure.WriteBuffer; 8 | 9 | import java.lang.foreign.MemorySegment; 10 | 11 | public final class PgEncoder implements Encoder { 12 | @Override 13 | public void encode(WriteBuffer writeBuffer, Object o) { 14 | if(o instanceof PgMsg pgMsg) { 15 | byte type = pgMsg.type(); 16 | if(type != Constants.NUT) { 17 | writeBuffer.writeByte(type); 18 | } 19 | MemorySegment data = pgMsg.data(); 20 | int len = (int) data.byteSize(); 21 | writeBuffer.writeInt(len + 4); 22 | if(len > 0) { 23 | writeBuffer.writeSegment(data); 24 | } 25 | }else { 26 | throw new FrameworkException(ExceptionType.POSTGRESQL, Constants.UNREACHED); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/WriterTaskType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | /** 4 | * Used as writer msg type enum 5 | */ 6 | public enum WriterTaskType { 7 | /** 8 | * Bind a protocol and channel with current writer instance 9 | */ 10 | INITIATE, 11 | /** 12 | * Send a single msg over the channel 13 | */ 14 | SINGLE_MSG, 15 | /** 16 | * Send multiple msg over the channel 17 | */ 18 | MULTIPLE_MSG, 19 | /** 20 | * Indicates that channel is writable again 21 | */ 22 | WRITABLE, 23 | /** 24 | * Tell the writer to shut down the channel 25 | */ 26 | SHUTDOWN, 27 | /** 28 | * Tell the channel to force close the channel 29 | */ 30 | CLOSE, 31 | /** 32 | * Indicates that current writer instance has no channel bound to it, it might be a potential exit for the whole application 33 | */ 34 | POTENTIAL_EXIT, 35 | /** 36 | * Tell the writer to shut down all the channel bound to it for exiting the whole application 37 | */ 38 | EXIT 39 | } 40 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/Column.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import java.util.function.BiConsumer; 4 | import java.util.function.Function; 5 | import java.util.function.Supplier; 6 | 7 | /** 8 | * We could review each field in a class as a column, where we could modify it as we want 9 | */ 10 | public record Column ( 11 | String name, 12 | RecursiveType type, 13 | Function tagMapping, 14 | BiConsumer, Object> assigner, 15 | Function fetcher 16 | ) { 17 | /** 18 | * EMPTY_TAG would be used in source-code generation, never rename or remove it 19 | */ 20 | @SuppressWarnings("unused") 21 | public static final Function EMPTY_TAG = _ -> null; 22 | 23 | public String tag(String key) { 24 | return tagMapping.apply(key); 25 | } 26 | 27 | public void assign(Supplier supplier, Object value) { 28 | assigner.accept(supplier, value); 29 | } 30 | 31 | public Object fetch(T value) { 32 | return fetcher.apply(value); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/AbstractLifeCycle.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | import cn.zorcc.common.exception.FrameworkException; 4 | 5 | import java.util.concurrent.atomic.AtomicInteger; 6 | 7 | /** 8 | * Abstract lifecycle interface implementation, the init() and exit() methods are limited to be only invoked once 9 | */ 10 | public abstract class AbstractLifeCycle implements LifeCycle { 11 | private final AtomicInteger state = new AtomicInteger(Constants.INITIAL); 12 | protected abstract void doInit(); 13 | protected abstract void doExit() throws InterruptedException; 14 | 15 | @Override 16 | public void init() { 17 | if(state.compareAndSet(Constants.INITIAL, Constants.RUNNING)) { 18 | doInit(); 19 | }else { 20 | throw new FrameworkException(ExceptionType.CONTEXT, Constants.UNREACHED); 21 | } 22 | } 23 | 24 | @Override 25 | public void exit() throws InterruptedException { 26 | if(state.compareAndSet(Constants.RUNNING, Constants.STOPPED)) { 27 | doExit(); 28 | }else { 29 | throw new FrameworkException(ExceptionType.CONTEXT, Constants.UNREACHED); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/json/JsonTypeRef.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.json; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | import cn.zorcc.common.exception.JsonParseException; 7 | 8 | import java.lang.reflect.ParameterizedType; 9 | import java.lang.reflect.Type; 10 | 11 | /** 12 | * Helper class to get generic type from parameters 13 | */ 14 | @SuppressWarnings("unused") 15 | public abstract class JsonTypeRef { 16 | private final Type type; 17 | 18 | protected JsonTypeRef() { 19 | Type t = getClass().getGenericSuperclass(); 20 | if (t instanceof ParameterizedType parameterizedType) { 21 | Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 22 | if(actualTypeArguments.length != 1) { 23 | throw new FrameworkException(ExceptionType.JSON, Constants.UNREACHED); 24 | } 25 | this.type = actualTypeArguments[0]; 26 | }else { 27 | throw new JsonParseException(Constants.UNREACHED); 28 | } 29 | } 30 | 31 | public Type type() { 32 | return type; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/Decoder.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.structure.ReadBuffer; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Channel Decoder interface determines how the data received could be transformed into a new created Java Object for parsing 9 | */ 10 | @FunctionalInterface 11 | public interface Decoder { 12 | 13 | /** 14 | * Decode a memory-segment into an object, could return null indicating that the readBuffer is currently incomplete for parsing 15 | * If readBuffer's readerIndex is not equal to writeIndex after decoding, or null is returned, which means there are still some data remaining in the socket 16 | * In that case remaining-data will be retrieved in the next loop, the buffer will be shortly cached in channel's local storage 17 | * This function would be invoked only in poller thread, developers should take care about not blocking the poller thread by doing time-consuming logic 18 | * If a RuntimeException was thrown in this function, possibly a corrupted request format or decoding logic, the channel would be closed 19 | */ 20 | void decode(ReadBuffer readBuffer, List entityList); 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/json/JsonWriterCollectionNode.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.json; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.Format; 5 | import cn.zorcc.common.structure.WriteBuffer; 6 | 7 | import java.util.Iterator; 8 | 9 | public class JsonWriterCollectionNode extends JsonWriterNode { 10 | private final WriteBuffer writeBuffer; 11 | private final Iterator iterator; 12 | private final Format format; 13 | 14 | public JsonWriterCollectionNode(WriteBuffer writeBuffer, Iterator iterator, Format format) { 15 | this.writeBuffer = writeBuffer; 16 | this.iterator = iterator; 17 | this.format = format; 18 | writeBuffer.writeByte(Constants.LSB); 19 | } 20 | 21 | @Override 22 | protected JsonWriterNode trySerialize() { 23 | while (iterator.hasNext()) { 24 | writeSep(writeBuffer); 25 | Object element = iterator.next(); 26 | JsonWriterNode jsonNode = writeValue(writeBuffer, element, format); 27 | if(jsonNode != null) { 28 | return jsonNode; 29 | } 30 | } 31 | writeBuffer.writeByte(Constants.RSB); 32 | return toPrev(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/structure/MemApi.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import cn.zorcc.common.bindings.SystemBinding; 4 | 5 | import java.lang.foreign.MemorySegment; 6 | 7 | public interface MemApi { 8 | /** 9 | * Default system memApi, could be overwritten using LD_PRELOAD with custom memory allocators such as jemalloc, tcmalloc, or mimalloc 10 | */ 11 | MemApi DEFAULT = new MemApi() { 12 | @Override 13 | public MemorySegment allocateMemory(long byteSize) { 14 | return SystemBinding.malloc(byteSize); 15 | } 16 | 17 | @Override 18 | public MemorySegment reallocateMemory(MemorySegment ptr, long newSize) { 19 | return SystemBinding.realloc(ptr, newSize); 20 | } 21 | 22 | @Override 23 | public void freeMemory(MemorySegment ptr) { 24 | SystemBinding.free(ptr); 25 | } 26 | }; 27 | 28 | /** 29 | * Allocate a chunk of memory 30 | */ 31 | MemorySegment allocateMemory(long byteSize); 32 | 33 | /** 34 | * Reallocate a chunk of memory 35 | */ 36 | MemorySegment reallocateMemory(MemorySegment ptr, long newSize); 37 | 38 | /** 39 | * Free a chunk of memory 40 | */ 41 | void freeMemory(MemorySegment ptr); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/Loc.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | /** 8 | * Ipv4 or Ipv6 address, Note that port is a number between 0 and 65535, in C normally represented as u_short, but in java there is no unsigned number, so here we did some transformation 9 | */ 10 | public record Loc ( 11 | IpType ipType, 12 | String ip, 13 | int port 14 | ) { 15 | private static final int PORT_MAX = 65535; 16 | 17 | /** 18 | * Create a default local address 19 | */ 20 | public Loc(IpType ipType, int port) { 21 | this(ipType, Constants.EMPTY_STRING, port); 22 | } 23 | 24 | /** 25 | * Convert an int port to an unsigned short type, this method force retain the lower 16bits, the result could be negative 26 | */ 27 | public short shortPort() { 28 | if(port < 0 || port > PORT_MAX) { 29 | throw new FrameworkException(ExceptionType.NETWORK, "Port number overflow"); 30 | } 31 | return (short) port; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return STR."[\{ip == null || ip.isBlank() ? "localhost" : ip}:\{port}]"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgHandler.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | import cn.zorcc.common.log.Logger; 4 | import cn.zorcc.common.network.Channel; 5 | import cn.zorcc.common.network.Handler; 6 | import cn.zorcc.common.network.TagMsg; 7 | 8 | import java.util.Optional; 9 | import java.util.concurrent.BlockingQueue; 10 | import java.util.concurrent.LinkedTransferQueue; 11 | import java.util.concurrent.atomic.AtomicBoolean; 12 | 13 | public class PgHandler implements Handler { 14 | private static final Logger log = new Logger(PgHandler.class); 15 | private final PgManager pgManager; 16 | private final AtomicBoolean available = new AtomicBoolean(true); 17 | private final BlockingQueue msgQueue = new LinkedTransferQueue<>(); 18 | public PgHandler(PgManager pgManager) { 19 | this.pgManager = pgManager; 20 | } 21 | 22 | @Override 23 | public void onFailed(Channel channel) { 24 | 25 | } 26 | 27 | @Override 28 | public void onConnected(Channel channel) { 29 | 30 | } 31 | 32 | @Override 33 | public Optional onRecv(Channel channel, Object data) { 34 | return Optional.empty(); 35 | } 36 | 37 | @Override 38 | public void onShutdown(Channel channel) { 39 | 40 | } 41 | 42 | @Override 43 | public void onRemoved(Channel channel) { 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/Socket.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | public sealed interface Socket permits Socket.IntSocket, Socket.LongSocket{ 4 | /** 5 | * Return the int value of current socket implementation 6 | */ 7 | int intValue(); 8 | 9 | /** 10 | * Return the int value of current socket implementation 11 | */ 12 | long longValue(); 13 | 14 | static Socket ofInt(int value) { 15 | return new IntSocket(value); 16 | } 17 | 18 | static Socket ofLong(long value) { 19 | return new LongSocket(value); 20 | } 21 | 22 | /** 23 | * Socket used for linux and macOS 24 | * TODO value-based class 25 | */ 26 | record IntSocket(int value) implements Socket { 27 | @Override 28 | public int intValue() { 29 | return value; 30 | } 31 | 32 | @Override 33 | public long longValue() { 34 | return value; 35 | } 36 | } 37 | 38 | /** 39 | * Socket used for Windows 40 | * TODO value-based class 41 | */ 42 | record LongSocket(long value) implements Socket { 43 | @Override 44 | public int intValue() { 45 | return Math.toIntExact(value); 46 | } 47 | 48 | @Override 49 | public long longValue() { 50 | return value; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/jmh/TimeFormatTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.jmh; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.log.DefaultTimeResolver; 5 | import cn.zorcc.common.log.TimeResolver; 6 | import org.openjdk.jmh.annotations.Benchmark; 7 | import org.openjdk.jmh.infra.Blackhole; 8 | import org.openjdk.jmh.runner.RunnerException; 9 | 10 | import java.time.LocalDateTime; 11 | import java.time.format.DateTimeFormatter; 12 | 13 | /** 14 | * May get twice the boost using timeResolver 15 | * Benchmark Mode Cnt Score Error Units 16 | * TimeFormatTest.testDefault avgt 50 33.715 ± 0.212 ns/op 17 | * TimeFormatTest.testFormat avgt 50 63.067 ± 0.562 ns/op 18 | */ 19 | public class TimeFormatTest extends JmhTest { 20 | private static final TimeResolver timeResolver = new DefaultTimeResolver(); 21 | private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Constants.DEFAULT_TIME_FORMAT); 22 | @Benchmark 23 | public void testFormat(Blackhole bh) { 24 | bh.consume(formatter.format(LocalDateTime.now())); 25 | } 26 | 27 | @Benchmark 28 | public void testDefault(Blackhole bh) { 29 | bh.consume(timeResolver.format(LocalDateTime.now())); 30 | } 31 | 32 | public static void main(String[] args) throws RunnerException { 33 | runTest(TimeFormatTest.class); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/jmh/AtomicTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.jmh; 2 | 3 | import org.openjdk.jmh.annotations.Benchmark; 4 | import org.openjdk.jmh.infra.Blackhole; 5 | import org.openjdk.jmh.runner.RunnerException; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | import java.util.concurrent.locks.Lock; 11 | import java.util.concurrent.locks.ReentrantLock; 12 | 13 | public class AtomicTest extends JmhTest { 14 | private static final AtomicInteger a = new AtomicInteger(0); 15 | private static final Lock lock = new ReentrantLock(); 16 | private int i = 0; 17 | private Map map = new HashMap<>(); 18 | 19 | @Benchmark 20 | public void testPlain(Blackhole bh) { 21 | bh.consume(++i); 22 | } 23 | 24 | @Benchmark 25 | public void testAtomic(Blackhole bh) { 26 | bh.consume(a.getAndIncrement()); 27 | } 28 | 29 | @Benchmark 30 | public void testMap(Blackhole bh) { 31 | bh.consume(map.put(a, "")); 32 | } 33 | 34 | @Benchmark 35 | public void testLock(Blackhole bh) { 36 | lock.lock(); 37 | try{ 38 | bh.consume(++i); 39 | }finally { 40 | lock.unlock(); 41 | } 42 | } 43 | 44 | public static void main(String[] args) throws RunnerException { 45 | runTest(AtomicTest.class); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/json/JsonWriterMapNode.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.json; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.structure.WriteBuffer; 5 | 6 | import java.util.Iterator; 7 | import java.util.Map; 8 | 9 | /** 10 | * Represent a Map structure when writing into target writer 11 | * Note that using Map structure for serialization won't be able to assign the target Format for built-in types like Integer or String 12 | */ 13 | public final class JsonWriterMapNode extends JsonWriterNode { 14 | private final WriteBuffer writeBuffer; 15 | private final Iterator> iterator; 16 | 17 | public JsonWriterMapNode(WriteBuffer writeBuffer, Map map) { 18 | this.writeBuffer = writeBuffer; 19 | this.iterator = map.entrySet().iterator(); 20 | writeBuffer.writeByte(Constants.LCB); 21 | } 22 | 23 | @Override 24 | protected JsonWriterNode trySerialize() { 25 | while (iterator.hasNext()) { 26 | Map.Entry entry = iterator.next(); 27 | writeSep(writeBuffer); 28 | writeKey(writeBuffer, entry.getKey().toString()); 29 | JsonWriterNode appended = writeValue(writeBuffer, entry.getValue()); 30 | if(appended != null) { 31 | return appended; 32 | } 33 | } 34 | writeBuffer.writeByte(Constants.RCB); 35 | return toPrev(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/FileLogConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | public final class FileLogConfig { 6 | /** 7 | * Dir path to store the log file 8 | */ 9 | private String dir = Constants.EMPTY_STRING; 10 | /** 11 | * Max flush threshold 12 | */ 13 | private int flushThreshold = 128; 14 | /** 15 | * Max file size before switching database file 16 | */ 17 | private long maxFileSize = 256 * Constants.MB; 18 | /** 19 | * Max existing time before switching recording file 20 | */ 21 | private long maxRecordingTime = Constants.DAY; 22 | 23 | public String getDir() { 24 | return dir; 25 | } 26 | 27 | public void setDir(String dir) { 28 | this.dir = dir; 29 | } 30 | 31 | public int getFlushThreshold() { 32 | return flushThreshold; 33 | } 34 | 35 | public void setFlushThreshold(int flushThreshold) { 36 | this.flushThreshold = flushThreshold; 37 | } 38 | 39 | public long getMaxFileSize() { 40 | return maxFileSize; 41 | } 42 | 43 | public void setMaxFileSize(long maxFileSize) { 44 | this.maxFileSize = maxFileSize; 45 | } 46 | 47 | public long getMaxRecordingTime() { 48 | return maxRecordingTime; 49 | } 50 | 51 | public void setMaxRecordingTime(long maxRecordingTime) { 52 | this.maxRecordingTime = maxRecordingTime; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/SqliteLogConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | public final class SqliteLogConfig { 6 | /** 7 | * Dir path to store the sqlite database file 8 | */ 9 | private String dir = Constants.EMPTY_STRING; 10 | /** 11 | * Max flush threshold 12 | */ 13 | private int flushThreshold = 128; 14 | /** 15 | * Max existing row count before switching database file 16 | */ 17 | private long maxRowCount = Constants.MB; 18 | /** 19 | * Max existing time before switching database file 20 | */ 21 | private long maxRecordingTime = Constants.DAY; 22 | 23 | public String getDir() { 24 | return dir; 25 | } 26 | 27 | public void setDir(String dir) { 28 | this.dir = dir; 29 | } 30 | 31 | public int getFlushThreshold() { 32 | return flushThreshold; 33 | } 34 | 35 | public void setFlushThreshold(int flushThreshold) { 36 | this.flushThreshold = flushThreshold; 37 | } 38 | 39 | public long getMaxRowCount() { 40 | return maxRowCount; 41 | } 42 | 43 | public void setMaxRowCount(long maxRowCount) { 44 | this.maxRowCount = maxRowCount; 45 | } 46 | 47 | public long getMaxRecordingTime() { 48 | return maxRecordingTime; 49 | } 50 | 51 | public void setMaxRecordingTime(long maxRecordingTime) { 52 | this.maxRecordingTime = maxRecordingTime; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/jmh/ScopedValueTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.jmh; 2 | 3 | import org.openjdk.jmh.annotations.Benchmark; 4 | import org.openjdk.jmh.annotations.Param; 5 | import org.openjdk.jmh.infra.Blackhole; 6 | import org.openjdk.jmh.runner.RunnerException; 7 | 8 | public class ScopedValueTest extends JmhTest { 9 | private static final String s = "hello"; 10 | @Param({"100", "1000", "10000"}) 11 | private int BATCH; 12 | private static final ThreadLocal threadLocal = new ThreadLocal<>(); 13 | private static final ScopedValue scopedValue = ScopedValue.newInstance(); 14 | 15 | @Benchmark 16 | public void testScopedValue(Blackhole blackhole) { 17 | ScopedValue.runWhere(scopedValue, s, () -> { 18 | for(int i = 0; i < BATCH; i++) { 19 | blackhole.consume(scopedValue.get()); 20 | } 21 | }); 22 | } 23 | 24 | @Benchmark 25 | public void testThreadLocal(Blackhole blackhole) { 26 | threadLocal.set(s); 27 | for(int i = 0; i < BATCH; i++) { 28 | blackhole.consume(threadLocal.get()); 29 | } 30 | threadLocal.remove(); 31 | } 32 | 33 | @Benchmark 34 | public void testEmpty(Blackhole blackhole) { 35 | for(int i = 0; i < BATCH; i++) { 36 | blackhole.consume(s); 37 | } 38 | } 39 | 40 | public static void main(String[] args) throws RunnerException { 41 | runTest(ScopedValueTest.class); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /orm/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | tenet 5 | cn.zorcc 6 | 0.0.1 7 | 8 | 9 | 10 | 11 | org.apache.maven.plugins 12 | maven-compiler-plugin 13 | 14 | 22 15 | 22 16 | --enable-preview 17 | 18 | 19 | 20 | 21 | 4.0.0 22 | tenet-orm 23 | jar 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | cn.zorcc 32 | tenet-common 33 | ${project.version} 34 | 35 | 36 | 37 | 38 | com.ongres.scram 39 | client 40 | ${scram.version} 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /http/src/main/java/cn/zorcc/http/HttpTools.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.http; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | import io.netty.channel.Channel; 6 | import io.netty.channel.ChannelFutureListener; 7 | import io.netty.handler.codec.http.DefaultFullHttpResponse; 8 | import io.netty.handler.codec.http.FullHttpResponse; 9 | import io.netty.handler.codec.http.HttpHeaderNames; 10 | import io.netty.handler.codec.http.HttpResponseStatus; 11 | 12 | import java.nio.charset.StandardCharsets; 13 | 14 | import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; 15 | 16 | /** 17 | * http协议工具类,避免与Netty本身的HttpUtil重名 18 | */ 19 | public class HttpTools { 20 | private static final String FAILURE = "Failure: "; 21 | private static final String TEXT_TYPE = "text/plain; charset=UTF-8"; 22 | 23 | private HttpTools() { 24 | throw new UnsupportedOperationException(); 25 | } 26 | 27 | /** 28 | * 返回http状态消息 29 | * @param channel http通信channel 30 | * @param httpResponseStatus http状态码 31 | */ 32 | public static void httpFail(Channel channel, HttpResponseStatus httpResponseStatus) { 33 | String msg = FAILURE + httpResponseStatus.reasonPhrase(); 34 | ByteBuf buf = Unpooled.wrappedBuffer(msg.getBytes(StandardCharsets.UTF_8)); 35 | FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, httpResponseStatus, buf); 36 | response.headers().set(HttpHeaderNames.CONTENT_TYPE, TEXT_TYPE); 37 | channel.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/json/JsonWriterObjectNode.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.json; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.Meta; 5 | import cn.zorcc.common.MetaInfo; 6 | import cn.zorcc.common.structure.WriteBuffer; 7 | 8 | import java.util.List; 9 | 10 | public final class JsonWriterObjectNode extends JsonWriterNode { 11 | private final WriteBuffer writeBuffer; 12 | private final Meta meta; 13 | private final Object obj; 14 | private int index = 0; 15 | 16 | public JsonWriterObjectNode(WriteBuffer writeBuffer, Object obj, Class type) { 17 | this.writeBuffer = writeBuffer; 18 | this.meta = JsonParser.getMeta(type); 19 | this.obj = obj; 20 | writeBuffer.writeByte(Constants.LCB); 21 | } 22 | 23 | @Override 24 | protected JsonWriterNode trySerialize() { 25 | final List metaInfoList = meta.metaInfoList(); 26 | while (index < metaInfoList.size()) { 27 | MetaInfo metaInfo = metaInfoList.get(index); 28 | index = index + 1; 29 | Object value = metaInfo.getter().apply(obj); 30 | if(value != null) { 31 | writeSep(writeBuffer); 32 | writeKey(writeBuffer, metaInfo.fieldName()); 33 | JsonWriterNode appended = writeValue(writeBuffer, value, metaInfo.format()); 34 | if(appended != null) { 35 | return appended; 36 | } 37 | } 38 | } 39 | writeBuffer.writeByte(Constants.RCB); 40 | return toPrev(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /json.md: -------------------------------------------------------------------------------- 1 | # Json 2 | 3 | In the Tenet project, there is an extremely simple JSON serialization tool designed for seamless conversion between byte stream data and Java objects. 4 | While specialized libraries are typically employed for such tasks, JSON parsing itself is a straightforward operation. 5 | We aim to keep the source code as simple as possible, aligning it closely with our framework. 6 | This approach also facilitates developers in customizing and enhancing its functionality through the use of annotations. 7 | 8 | # Reflection 9 | 10 | When it comes to serialization and deserialization, using reflection is an unavoidable approach. In Java, there are currently several reflection invocation methods: 11 | 12 | - Invocation using Method.invoke(). 13 | - Invocation using MethodHandle.invokeExact(). 14 | - Invocation using LambdaMetaFactory. 15 | 16 | During serialization, we primarily utilize get(), set(), and constructor methods, which inherently have low overhead. 17 | In actual testing scenarios, the efficiency of invoking methods using Method.invoke() is highest when there is no caching involved. 18 | On the other hand, when caching is employed, the efficiency of using LambdaMetaFactory is optimal. 19 | However, it's worth noting that the dynamically generated performance of LambdaMetaFactory is significantly poor. 20 | In comparison, MethodHandle.invokeExact() strikes a better balance between generation time and runtime performance. 21 | Therefore, we have decided to use the Method.invoke() approach for ordinary reflection invocations and the MethodHandle.invokeExact() approach for cases where object information is pre-cached. -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/json/JsonWriterRecordNode.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.json; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.Record; 5 | import cn.zorcc.common.RecordInfo; 6 | import cn.zorcc.common.structure.WriteBuffer; 7 | 8 | import java.util.List; 9 | 10 | public final class JsonWriterRecordNode extends JsonWriterNode { 11 | private final WriteBuffer writeBuffer; 12 | private final Record record; 13 | private final Object obj; 14 | private int index = 0; 15 | 16 | public JsonWriterRecordNode(WriteBuffer writeBuffer, Object obj, Class type) { 17 | this.writeBuffer = writeBuffer; 18 | this.record = Record.of(type); 19 | this.obj = obj; 20 | writeBuffer.writeByte(Constants.LCB); 21 | } 22 | 23 | @Override 24 | protected JsonWriterNode trySerialize() { 25 | final List recordInfoList = record.recordInfoList(); 26 | while (index < recordInfoList.size()) { 27 | RecordInfo recordInfo = recordInfoList.get(index); 28 | index = index + 1; 29 | Object value = recordInfo.getter().apply(obj); 30 | if(value != null) { 31 | writeSep(writeBuffer); 32 | writeKey(writeBuffer, recordInfo.fieldName()); 33 | JsonWriterNode appended = writeValue(writeBuffer, value, recordInfo.format()); 34 | if(appended != null) { 35 | return appended; 36 | } 37 | } 38 | } 39 | writeBuffer.writeByte(Constants.RCB); 40 | return toPrev(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/Seq.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common; 2 | 3 | 4 | import cn.zorcc.common.structure.Allocator; 5 | 6 | import java.lang.foreign.MemorySegment; 7 | import java.lang.foreign.ValueLayout; 8 | import java.util.Random; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | /** 12 | * Global seq generator, default representation would be using 16 bytes, so it can be simplified as two long value writing 13 | */ 14 | public final class Seq { 15 | private static final int TIMESTAMP_BYTES = 6; 16 | private static final int APP_ID_BYTES = 2; 17 | private static final int NODE_ID_BYTES = 1; 18 | private static final int SEQ_BYTES = 4; 19 | private static final AtomicInteger sequence = new AtomicInteger(new Random().nextInt()); 20 | 21 | private Seq() { 22 | throw new UnsupportedOperationException(); 23 | } 24 | 25 | public static MemorySegment create(int currentAppId, int currentNodeId, int targetAppId, int targetNodeId) { 26 | return create(Clock.current(), currentAppId, currentNodeId, targetAppId, targetNodeId); 27 | } 28 | 29 | public static MemorySegment create(long timestamp, long currentAppId, long currentNodeId, long targetAppId, long targetNodeId) { 30 | MemorySegment segment = Allocator.HEAP.allocate(ValueLayout.JAVA_LONG, 2); 31 | long l1 = (timestamp << 16) | currentAppId; 32 | long l2 = (currentNodeId << 56) | (targetAppId << 40) | (targetNodeId << 32) | sequence.getAndIncrement(); 33 | segment.set(ValueLayout.JAVA_LONG, 0L, l1); 34 | segment.set(ValueLayout.JAVA_LONG, 8L, l2); 35 | return segment; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/beans/Beta.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.beans; 2 | 3 | import java.util.List; 4 | 5 | public class Beta { 6 | private int a1; 7 | private Integer a2; 8 | private int[] a3; 9 | private Integer[] a4; 10 | private String a5; 11 | private List a6; 12 | private List a7; 13 | private List a8; 14 | 15 | public int getA1() { 16 | return a1; 17 | } 18 | 19 | public void setA1(int a1) { 20 | this.a1 = a1; 21 | } 22 | 23 | public Integer getA2() { 24 | return a2; 25 | } 26 | 27 | public void setA2(Integer a2) { 28 | this.a2 = a2; 29 | } 30 | 31 | public int[] getA3() { 32 | return a3; 33 | } 34 | 35 | public void setA3(int[] a3) { 36 | this.a3 = a3; 37 | } 38 | 39 | public Integer[] getA4() { 40 | return a4; 41 | } 42 | 43 | public void setA4(Integer[] a4) { 44 | this.a4 = a4; 45 | } 46 | 47 | public String getA5() { 48 | return a5; 49 | } 50 | 51 | public void setA5(String a5) { 52 | this.a5 = a5; 53 | } 54 | 55 | public List getA6() { 56 | return a6; 57 | } 58 | 59 | public void setA6(List a6) { 60 | this.a6 = a6; 61 | } 62 | 63 | public List getA7() { 64 | return a7; 65 | } 66 | 67 | public void setA7(List a7) { 68 | this.a7 = a7; 69 | } 70 | 71 | public List getA8() { 72 | return a8; 73 | } 74 | 75 | public void setA8(List a8) { 76 | this.a8 = a8; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/Mux.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | import java.lang.foreign.MemorySegment; 8 | 9 | /** 10 | * Multiplexing fd abstraction on different platforms 11 | * On Windows, it is a pointer 12 | * On Linux or macOS, it is an int fd 13 | * TODO value-based record 14 | */ 15 | public record Mux ( 16 | MemorySegment winHandle, 17 | int epfd, 18 | int kqfd 19 | ) { 20 | /** 21 | * Create a Windows mux 22 | */ 23 | public static Mux win(MemorySegment winHandle) { 24 | return new Mux(winHandle, Integer.MIN_VALUE, Integer.MIN_VALUE); 25 | } 26 | 27 | /** 28 | * Create a Linux mux 29 | */ 30 | public static Mux linux(int epfd) { 31 | return new Mux(MemorySegment.NULL, epfd, Integer.MIN_VALUE); 32 | } 33 | 34 | /** 35 | * Create a macOS mux 36 | */ 37 | public static Mux mac(int kqfd) { 38 | return new Mux(MemorySegment.NULL, Integer.MIN_VALUE, kqfd); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | if(winHandle != MemorySegment.NULL) { 44 | return String.valueOf(winHandle.address()); 45 | }else if(epfd != Integer.MIN_VALUE) { 46 | return String.valueOf(epfd); 47 | }else if(kqfd != Integer.MIN_VALUE) { 48 | return String.valueOf(kqfd); 49 | }else { 50 | throw new FrameworkException(ExceptionType.NETWORK, Constants.UNREACHED); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/http/HttpRequest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.http; 2 | 3 | import java.lang.foreign.MemorySegment; 4 | 5 | /** 6 | * Http request abstraction 7 | */ 8 | public final class HttpRequest { 9 | /** 10 | * Http request method 11 | */ 12 | private HttpMethod method; 13 | /** 14 | * Http request rri 15 | */ 16 | private String uri; 17 | /** 18 | * Http version, default would be HTTP1.1 19 | */ 20 | private String version; 21 | /** 22 | * Http headers 23 | */ 24 | private HttpHeader httpHeader = new HttpHeader(); 25 | /** 26 | * Http content data, normally would be json UTF-8 bytes or null 27 | */ 28 | private MemorySegment data; 29 | 30 | public HttpMethod getMethod() { 31 | return method; 32 | } 33 | 34 | public void setMethod(HttpMethod method) { 35 | this.method = method; 36 | } 37 | 38 | public String getUri() { 39 | return uri; 40 | } 41 | 42 | public void setUri(String uri) { 43 | this.uri = uri; 44 | } 45 | 46 | public String getVersion() { 47 | return version; 48 | } 49 | 50 | public void setVersion(String version) { 51 | this.version = version; 52 | } 53 | 54 | public HttpHeader getHttpHeader() { 55 | return httpHeader; 56 | } 57 | 58 | public void setHttpHeader(HttpHeader httpHeader) { 59 | this.httpHeader = httpHeader; 60 | } 61 | 62 | public MemorySegment getData() { 63 | return data; 64 | } 65 | 66 | public void setData(MemorySegment data) { 67 | this.data = data; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/util/SqlUtil.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.util; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | import java.util.List; 8 | 9 | public final class SqlUtil { 10 | private SqlUtil() { 11 | throw new UnsupportedOperationException(); 12 | } 13 | 14 | public static StringBuilder values(StringBuilder sb, int count) { 15 | sb.append(" values "); 16 | return params(sb, count); 17 | } 18 | 19 | public static StringBuilder params(StringBuilder sb, int count, int startIndex) { 20 | if(count > 0) { 21 | sb.append(Constants.L_BRACKET); 22 | for(int i = startIndex; i < count + startIndex; i++) { 23 | sb.append(Constants.SIGN_CHAR).append(i).append(i == count + startIndex - 1 ? Constants.R_BRACKET : Constants.COMMA_CHAR); 24 | } 25 | return sb; 26 | }else { 27 | throw new FrameworkException(ExceptionType.SQL, Constants.UNREACHED); 28 | } 29 | } 30 | 31 | public static StringBuilder params(StringBuilder sb, int count) { 32 | return params(sb, count, 1); 33 | } 34 | 35 | 36 | /** 37 | * Pattern : insert into table_name(a,b,c) 38 | */ 39 | public static StringBuilder insertInto(StringBuilder sb, String tableName, List databaseColumns) { 40 | sb.append("insert into ").append(tableName); 41 | String databaseColumnString = String.join(",", databaseColumns); 42 | sb.append(Constants.L_BRACKET).append(databaseColumnString).append(Constants.R_BRACKET); 43 | return sb; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/serde/GenerationContext.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | import java.lang.invoke.MethodHandles; 8 | import java.util.AbstractMap; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.stream.Collectors; 13 | 14 | public final class GenerationContext { 15 | private static final List, Handle>> entryList = new ArrayList<>(); 16 | private static final Map, Handle> handleMap; 17 | 18 | static { 19 | try{ 20 | MethodHandles.Lookup lookup = MethodHandles.lookup(); 21 | lookup.ensureInitialized(Class.forName("cn.zorcc.common.serde.BeanGenerationExample")); 22 | lookup.ensureInitialized(Class.forName("cn.zorcc.common.serde.EnumGenerationExample")); 23 | lookup.ensureInitialized(Class.forName("cn.zorcc.common.serde.RecordGenerationExample")); 24 | handleMap = entryList.stream().collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); 25 | } catch (Throwable e) { 26 | throw new FrameworkException(ExceptionType.CONTEXT, Constants.UNREACHED, e); 27 | } 28 | } 29 | 30 | public static void registerHandle(final Class clazz, final Handle handle) { 31 | entryList.add(new AbstractMap.SimpleImmutableEntry<>(clazz, handle)); 32 | } 33 | 34 | @SuppressWarnings("unchecked") 35 | public static Handle getHandle(final Class clazz) { 36 | return (Handle) handleMap.get(clazz); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | tenet 5 | cn.zorcc 6 | 0.0.1 7 | 8 | 9 | 10 | 11 | org.apache.maven.plugins 12 | maven-compiler-plugin 13 | 14 | 22 15 | 22 16 | --enable-preview 17 | 18 | 19 | 20 | 21 | 4.0.0 22 | tenet-app 23 | jar 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | cn.zorcc 32 | tenet-common 33 | ${project.version} 34 | 35 | 36 | 37 | cn.zorcc 38 | tenet-orm 39 | ${project.version} 40 | 41 | 42 | 43 | cn.zorcc 44 | tenet-http 45 | ${project.version} 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/sqlite/SqliteConstants.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.sqlite; 2 | 3 | public class SqliteConstants { 4 | public static final String CREATE_DISCOVERY_TABLE_SQL = """ 5 | CREATE TABLE IF NOT EXIST discovery ( 6 | id INTEGER PRIMARY KEY, 7 | app_id INTEGER, 8 | node_id INTEGER, 9 | ip_type INTEGER, 10 | ip TEXT, 11 | port INTEGER, 12 | weight INTEGER, 13 | created_at INTEGER, 14 | modified_at INTEGER 15 | ) 16 | """; 17 | public static final String INSERT_DISCOVERY_SQL = """ 18 | INSERT INTO discovery (app_id, node_id, ip_type, ip, port, weight, created_at) 19 | VALUES (?, ?, ?, ?, ?, ?, ?) 20 | """; 21 | public static final String SELECT_ID_DISCOVERY_SQL = """ 22 | SELECT id FROM discovery where app_id = ? and node_id = ? 23 | """; 24 | public static final String UPDATE_DISCOVERY_SQL = """ 25 | UPDATE discovery SET weight = ?, modified_at = ? WHERE id = ? 26 | """; 27 | public static final String DELETE_DISCOVERY_SQL = """ 28 | DELETE FROM discovery where app_id = ? and node_id = ? 29 | """; 30 | public static final String SELECT_MULTI_DISCOVERY_SQL = """ 31 | SELECT app_id, node_id, ip_type, ip, port, weight, created_at, modified_at FROM discovery where app_id = ? 32 | """; 33 | public static final String SELECT_ONE_DISCOVERY_SQL = """ 34 | SELECT app_id, node_id, ip_type, ip, port, weight, created_at, modified_at FROM discovery where app_id = ? and node_id = ? 35 | """; 36 | } 37 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/util/ResourcesLoadingTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.util; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.util.Collection; 9 | 10 | /** 11 | * This test shows that, no matter which class we use as the caller, it will always locate at the current resource folder for searching 12 | */ 13 | public class ResourcesLoadingTest { 14 | @Test 15 | public void testSelfClass() { 16 | try(InputStream inputStream = ResourcesLoadingTest.class.getResourceAsStream("/large.json")) { 17 | Assertions.assertNotNull(inputStream); 18 | }catch (IOException e) { 19 | throw new RuntimeException(e); 20 | } 21 | } 22 | 23 | @Test 24 | public void testProjectClass() { 25 | try(InputStream inputStream = ConfigUtil.class.getResourceAsStream("/large.json")) { 26 | Assertions.assertNotNull(inputStream); 27 | }catch (IOException e) { 28 | throw new RuntimeException(e); 29 | } 30 | } 31 | 32 | @Test 33 | public void testThirdPartyClass() { 34 | try(InputStream inputStream = Assertions.class.getResourceAsStream("/large.json")) { 35 | Assertions.assertNotNull(inputStream); 36 | }catch (IOException e) { 37 | throw new RuntimeException(e); 38 | } 39 | } 40 | 41 | @Test 42 | public void testJDKClass() { 43 | try(InputStream inputStream = Collection.class.getResourceAsStream("/large.json")) { 44 | Assertions.assertNull(inputStream); 45 | }catch (IOException e) { 46 | throw new RuntimeException(e); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/util/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.util; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.Meta; 6 | import cn.zorcc.common.exception.FrameworkException; 7 | import cn.zorcc.common.json.JsonParser; 8 | import cn.zorcc.common.structure.ReadBuffer; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.lang.foreign.MemorySegment; 13 | 14 | public final class ConfigUtil { 15 | private ConfigUtil() { 16 | throw new UnsupportedOperationException(); 17 | } 18 | 19 | public static void checkParam(int value, int min, int max) { 20 | if(value <= min || value >= max) { 21 | throw new FrameworkException(ExceptionType.CONFIG, STR."Configuration error : \{value}"); 22 | } 23 | } 24 | 25 | /** 26 | * Load json configuration file from resources folder, create a default one if not found 27 | */ 28 | public static T loadJsonConfig(String fileName, Class configClass) { 29 | if (!fileName.endsWith(Constants.JSON_SUFFIX)) { 30 | throw new FrameworkException(ExceptionType.CONFIG, "Config file must be .json"); 31 | } 32 | try(InputStream jsonStream = ConfigUtil.class.getResourceAsStream(fileName)) { 33 | if(jsonStream == null) { 34 | return Meta.of(configClass).constructor().get(); 35 | }else { 36 | return JsonParser.readObject(new ReadBuffer(MemorySegment.ofArray(jsonStream.readAllBytes())), configClass); 37 | } 38 | } catch (IOException e) { 39 | throw new FrameworkException(ExceptionType.CONFIG, "Can't resolve config file : " + fileName, e); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/AppHttpEvent.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http; 2 | 3 | import cn.zorcc.http.HttpReq; 4 | import io.netty.channel.Channel; 5 | 6 | public class AppHttpEvent { 7 | /** 8 | * Http请求体 9 | */ 10 | private HttpReq httpReq; 11 | /** 12 | * Http请求通配字符串 13 | */ 14 | private String wildStr; 15 | /** 16 | * MethodInvoker中的方法调用索引 17 | */ 18 | private int methodIndex; 19 | /** 20 | * 参数索引 21 | */ 22 | private int argIndex; 23 | /** 24 | * MethodInvoker中的方法调用参数 25 | */ 26 | private Object[] args; 27 | /** 28 | * Http通信Channel 29 | */ 30 | private Channel channel; 31 | 32 | public HttpReq httpReq() { 33 | return httpReq; 34 | } 35 | 36 | public void setHttpReq(HttpReq httpReq) { 37 | this.httpReq = httpReq; 38 | } 39 | 40 | public String wildStr() { 41 | return wildStr; 42 | } 43 | 44 | public void setWildStr(String wildStr) { 45 | this.wildStr = wildStr; 46 | } 47 | 48 | public int methodIndex() { 49 | return methodIndex; 50 | } 51 | 52 | public void setMethodIndex(int methodIndex) { 53 | this.methodIndex = methodIndex; 54 | } 55 | 56 | public int argIndex() { 57 | return argIndex; 58 | } 59 | 60 | public void setArgIndex(int argIndex) { 61 | this.argIndex = argIndex; 62 | } 63 | 64 | public Object[] args() { 65 | return args; 66 | } 67 | 68 | public void setArgs(Object[] args) { 69 | this.args = args; 70 | } 71 | 72 | public Channel channel() { 73 | return channel; 74 | } 75 | 76 | public void setChannel(Channel channel) { 77 | this.channel = channel; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/WriterCallback.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.log.Logger; 4 | 5 | /** 6 | * CallBack interface, could be used for implementing back-pressure or other mechanisms 7 | * CallBack can't be counted on when implementing business logic, the callback only indicates that data has been transferred from user-space to kernel-space 8 | * There is no guarantee that when onSuccess() were called, the data will eventually be transferred to the remote peer 9 | */ 10 | public interface WriterCallback { 11 | Logger log = new Logger(WriterCallback.class); 12 | /** 13 | * When data are successfully transferred to the socket buffer, this function would be invoked in writer thread 14 | * Don't block current writer thread inside this function, if there is a time-consuming logic, try start a new virtual thread to handle it 15 | */ 16 | void onSuccess(Channel channel); 17 | 18 | /** 19 | * When socket is exceptionally closed, this function would be invoked in writer thread 20 | * Don't block current writer thread inside this function, if there is a time-consuming logic, try start a new virtual thread to handle it 21 | */ 22 | void onFailure(Channel channel); 23 | 24 | default void invokeOnSuccess(Channel channel) { 25 | try{ 26 | onSuccess(channel); 27 | }catch (RuntimeException e) { 28 | log.error("Err occurred while invoking onSuccess()", e); 29 | } 30 | } 31 | 32 | default void invokeOnFailure(Channel channel) { 33 | try{ 34 | onFailure(channel); 35 | }catch (RuntimeException e) { 36 | log.error("Err occurred while invoking onFailure()", e); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgMapper.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import cn.zorcc.common.database.Mapper; 4 | import cn.zorcc.common.database.Page; 5 | import cn.zorcc.common.database.Where; 6 | 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | public class PgMapper implements Mapper { 11 | public PgMapper() { 12 | 13 | } 14 | 15 | @Override 16 | public int insert(T po) { 17 | return 0; 18 | } 19 | 20 | @Override 21 | public int insertBatch(Collection poCollection) { 22 | return 0; 23 | } 24 | 25 | @Override 26 | public int delete(Where where) { 27 | return 0; 28 | } 29 | 30 | @Override 31 | public int deleteById(Object id) { 32 | return 0; 33 | } 34 | 35 | @Override 36 | public int deleteByIds(Collection idCollection) { 37 | return 0; 38 | } 39 | 40 | @Override 41 | public int update(T po, Where where) { 42 | return 0; 43 | } 44 | 45 | @Override 46 | public int updateById(T po) { 47 | return 0; 48 | } 49 | 50 | @Override 51 | public T selectById(Object id) { 52 | return null; 53 | } 54 | 55 | @Override 56 | public List selectByIds(Collection idCollection) { 57 | return null; 58 | } 59 | 60 | @Override 61 | public List select(Where where) { 62 | return null; 63 | } 64 | 65 | @Override 66 | public T selectOne(Where where) { 67 | return null; 68 | } 69 | 70 | @Override 71 | public long count(Where where) { 72 | return 0; 73 | } 74 | 75 | @Override 76 | public Page page(Long pageNo, Long pageSize, Where where) { 77 | return null; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/jmh/JmhTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.jmh; 2 | 3 | import org.openjdk.jmh.annotations.*; 4 | import org.openjdk.jmh.results.format.ResultFormatType; 5 | import org.openjdk.jmh.runner.Runner; 6 | import org.openjdk.jmh.runner.RunnerException; 7 | import org.openjdk.jmh.runner.options.Options; 8 | import org.openjdk.jmh.runner.options.OptionsBuilder; 9 | 10 | import java.time.LocalDateTime; 11 | import java.time.format.DateTimeFormatter; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * Jmh Test base class, all the JMH Tests should be put here 16 | */ 17 | @BenchmarkMode(value = Mode.AverageTime) 18 | @Warmup(iterations = 3, time = 500, timeUnit = TimeUnit.MILLISECONDS) 19 | @Measurement(iterations = 5, time = 2000, timeUnit = TimeUnit.MILLISECONDS) 20 | @State(Scope.Thread) 21 | @OutputTimeUnit(TimeUnit.NANOSECONDS) 22 | abstract class JmhTest { 23 | private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"); 24 | 25 | /** 26 | * Recommended jvm args: 27 | * --enable-native-access=ALL-UNNAMED 28 | * -DTENET_LIBRARY_PATH=C:/workspace/tenet-lib/lib 29 | * -Xmx2G 30 | * -XX:+UseZGC 31 | * -XX:+ZGenerational 32 | * --add-modules 33 | * jdk.incubator.vector 34 | */ 35 | public static void runTest(Class launchClass) throws RunnerException { 36 | Options options = new OptionsBuilder() 37 | .include(launchClass.getSimpleName()) 38 | .detectJvmArgs() 39 | .resultFormat(ResultFormatType.TEXT) 40 | .result("%s_%s.txt".formatted(launchClass.getSimpleName(), LocalDateTime.now().format(FORMATTER))) 41 | .build(); 42 | new Runner(options).run(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/cn/zorcc/app/http/UrlTreeNode.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.app.http; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | import java.util.function.Function; 7 | 8 | /** 9 | * url匹配树中的单个节点 10 | */ 11 | public class UrlTreeNode { 12 | /** 13 | * 本地methodIndex的值 14 | */ 15 | private Integer index; 16 | /** 17 | * 转化函数 18 | */ 19 | private Function func; 20 | /** 21 | * 占位符Node,以:开头,只能出现在匹配路径的末尾 22 | */ 23 | private UrlTreeNode wildNode; 24 | /** 25 | * 下个结点的map 26 | */ 27 | private Map next = new HashMap<>(); 28 | 29 | public Integer index() { 30 | return index; 31 | } 32 | 33 | public void setIndex(Integer index) { 34 | this.index = index; 35 | } 36 | 37 | public Function func() { 38 | return func; 39 | } 40 | 41 | public void setFunc(Function func) { 42 | this.func = func; 43 | } 44 | 45 | public UrlTreeNode wildNode() { 46 | return wildNode; 47 | } 48 | 49 | public void setWildNode(UrlTreeNode wildNode) { 50 | this.wildNode = wildNode; 51 | } 52 | 53 | public Map next() { 54 | return next; 55 | } 56 | 57 | /** 58 | * 将所有子结点的map结构转化为不可变,使其并发安全并提升访问性能 59 | */ 60 | public void sync() { 61 | if(wildNode != null) { 62 | wildNode.sync(); 63 | } 64 | if(next.isEmpty()) { 65 | next = Collections.emptyMap(); 66 | }else { 67 | next = Collections.unmodifiableMap(next); 68 | for (UrlTreeNode node : next.values()) { 69 | node.sync(); 70 | } 71 | } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/context/ContextTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.context; 2 | 3 | import cn.zorcc.common.AbstractLifeCycle; 4 | import cn.zorcc.common.Context; 5 | import cn.zorcc.common.log.Logger; 6 | import cn.zorcc.common.structure.Wheel; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.time.Duration; 10 | 11 | public class ContextTest { 12 | private static final Logger log = new Logger(ContextTest.class); 13 | static class LifeCycleTest extends AbstractLifeCycle { 14 | @Override 15 | protected void doInit() { 16 | log.info("Init called"); 17 | } 18 | 19 | @Override 20 | protected void doExit() { 21 | log.info("Exit called"); 22 | } 23 | } 24 | 25 | @Test 26 | public void testContext() throws InterruptedException { 27 | Context.load(new LifeCycleTest(), LifeCycleTest.class); 28 | Context.init(); 29 | Runnable exitOnce = Wheel.wheel().addJob(() -> log.info(STR."onetime\{Thread.currentThread().threadId()}"), Duration.ofSeconds(5)); 30 | exitOnce.run(); 31 | Runnable exitPeriod = Wheel.wheel().addPeriodicJob(() -> log.info(String.valueOf(Thread.currentThread().threadId())), Duration.ZERO, Duration.ofSeconds(1)); 32 | Thread.sleep(5000); 33 | exitPeriod.run(); 34 | Thread.sleep(Long.MAX_VALUE); 35 | } 36 | 37 | @Test 38 | public void testWheel() throws InterruptedException { 39 | Context.init(); 40 | Wheel.wheel().addPeriodicJob(() -> log.debug("1"), Duration.ZERO, Duration.ofSeconds(1)); 41 | Wheel.wheel().addJob(() -> log.info("hello"), Duration.ofSeconds(5)); 42 | Wheel.wheel().addPeriodicJob(() -> log.debug("2"), Duration.ZERO, Duration.ofSeconds(3)); 43 | Wheel.wheel().addJob(() -> log.info("world"), Duration.ofSeconds(10)); 44 | Thread.sleep(Long.MAX_VALUE); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/SocketConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.serde.Serde; 4 | 5 | @Serde 6 | public final class SocketConfig { 7 | /** 8 | * Whether allow reuse addr, only affect server socket, recommended to open 9 | */ 10 | private boolean reuseAddr = true; 11 | /** 12 | * Whether using tcp heartbeat, recommended to close, application should develop heartbeat mechanism in their protocol level 13 | */ 14 | private boolean keepAlive = false; 15 | /** 16 | * Whether closing Nagle algorithm, recommended to open, so every packet gets flushed immediately 17 | */ 18 | private boolean tcpNoDelay = true; 19 | /** 20 | * If this option is set to true, then master with IPv6 loc specified will only receive IPv6 connections 21 | * this option is recommended to be closed, so a dual ipv4-ipv6 stack will co-exist when using IPv6 server socket 22 | */ 23 | private boolean ipv6Only = false; 24 | 25 | public SocketConfig setReuseAddr(boolean reuseAddr) { 26 | this.reuseAddr = reuseAddr; 27 | return this; 28 | } 29 | 30 | public SocketConfig setKeepAlive(boolean keepAlive) { 31 | this.keepAlive = keepAlive; 32 | return this; 33 | } 34 | 35 | public SocketConfig setTcpNoDelay(boolean tcpNoDelay) { 36 | this.tcpNoDelay = tcpNoDelay; 37 | return this; 38 | } 39 | 40 | public SocketConfig setIpv6Only(boolean ipv6Only) { 41 | this.ipv6Only = ipv6Only; 42 | return this; 43 | } 44 | 45 | public boolean isReuseAddr() { 46 | return reuseAddr; 47 | } 48 | 49 | public boolean isKeepAlive() { 50 | return keepAlive; 51 | } 52 | 53 | public boolean isTcpNoDelay() { 54 | return tcpNoDelay; 55 | } 56 | 57 | public boolean isIpv6Only() { 58 | return ipv6Only; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/http/HttpResponse.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.http; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | import java.lang.foreign.MemorySegment; 6 | 7 | /** 8 | * Http response abstraction 9 | */ 10 | public final class HttpResponse { 11 | /** 12 | * Http version, default would be HTTP1.1 13 | */ 14 | private String version = Constants.DEFAULT_HTTP_VERSION; 15 | /** 16 | * Http status code, default would be 200 17 | */ 18 | private HttpStatus status = HttpStatus.OK; 19 | /** 20 | * Http headers, must exist 21 | */ 22 | private HttpHeader headers = new HttpHeader(); 23 | /** 24 | * Http compression status 25 | */ 26 | private HttpCompressionStatus compressionStatus = HttpCompressionStatus.NONE; 27 | /** 28 | * Http content data, normally would be json UTF-8 bytes, could be null for chunked data 29 | */ 30 | private MemorySegment data; 31 | 32 | public String getVersion() { 33 | return version; 34 | } 35 | 36 | public void setVersion(String version) { 37 | this.version = version; 38 | } 39 | 40 | public HttpStatus getStatus() { 41 | return status; 42 | } 43 | 44 | public void setStatus(HttpStatus status) { 45 | this.status = status; 46 | } 47 | 48 | public HttpHeader getHeaders() { 49 | return headers; 50 | } 51 | 52 | public void setHeaders(HttpHeader headers) { 53 | this.headers = headers; 54 | } 55 | 56 | public HttpCompressionStatus getCompressionStatus() { 57 | return compressionStatus; 58 | } 59 | 60 | public void setCompressionStatus(HttpCompressionStatus compressionStatus) { 61 | this.compressionStatus = compressionStatus; 62 | } 63 | 64 | public MemorySegment getData() { 65 | return data; 66 | } 67 | 68 | public void setData(MemorySegment data) { 69 | this.data = data; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/beans/City.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.beans; 2 | 3 | import java.util.Objects; 4 | 5 | public class City { 6 | private int population; 7 | private double area; 8 | private boolean capital; 9 | private char category; 10 | private long elevation; 11 | private String name; 12 | 13 | public int getPopulation() { 14 | return population; 15 | } 16 | 17 | public void setPopulation(int population) { 18 | this.population = population; 19 | } 20 | 21 | public double getArea() { 22 | return area; 23 | } 24 | 25 | public void setArea(double area) { 26 | this.area = area; 27 | } 28 | 29 | public boolean isCapital() { 30 | return capital; 31 | } 32 | 33 | public void setCapital(boolean capital) { 34 | this.capital = capital; 35 | } 36 | 37 | public char getCategory() { 38 | return category; 39 | } 40 | 41 | public void setCategory(char category) { 42 | this.category = category; 43 | } 44 | 45 | public long getElevation() { 46 | return elevation; 47 | } 48 | 49 | public void setElevation(long elevation) { 50 | this.elevation = elevation; 51 | } 52 | 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | public void setName(String name) { 58 | this.name = name; 59 | } 60 | 61 | @Override 62 | public boolean equals(Object o) { 63 | if (this == o) return true; 64 | if (o == null || getClass() != o.getClass()) return false; 65 | City city = (City) o; 66 | return population == city.population && Double.compare(area, city.area) == 0 && capital == city.capital && category == city.category && elevation == city.elevation && Objects.equals(name, city.name); 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | return Objects.hash(population, area, capital, category, elevation, name); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/CodeBlock.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.List; 10 | 11 | /** 12 | * Code block represents a chunk of code-lines, designed to help control over the indent issue 13 | */ 14 | public final class CodeBlock { 15 | 16 | public static CodeBlock IGNORED = new CodeBlock(); 17 | 18 | private List contents; 19 | private int currentIndent; 20 | 21 | public CodeBlock addLine(String content) { 22 | if(contents == null) { 23 | contents = new ArrayList<>(); 24 | } 25 | contents.add(new Content(content, currentIndent)); 26 | return this; 27 | } 28 | 29 | public CodeBlock addBlock(CodeBlock c) { 30 | if(c == IGNORED) { 31 | return this; 32 | } 33 | if(contents == null) { 34 | contents = new ArrayList<>(); 35 | } 36 | for (Content ct : c.contents) { 37 | contents.add(new Content(ct.value(), currentIndent + ct.indent())); 38 | } 39 | return this; 40 | } 41 | 42 | public CodeBlock addBlocks(Collection cs) { 43 | for (CodeBlock c : cs) { 44 | CodeBlock _ = addBlock(c); 45 | } 46 | return this; 47 | } 48 | 49 | public CodeBlock newLine() { 50 | if(contents == null) { 51 | contents = new ArrayList<>(); 52 | } 53 | contents.add(new Content("", currentIndent)); 54 | return this; 55 | } 56 | 57 | public CodeBlock indent() { 58 | currentIndent++; 59 | return this; 60 | } 61 | 62 | public CodeBlock unindent() { 63 | if(--currentIndent < 0) { 64 | throw new FrameworkException(ExceptionType.ANNO, Constants.UNREACHED); 65 | } 66 | return this; 67 | } 68 | 69 | public List contents() { 70 | return List.copyOf(contents); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Base.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | /** 6 | * Default design specification for database tables 7 | */ 8 | public abstract class Base implements Filler { 9 | 10 | /** 11 | * Auto increment id column 12 | */ 13 | @Id() 14 | private Long id; 15 | 16 | /** 17 | * Create time column, will be auto-generated when performing insert operation 18 | */ 19 | @Col(value = "created_at") 20 | private LocalDateTime createdAt; 21 | 22 | /** 23 | * Modify time column, will be auto-generated when performing update operation 24 | * Note that if using logical-delete, then this column will also be updated when performing delete operation 25 | */ 26 | @Col(value = "modified_at") 27 | private LocalDateTime modifiedAt; 28 | 29 | /** 30 | * Logical delete field, false when the record does exist, true when the record was deleted 31 | */ 32 | @Del(value = "deleted") 33 | private Boolean deleted; 34 | 35 | @Override 36 | public void onInsert() { 37 | if (deleted == null) { 38 | setDeleted(Boolean.FALSE); 39 | } 40 | if (createdAt == null) { 41 | setCreatedAt(LocalDateTime.now()); 42 | } 43 | } 44 | 45 | @Override 46 | public void onUpdate() { 47 | setModifiedAt(LocalDateTime.now()); 48 | } 49 | 50 | public Long id() { 51 | return id; 52 | } 53 | 54 | public void setId(Long id) { 55 | this.id = id; 56 | } 57 | 58 | public LocalDateTime createdAt() { 59 | return createdAt; 60 | } 61 | 62 | public void setCreatedAt(LocalDateTime createdAt) { 63 | this.createdAt = createdAt; 64 | } 65 | 66 | public LocalDateTime modifiedAt() { 67 | return modifiedAt; 68 | } 69 | 70 | public void setModifiedAt(LocalDateTime modifiedAt) { 71 | this.modifiedAt = modifiedAt; 72 | } 73 | 74 | public Boolean deleted() { 75 | return deleted; 76 | } 77 | 78 | public void setDeleted(Boolean deleted) { 79 | this.deleted = deleted; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgManager.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.LifeCycle; 6 | import cn.zorcc.common.exception.FrameworkException; 7 | import cn.zorcc.common.log.Logger; 8 | import cn.zorcc.common.network.Loc; 9 | import cn.zorcc.common.network.Net; 10 | import cn.zorcc.orm.PgConfig; 11 | 12 | import java.util.concurrent.LinkedTransferQueue; 13 | import java.util.concurrent.TransferQueue; 14 | import java.util.concurrent.atomic.AtomicBoolean; 15 | import java.util.concurrent.locks.Lock; 16 | import java.util.concurrent.locks.ReentrantLock; 17 | 18 | /** 19 | * The main postgresql manager for handling all incoming msg 20 | */ 21 | public final class PgManager implements LifeCycle { 22 | private static final Logger log = new Logger(PgManager.class); 23 | private final Net net; 24 | private final PgConfig pgConfig; 25 | private final TransferQueue connPool = new LinkedTransferQueue<>(); 26 | private final AtomicBoolean running = new AtomicBoolean(false); 27 | private final Lock lock = new ReentrantLock(); 28 | 29 | public PgManager(Net net, PgConfig pgConfig) { 30 | this.net = net; 31 | this.pgConfig = pgConfig; 32 | } 33 | 34 | public PgConfig pgConfig() { 35 | return pgConfig; 36 | } 37 | 38 | public void registerConn(PgConn conn) { 39 | if (!connPool.offer(conn)) { 40 | throw new FrameworkException(ExceptionType.CONTEXT, Constants.UNREACHED); 41 | } 42 | } 43 | 44 | public PgConn get() { 45 | try { 46 | return connPool.take(); 47 | } catch (InterruptedException e) { 48 | Thread.currentThread().interrupt(); 49 | throw new FrameworkException(ExceptionType.SQL, "thread interrupt", e); 50 | } 51 | } 52 | 53 | 54 | 55 | @Override 56 | public void init() { 57 | Loc loc = pgConfig.getLoc(); 58 | new PgEncoder(); 59 | new PgDecoder(); 60 | new PgHandler(this); 61 | // net.connect(loc, ); 62 | } 63 | 64 | @Override 65 | public void exit() { 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/database/Mapper.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.database; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | 6 | /** 7 | * Mapper is a generic structure designed to help developers save time writing simple SQL 8 | */ 9 | public interface Mapper { 10 | 11 | /** 12 | * Insert a record, this method will only process the non-null fields in the po 13 | */ 14 | int insert(T po); 15 | 16 | /** 17 | * Insert batch record, process all the fields 18 | * Note that the user must safely configure the batch size when using this method, dividing a big batch into several small one would be much better 19 | */ 20 | int insertBatch(Collection poCollection); 21 | 22 | /** 23 | * Delete a record base on where condition 24 | */ 25 | int delete(Where where); 26 | 27 | /** 28 | * Delete a record based on id 29 | */ 30 | int deleteById(Object id); 31 | 32 | /** 33 | * Delete several records based on Ids 34 | */ 35 | int deleteByIds(Collection idCollection); 36 | 37 | /** 38 | * Update records based on where condition 39 | * Note that this method will only process the non-null fields, if you want to set some field to null, use a DynamicSqlMapper instead 40 | */ 41 | int update(T po, Where where); 42 | 43 | /** 44 | * Update record based on id column 45 | */ 46 | int updateById(T po); 47 | 48 | /** 49 | * Select a record based on id column 50 | */ 51 | T selectById(Object id); 52 | 53 | /** 54 | * Select records based on id column 55 | */ 56 | List selectByIds(Collection idCollection); 57 | 58 | /** 59 | * Select records based on where 60 | */ 61 | List select(Where where); 62 | 63 | /** 64 | * Select a record based on id column, throw an exception if multiple records return 65 | */ 66 | T selectOne(Where where); 67 | 68 | /** 69 | * Select count(*) based on Where 70 | */ 71 | long count(Where where); 72 | 73 | /** 74 | * Select a page based on Where 75 | */ 76 | Page page(Long pageNo, Long pageSize, Where where); 77 | } 78 | -------------------------------------------------------------------------------- /network-model.md: -------------------------------------------------------------------------------- 1 | # Network model 2 | 3 | ## Overview 4 | 5 | The whole tenet networking part is quite simple, the main components are : 6 | 7 | 1. `Encoder`, Encoder determines how your POJO should be encoded into a WriteBuffer for transferring 8 | 2. `Decoder`, Decoder determines how to decode a POJO from the target ReadBuffer 9 | 3. `Handler`, Handler is where you put your specific business logic, to process the data received 10 | 4. `Provider`, Provider determines how a Sentry object could be created, and what to be done when the application exit 11 | 12 | About concrete networking protocol, they are divided into two phases: 13 | 14 | 1. `Sentry` phase, where the read-write model are fully controlled by developers only, all the stuff like Encoder, Decoder, Handler are not functional yet, during sentry phase, the connection must have been well established, and ready for further exchange of data 15 | 2. `Protocol` phase, where Encoder, Decoder, Handler would take over the control, reading from channel and writing data to channel are well organized by tenet 16 | 17 | ## Threading model 18 | 19 | Each TCP connection will be represented as an `Channel`, the `Channel` was first mounted on a `Poller` thread in `Sentry` phase, if it successfully upgraded to `Protocol` phase, it will be also mounted on `Writer` thread. 20 | All the server socket were registered to a single `Net` thread, and the default `Poller` and `Writer` threads are the number of your CPU cores. 21 | `Poller` thread will handle the reading part of the socket, `Writer` thread will handle the writing part of the socket, the access to the critical section will be managed through a locking mechanism. 22 | 23 | ## Example 24 | 25 | A small `echo` example could be found in [echo example](https://github.com/microhardsmith/tenet/blob/master/common/src/test/java/cn/zorcc/common/network/EchoTest.java) 26 | A simple `http` example could be found in [http example](https://github.com/microhardsmith/tenet/blob/master/common/src/test/java/cn/zorcc/common/network/HttpTest.java) 27 | 28 | Note that in order to run tenet application, you need to specify some arguments in system properties: 29 | 30 | ```shell 31 | --enable-preview 32 | --enable-native-access=ALL-UNNAMED 33 | -DTENET_LIBRARY_PATH=/path/to/lib 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/sqlite/SqliteConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.sqlite; 2 | 3 | public final class SqliteConfig { 4 | /** 5 | * The absolute path of the sqlite db files 6 | */ 7 | private String path; 8 | /** 9 | * The number of the reader threads 10 | */ 11 | private int readers; 12 | /** 13 | * Whether using WAL mechanism 14 | */ 15 | private boolean usingWAL; 16 | /** 17 | * Whether enabling remote discovery 18 | */ 19 | private boolean enableDiscovery; 20 | /** 21 | * Whether enabling remote configuration 22 | */ 23 | private boolean enableConfiguration; 24 | /** 25 | * Whether enabling remote distributed lock 26 | */ 27 | private boolean enableDistributedLock; 28 | 29 | public String getPath() { 30 | return path; 31 | } 32 | 33 | public SqliteConfig setPath(String path) { 34 | this.path = path; 35 | return this; 36 | } 37 | 38 | public int getReaders() { 39 | return readers; 40 | } 41 | 42 | public SqliteConfig setReaders(int readers) { 43 | this.readers = readers; 44 | return this; 45 | } 46 | 47 | public boolean isUsingWAL() { 48 | return usingWAL; 49 | } 50 | 51 | public SqliteConfig setUsingWAL(boolean usingWAL) { 52 | this.usingWAL = usingWAL; 53 | return this; 54 | } 55 | 56 | public boolean isEnableDiscovery() { 57 | return enableDiscovery; 58 | } 59 | 60 | public SqliteConfig setEnableDiscovery(boolean enableDiscovery) { 61 | this.enableDiscovery = enableDiscovery; 62 | return this; 63 | } 64 | 65 | public boolean isEnableConfiguration() { 66 | return enableConfiguration; 67 | } 68 | 69 | public SqliteConfig setEnableConfiguration(boolean enableConfiguration) { 70 | this.enableConfiguration = enableConfiguration; 71 | return this; 72 | } 73 | 74 | public boolean isEnableDistributedLock() { 75 | return enableDistributedLock; 76 | } 77 | 78 | public SqliteConfig setEnableDistributedLock(boolean enableDistributedLock) { 79 | this.enableDistributedLock = enableDistributedLock; 80 | return this; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | tenet 5 | cn.zorcc 6 | 0.0.1 7 | 8 | 4.0.0 9 | tenet-common 10 | jar 11 | 12 | 13 | 14 | org.jctools 15 | jctools-core 16 | ${jctools.version} 17 | 18 | 19 | 20 | 21 | com.ongres.scram 22 | client 23 | ${scram.version} 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-assembly-plugin 32 | ${maven-assembly-plugin.version} 33 | 34 | 35 | package 36 | 37 | single 38 | 39 | 40 | 41 | 42 | cn.zorcc.common.LaunchTest 43 | 44 | 45 | 46 | jar-with-dependencies 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/metrics/Metrics.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.metrics; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.OsType; 6 | import cn.zorcc.common.exception.FrameworkException; 7 | import cn.zorcc.common.util.NativeUtil; 8 | 9 | import java.lang.foreign.FunctionDescriptor; 10 | import java.lang.foreign.MemorySegment; 11 | import java.lang.foreign.SegmentAllocator; 12 | import java.lang.foreign.ValueLayout; 13 | import java.lang.invoke.MethodHandle; 14 | 15 | public final class Metrics { 16 | /** 17 | * Note that load average will not be supported on windows, thus always returning -1d 18 | */ 19 | private static final MethodHandle loadAverage; 20 | 21 | static { 22 | OsType ostype = NativeUtil.ostype(); 23 | if(ostype == OsType.Windows) { 24 | loadAverage = null; 25 | }else if(ostype == OsType.Linux || ostype == OsType.MacOS) { 26 | loadAverage = NativeUtil.nativeMethodHandle("getloadavg", FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_INT)); 27 | }else { 28 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 29 | } 30 | } 31 | 32 | private static int getLoadAverage(MemorySegment ptr) { 33 | try{ 34 | return (int) loadAverage.invokeExact(ptr, 3); 35 | }catch (Throwable throwable) { 36 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 37 | } 38 | } 39 | 40 | public static CpuLoadAverage getLoadAverage(SegmentAllocator allocator) { 41 | if(loadAverage == null) { 42 | return CpuLoadAverage.UNSUPPORTED; 43 | } 44 | MemorySegment ptr = allocator.allocate(ValueLayout.JAVA_DOUBLE, 3); 45 | int n = Metrics.getLoadAverage(ptr); 46 | if(n < 3) { 47 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 48 | } 49 | double l1 = ptr.get(ValueLayout.JAVA_DOUBLE_UNALIGNED, 0L); 50 | double l2 = ptr.get(ValueLayout.JAVA_DOUBLE_UNALIGNED, Double.BYTES); 51 | double l3 = ptr.get(ValueLayout.JAVA_DOUBLE_UNALIGNED, 2 * Double.BYTES); 52 | return new CpuLoadAverage(l1, l2, l3); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.network.Loc; 5 | import cn.zorcc.common.util.NativeUtil; 6 | 7 | public final class PgConfig { 8 | /** 9 | * Postgresql database server location 10 | */ 11 | private Loc loc; 12 | /** 13 | * Postgresql database username 14 | */ 15 | private String userName; 16 | /** 17 | * Postgresql database password 18 | */ 19 | private String password; 20 | /** 21 | * Postgresql database name 22 | */ 23 | private String databaseName = "postgres"; 24 | /** 25 | * Postgresql database schema 26 | */ 27 | private String currentSchema = "public"; 28 | /** 29 | * The default ssl connection mode, could be: prefer, verify-ca, verify-full 30 | */ 31 | private String sslMode = Constants.PG_SSL_PREFER; 32 | private Integer maxConn = NativeUtil.getCpuCores(); 33 | 34 | public Loc getLoc() { 35 | return loc; 36 | } 37 | 38 | public void setLoc(Loc loc) { 39 | this.loc = loc; 40 | } 41 | 42 | public String getUserName() { 43 | return userName; 44 | } 45 | 46 | public void setUserName(String userName) { 47 | this.userName = userName; 48 | } 49 | 50 | public String getPassword() { 51 | return password; 52 | } 53 | 54 | public void setPassword(String password) { 55 | this.password = password; 56 | } 57 | 58 | public String getDatabaseName() { 59 | return databaseName; 60 | } 61 | 62 | public void setDatabaseName(String databaseName) { 63 | this.databaseName = databaseName; 64 | } 65 | 66 | public String getCurrentSchema() { 67 | return currentSchema; 68 | } 69 | 70 | public void setCurrentSchema(String currentSchema) { 71 | this.currentSchema = currentSchema; 72 | } 73 | 74 | public String getSslMode() { 75 | return sslMode; 76 | } 77 | 78 | public void setSslMode(String sslMode) { 79 | this.sslMode = sslMode; 80 | } 81 | 82 | public Integer getMaxConn() { 83 | return maxConn; 84 | } 85 | 86 | public void setMaxConn(Integer maxConn) { 87 | this.maxConn = maxConn; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/structure/RefTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.Ref; 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.concurrent.BlockingQueue; 11 | import java.util.concurrent.LinkedTransferQueue; 12 | import java.util.concurrent.atomic.AtomicReferenceArray; 13 | 14 | public class RefTest { 15 | private static final int BATCH_SIZE = 100000; 16 | private static final AtomicReferenceArray arr = new AtomicReferenceArray<>(BATCH_SIZE); 17 | 18 | @Test 19 | public void testRef() throws InterruptedException { 20 | for (int i = 0; i < BATCH_SIZE; i++) { 21 | arr.set(i, 0); 22 | } 23 | BlockingQueue queue = new LinkedTransferQueue<>(); 24 | Thread consumer = Thread.ofPlatform().start(() -> { 25 | for (int i = 0; i < BATCH_SIZE; i++) { 26 | try { 27 | Ref ref = queue.take(); 28 | ref.assign(i); 29 | } catch (InterruptedException e) { 30 | throw new RuntimeException(Constants.UNREACHED, e); 31 | } 32 | } 33 | }); 34 | List threads = new ArrayList<>(BATCH_SIZE); 35 | for(int i = 0; i < BATCH_SIZE; i++) { 36 | threads.add(Thread.ofVirtual().start(() -> { 37 | Ref ref = new Ref(); 38 | if (queue.offer(ref)) { 39 | Object r = ref.fetch(); 40 | if(r instanceof Integer index && index >= 0 && index < arr.length() && arr.get(index) == 0) { 41 | arr.set(index, 1); 42 | return ; 43 | } else { 44 | throw new RuntimeException("Illegal ref : %s".formatted(r)); 45 | } 46 | } 47 | throw new RuntimeException(Constants.UNREACHED); 48 | })); 49 | } 50 | consumer.join(); 51 | for (Thread t : threads) { 52 | t.join(); 53 | } 54 | for (int i = 0; i < BATCH_SIZE; i++) { 55 | Assertions.assertEquals(arr.get(i), 1); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/Handler.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import java.util.Optional; 4 | 5 | /** 6 | * Handler represents the actual business logic that a channel should perform in Protocol phase 7 | */ 8 | public interface Handler { 9 | 10 | /** 11 | * If connection failed in Sentry phase, this function would be invoked 12 | * Note that you can't do much in this callback function, try sending message would be impossible (also no side effect) 13 | * It's suggested to only do logging in this function, or schedule a reconnect 14 | */ 15 | void onFailed(Channel channel); 16 | 17 | /** 18 | * After channel got connected, this function would be invoked 19 | * The definition of connected means the Sentry has been successfully upgraded to Protocol 20 | * If a RuntimeException was thrown in this function, the channel would be immediately closed to guard the application 21 | */ 22 | void onConnected(Channel channel); 23 | 24 | /** 25 | * After data were received, this function would be invoked in poller thread, business logic should be put here 26 | * Note that the data object was generated by channel's decoder, if decode() return null then this function won't be invoked 27 | * If a RuntimeException was thrown in this function, the channel would be immediately closed to guard the application 28 | */ 29 | Optional onRecv(Channel channel, Object data); 30 | 31 | /** 32 | * Before channel was going to shut down, this function would be invoked in caller thread 33 | * For most use cases, this function is used to send some goodbye message to perform a graceful shutdown 34 | * If a RuntimeException was thrown in this function, the channel would be immediately closed to guard the application 35 | */ 36 | void onShutdown(Channel channel); 37 | 38 | /** 39 | * After connection was closed, this function would be invoked 40 | * Note that you can't expect sending some data in this function, since the connection has already been closed 41 | * If connection failed in Sentry phase (in which case onFailed() would be invoked), this function would never be triggered (if there's an onConnected(), there is an onRemoved(), vice versa) 42 | */ 43 | void onRemoved(Channel channel); 44 | } 45 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgVariable.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | import com.ongres.scram.client.ScramClient; 4 | import com.ongres.scram.client.ScramSession; 5 | 6 | import java.util.LinkedHashMap; 7 | import java.util.Map; 8 | 9 | public class PgVariable { 10 | public static final String ERR = "Err state detected"; 11 | public static final int INITIAL = 0; 12 | public static final int WAITING_AUTH_OK = 1; 13 | public static final int AUTH_OK = 2; 14 | 15 | private int state = INITIAL; 16 | 17 | private ScramClient scramClient = null; 18 | 19 | private ScramSession scramSession = null; 20 | 21 | private ScramSession.ClientFinalProcessor clientFinalProcessor = null; 22 | 23 | private int processId; 24 | 25 | private int secretKey; 26 | 27 | private Map parameterStatus = new LinkedHashMap<>(); 28 | 29 | public PgVariable() { 30 | } 31 | 32 | public int getState() { 33 | return this.state; 34 | } 35 | 36 | public ScramClient getScramClient() { 37 | return this.scramClient; 38 | } 39 | 40 | public ScramSession getScramSession() { 41 | return this.scramSession; 42 | } 43 | 44 | public ScramSession.ClientFinalProcessor getClientFinalProcessor() { 45 | return this.clientFinalProcessor; 46 | } 47 | 48 | public int getProcessId() { 49 | return this.processId; 50 | } 51 | 52 | public int getSecretKey() { 53 | return this.secretKey; 54 | } 55 | 56 | public Map getParameterStatus() { 57 | return this.parameterStatus; 58 | } 59 | 60 | public void setState(int state) { 61 | this.state = state; 62 | } 63 | 64 | public void setScramClient(ScramClient scramClient) { 65 | this.scramClient = scramClient; 66 | } 67 | 68 | public void setScramSession(ScramSession scramSession) { 69 | this.scramSession = scramSession; 70 | } 71 | 72 | public void setClientFinalProcessor(ScramSession.ClientFinalProcessor clientFinalProcessor) { 73 | this.clientFinalProcessor = clientFinalProcessor; 74 | } 75 | 76 | public void setProcessId(int processId) { 77 | this.processId = processId; 78 | } 79 | 80 | public void setSecretKey(int secretKey) { 81 | this.secretKey = secretKey; 82 | } 83 | 84 | public void setParameterStatus(Map parameterStatus) { 85 | this.parameterStatus = parameterStatus; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/jmh/MemAccessTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.jmh; 2 | 3 | import cn.zorcc.common.util.NativeUtil; 4 | import org.openjdk.jmh.annotations.Benchmark; 5 | import org.openjdk.jmh.annotations.Setup; 6 | import org.openjdk.jmh.annotations.TearDown; 7 | import org.openjdk.jmh.infra.Blackhole; 8 | import org.openjdk.jmh.runner.RunnerException; 9 | 10 | import java.lang.foreign.Arena; 11 | import java.lang.foreign.MemorySegment; 12 | import java.lang.foreign.ValueLayout; 13 | 14 | /** 15 | * MemTest.testAlignedAccess avgt 25 75.096 ± 0.833 ns/op 16 | * MemTest.testDefaultAccess avgt 25 74.359 ± 0.712 ns/op 17 | * MemTest.testDefaultUnalignedAccess avgt 25 74.812 ± 1.313 ns/op 18 | * MemTest.testUnalignedAccess avgt 25 91.217 ± 0.948 ns/op 19 | * Conclusion : Unaligned access would be slower than Aligned, but not quite much 20 | */ 21 | public class MemAccessTest extends JmhTest { 22 | private static final int COUNT = 1000; 23 | private Arena arena; 24 | private MemorySegment memorySegment; 25 | @Setup 26 | public void setup() { 27 | arena = Arena.ofConfined(); 28 | memorySegment = arena.allocate(ValueLayout.JAVA_LONG, COUNT); 29 | } 30 | 31 | @Benchmark 32 | public void testDefaultAccess(Blackhole blackhole) { 33 | for(int i = 0; i < COUNT - 1; i++) { 34 | blackhole.consume(memorySegment.get(ValueLayout.JAVA_LONG, (long) Long.BYTES * i)); 35 | } 36 | } 37 | 38 | @Benchmark 39 | public void testDefaultUnalignedAccess(Blackhole blackhole) { 40 | for(int i = 0; i < COUNT - 1; i++) { 41 | blackhole.consume(memorySegment.get(ValueLayout.JAVA_LONG, (long) Long.BYTES * i)); 42 | } 43 | } 44 | 45 | 46 | @Benchmark 47 | public void testUnalignedAccess(Blackhole blackhole) { 48 | for(int i = 0; i < COUNT - 1; i++) { 49 | blackhole.consume(NativeUtil.getLong(memorySegment, (long) Long.BYTES * i + 1L)); 50 | } 51 | } 52 | 53 | @Benchmark 54 | public void testAlignedAccess(Blackhole blackhole) { 55 | for(int i = 0; i < COUNT - 1; i++) { 56 | blackhole.consume(NativeUtil.getLong(memorySegment, (long) Long.BYTES * i)); 57 | } 58 | } 59 | 60 | @TearDown 61 | public void tearDown() { 62 | arena.close(); 63 | } 64 | 65 | public static void main(String[] args) throws RunnerException { 66 | runTest(MemAccessTest.class); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/json/JsonTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.json; 2 | 3 | import cn.zorcc.common.beans.Book; 4 | import cn.zorcc.common.beans.City; 5 | import cn.zorcc.common.log.LogConfig; 6 | import cn.zorcc.common.structure.ReadBuffer; 7 | import cn.zorcc.common.structure.WriteBuffer; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import java.lang.foreign.MemorySegment; 12 | import java.nio.charset.StandardCharsets; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public class JsonTest { 17 | @Test 18 | public void testCity() { 19 | City c1 = new City(); 20 | c1.setName("New York"); 21 | c1.setPopulation(8537673); 22 | c1.setArea(783.8); 23 | c1.setCapital(false); 24 | c1.setCategory('A'); 25 | c1.setElevation(10); 26 | try(WriteBuffer writeBuffer = WriteBuffer.newHeapWriteBuffer()) { 27 | JsonParser.writeObject(writeBuffer, c1); 28 | String serializeResult = writeBuffer.toString(); 29 | System.out.println(serializeResult); 30 | City c2 = JsonParser.readObject(new ReadBuffer(MemorySegment.ofArray(serializeResult.getBytes(StandardCharsets.UTF_8))), City.class); 31 | Assertions.assertEquals(c1, c2); 32 | } 33 | } 34 | 35 | @Test 36 | public void testBook() { 37 | Book b1 = new Book(); 38 | b1.setId(Long.MAX_VALUE); 39 | b1.setNames(List.of("hello","world","goodbye")); 40 | b1.setMap(Map.of("a", List.of(1,2,3), "b", List.of(4,5,6))); 41 | try(WriteBuffer writeBuffer = WriteBuffer.newHeapWriteBuffer()) { 42 | JsonParser.writeObject(writeBuffer, b1); 43 | String serializeResult = writeBuffer.toString(); 44 | System.out.println(serializeResult); 45 | Book b2 = JsonParser.readObject(new ReadBuffer(MemorySegment.ofArray(serializeResult.getBytes(StandardCharsets.UTF_8))), Book.class); 46 | Assertions.assertEquals(b1, b2); 47 | } 48 | } 49 | 50 | @Test 51 | public void testEmpty() { 52 | String s = """ 53 | { 54 | "file" : {} 55 | } 56 | """; 57 | ReadBuffer readBuffer = new ReadBuffer(MemorySegment.ofArray(s.getBytes(StandardCharsets.UTF_8))); 58 | LogConfig logConfig = JsonParser.readObject(readBuffer, LogConfig.class); 59 | System.out.println(logConfig.getFile().getDir()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/DefaultTimeResolver.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.structure.WriteBuffer; 5 | import cn.zorcc.common.util.NativeUtil; 6 | 7 | import java.lang.foreign.MemorySegment; 8 | import java.time.LocalDateTime; 9 | 10 | /** 11 | * A default time-resolver for TIME_FORMAT 12 | */ 13 | public final class DefaultTimeResolver implements TimeResolver { 14 | @Override 15 | public MemorySegment format(LocalDateTime time) { 16 | try(WriteBuffer writeBuffer = WriteBuffer.newHeapWriteBuffer(Constants.DEFAULT_TIME_FORMAT.length())) { 17 | int year = time.getYear(); 18 | int month = time.getMonthValue(); 19 | int day = time.getDayOfMonth(); 20 | int hour = time.getHour(); 21 | int minute = time.getMinute(); 22 | int second = time.getSecond(); 23 | int milli = time.getNano() / 1_000_000; 24 | writeBuffer.writeByte(NativeUtil.toAsciiByte(year / 1000)); 25 | writeBuffer.writeByte(NativeUtil.toAsciiByte((year / 100) % 10)); 26 | writeBuffer.writeByte(NativeUtil.toAsciiByte((year / 10) % 10)); 27 | writeBuffer.writeByte(NativeUtil.toAsciiByte(year % 10)); 28 | writeBuffer.writeByte(Constants.HYPHEN); 29 | writeBuffer.writeByte(NativeUtil.toAsciiByte(month / 10)); 30 | writeBuffer.writeByte(NativeUtil.toAsciiByte(month % 10)); 31 | writeBuffer.writeByte(Constants.HYPHEN); 32 | writeBuffer.writeByte(NativeUtil.toAsciiByte(day / 10)); 33 | writeBuffer.writeByte(NativeUtil.toAsciiByte(day % 10)); 34 | writeBuffer.writeByte(Constants.SPACE); 35 | writeBuffer.writeByte(NativeUtil.toAsciiByte(hour / 10)); 36 | writeBuffer.writeByte(NativeUtil.toAsciiByte(hour % 10)); 37 | writeBuffer.writeByte(Constants.COLON); 38 | writeBuffer.writeByte(NativeUtil.toAsciiByte(minute / 10)); 39 | writeBuffer.writeByte(NativeUtil.toAsciiByte(minute % 10)); 40 | writeBuffer.writeByte(Constants.COLON); 41 | writeBuffer.writeByte(NativeUtil.toAsciiByte(second / 10)); 42 | writeBuffer.writeByte(NativeUtil.toAsciiByte(second % 10)); 43 | writeBuffer.writeByte(Constants.PERIOD); 44 | writeBuffer.writeByte(NativeUtil.toAsciiByte(milli / 100)); 45 | writeBuffer.writeByte(NativeUtil.toAsciiByte((milli / 10) % 10)); 46 | writeBuffer.writeByte(NativeUtil.toAsciiByte(milli % 10)); 47 | return writeBuffer.asSegment(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/serde/SerdeContext.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.serde; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.lang.invoke.MethodHandles; 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Objects; 15 | import java.util.concurrent.locks.Lock; 16 | import java.util.concurrent.locks.ReentrantLock; 17 | import java.util.stream.Collectors; 18 | 19 | public final class SerdeContext { 20 | private static final Lock lock = new ReentrantLock(); 21 | private static final List, Handle>> entryList = new ArrayList<>(); 22 | private static final Map, Handle> handleMap; 23 | 24 | static { 25 | try(InputStream stream = SerdeContext.class.getResourceAsStream("/serde.txt")) { 26 | if(stream == null) { 27 | handleMap = Map.of(); 28 | } else { 29 | MethodHandles.Lookup lookup = MethodHandles.lookup(); 30 | try(BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { 31 | String className; 32 | while ((className = reader.readLine()) != null) { 33 | Class c = Class.forName(className); 34 | lookup.ensureInitialized(c); // trigger the static initializer 35 | } 36 | } 37 | handleMap = entryList.stream().collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); 38 | } 39 | } catch (Throwable e) { 40 | throw new FrameworkException(ExceptionType.CONTEXT, Constants.UNREACHED, e); 41 | } 42 | } 43 | 44 | /** 45 | * This function shouldn't be renamed, it will be used by generated source 46 | */ 47 | @SuppressWarnings("unused") 48 | public static void registerHandle(Class clazz, Handle handle) { 49 | lock.lock(); 50 | try { 51 | entryList.add(Map.entry(clazz, handle)); 52 | } finally { 53 | lock.unlock(); 54 | } 55 | } 56 | 57 | /** 58 | * Obtaining a handle from current SerdeContext, if the target clazz was not annotated with @Serde, then a NPE would be thrown 59 | */ 60 | @SuppressWarnings("unchecked") 61 | public static Handle getHandle(Class clazz) { 62 | return (Handle) Objects.requireNonNull(handleMap.get(clazz)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](https://github.com/microhardsmith/tenet-lib/blob/master/tenet.png) 2 | 3 | # Tenet Project Home 4 | 5 | This is the home page of the Tenet Project 6 | 7 | # Description 8 | 9 | Tenet is designed as several components that help you build microservices, which aims at simplicity and performance. 10 | 11 | The tenet of the Tenet project are: 12 | 13 | * All the components should stay as simple as possible, simplicity is our primary goal, The codebase should be kept at a moderate size, and the error stack traces as well as class inheritance relationships should also be maintained accordingly. 14 | * It's recommend that any developers who want to use Tenet project in their application read its source code first. The code should exhibit a relatively high level of readability, allowing all developers to easily grasp the author's intended ideas. 15 | * Performance would not be our first concern if it's conflicting the first two points. If there is a simple way to achieve significant performance boost, we will adopt it. However, if obtaining marginal gains requires a plethora of magic, such as bytecode generation, unsafe calls, and so forth, we prioritize simplicity. 16 | * We don't aim to solve the majority of issues in backend development; instead, we encourage developers to customize the functionality they desire based on the source code. 17 | 18 | # How to use 19 | 20 | Tenet application need both libraries from Maven repositories, but also need to load some native libraries in [tenet-lib](https://github.com/microhardsmith/tenet-lib) 21 | To run tenet application, you need to specify system properties : 22 | 23 | ```shell 24 | --enable-preview 25 | --enable-native-access=ALL-UNNAMED 26 | -DTENET_LIBRARY_PATH=/path/to/lib 27 | ``` 28 | 29 | Visit [tenet-lib](https://github.com/microhardsmith/tenet-lib) for more information. 30 | 31 | # Status 32 | 33 | The project is currently in the development stage, and we do not plan to make a full release until many Java preview features it relies on become production-ready. There are still numerous features to be implemented, and we are closely monitoring how Project Valhalla will impact the Java ecosystem. If you are interested in the Tenet project, feel free to reach out and get involved in the development. 34 | 35 | For now, the networking model has been implemented and there shouldn't be major changes in the future versions, you can get more information about it in [network-model](https://github.com/microhardsmith/tenet/blob/master/network-model.md) 36 | 37 | # Contact 38 | 39 | If you have any questions, suggestions, or would like to contribute to this project, feel free to reach out to me: 40 | 41 | - Email: benrush0705@gmail.com 42 | 43 | Looking forward to engaging with you and collaboratively advancing the project! 44 | 45 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/network/ListenerConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.serde.Serde; 4 | 5 | import java.util.function.Supplier; 6 | 7 | @Serde 8 | public final class ListenerConfig { 9 | 10 | /** 11 | * How master should provide encoder for server-side application, must be non-null 12 | */ 13 | private Supplier encoderSupplier; 14 | 15 | /** 16 | * How master should provide decoder for server-side application, must be non-null 17 | */ 18 | private Supplier decoderSupplier; 19 | 20 | /** 21 | * How master should provide handler for server-side application, must be non-null 22 | */ 23 | private Supplier handlerSupplier; 24 | 25 | /** 26 | * Target provider for server-side application, Net.tcpProvider() and Net.sslProvider() are recommended to use 27 | */ 28 | private Provider provider; 29 | /** 30 | * Target host:port to bind and listen 31 | * For Ipv6 server, it's recommended to listen on "::" 32 | * For Ipv4 server, it's recommended to listen on "0.0.0.0" 33 | * You could always set loc's ip to null or an empty string to use system default ip address, which is best for most applications 34 | */ 35 | private Loc loc; 36 | 37 | /** 38 | * Default socket options for server-side socket 39 | */ 40 | private SocketConfig socketConfig = new SocketConfig(); 41 | 42 | public Supplier getEncoderSupplier() { 43 | return encoderSupplier; 44 | } 45 | 46 | public void setEncoderSupplier(Supplier encoderSupplier) { 47 | this.encoderSupplier = encoderSupplier; 48 | } 49 | 50 | public Supplier getDecoderSupplier() { 51 | return decoderSupplier; 52 | } 53 | 54 | public void setDecoderSupplier(Supplier decoderSupplier) { 55 | this.decoderSupplier = decoderSupplier; 56 | } 57 | 58 | public Supplier getHandlerSupplier() { 59 | return handlerSupplier; 60 | } 61 | 62 | public void setHandlerSupplier(Supplier handlerSupplier) { 63 | this.handlerSupplier = handlerSupplier; 64 | } 65 | 66 | public Provider getProvider() { 67 | return provider; 68 | } 69 | 70 | public void setProvider(Provider provider) { 71 | this.provider = provider; 72 | } 73 | 74 | public Loc getLoc() { 75 | return loc; 76 | } 77 | 78 | public void setLoc(Loc loc) { 79 | this.loc = loc; 80 | } 81 | 82 | public SocketConfig getSocketConfig() { 83 | return socketConfig; 84 | } 85 | 86 | public void setSocketConfig(SocketConfig socketConfig) { 87 | this.socketConfig = socketConfig; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/jmh/CompressionTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.jmh; 2 | 3 | import cn.zorcc.common.ExceptionType; 4 | import cn.zorcc.common.exception.FrameworkException; 5 | import cn.zorcc.common.structure.MemApi; 6 | import cn.zorcc.common.util.CompressUtil; 7 | import cn.zorcc.common.util.NativeUtil; 8 | import org.openjdk.jmh.annotations.Benchmark; 9 | import org.openjdk.jmh.annotations.Param; 10 | import org.openjdk.jmh.annotations.Setup; 11 | import org.openjdk.jmh.infra.Blackhole; 12 | import org.openjdk.jmh.runner.RunnerException; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.lang.foreign.MemorySegment; 17 | import java.lang.foreign.ValueLayout; 18 | 19 | 20 | public class CompressionTest extends JmhTest { 21 | @Param({"/small.json", "medium.json", "/large.json"}) 22 | private String jsonFile; 23 | @Param({"1", "5", "9"}) 24 | private int level; 25 | private byte[] original; 26 | private MemorySegment originalSegment; 27 | 28 | @Setup 29 | public void setup() { 30 | try(InputStream stream = CompressionTest.class.getResourceAsStream(jsonFile)) { 31 | assert stream != null; 32 | this.original = stream.readAllBytes(); 33 | this.originalSegment = NativeUtil.globalArena.allocate(ValueLayout.JAVA_BYTE, original.length); 34 | for(int i = 0; i < original.length; i++) { 35 | originalSegment.set(ValueLayout.JAVA_BYTE, i, original[i]); 36 | } 37 | } catch (IOException e) { 38 | throw new FrameworkException(ExceptionType.JSON, "Json file not found", e); 39 | } 40 | } 41 | 42 | @Benchmark 43 | public void jdkDeflateTest(Blackhole bh) { 44 | byte[] bytes = CompressUtil.compressUsingJdkDeflate(original, level); 45 | bh.consume(CompressUtil.decompressUsingJdkDeflate(bytes)); 46 | } 47 | 48 | @Benchmark 49 | public void libDeflateTest(Blackhole bh) { 50 | CompressUtil.compressUsingDeflate(originalSegment, level, MemApi.DEFAULT, compressed -> { 51 | CompressUtil.decompressUsingDeflate(compressed, MemApi.DEFAULT, bh::consume); 52 | }); 53 | } 54 | 55 | @Benchmark 56 | public void jdkGzipTest(Blackhole bh) { 57 | byte[] bytes = CompressUtil.compressUsingJdkGzip(original, level); 58 | bh.consume(CompressUtil.decompressUsingJdkGzip(bytes)); 59 | } 60 | 61 | @Benchmark 62 | public void libGzipTest(Blackhole bh) { 63 | CompressUtil.compressUsingGzip(originalSegment, level, MemApi.DEFAULT, compressed -> { 64 | CompressUtil.decompressUsingGzip(compressed, MemApi.DEFAULT, bh::consume); 65 | }); 66 | } 67 | 68 | public static void main(String[] args) throws RunnerException { 69 | runTest(CompressionTest.class); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/structure/IntMapTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import org.junit.jupiter.api.Assertions; 4 | import org.junit.jupiter.api.Test; 5 | 6 | import java.util.ArrayList; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | import java.util.Set; 10 | import java.util.concurrent.ThreadLocalRandom; 11 | 12 | public class IntMapTest { 13 | 14 | private static final int COUNT = 100000; 15 | private static final int ROUNDS = 100; 16 | 17 | private static void testMap(IntMap map) { 18 | Set filter = new HashSet<>(COUNT); 19 | List keys = new ArrayList<>(COUNT); 20 | List values = new ArrayList<>(COUNT); 21 | ThreadLocalRandom random = ThreadLocalRandom.current(); 22 | // test put 23 | for(int i = 0; i < COUNT; i++) { 24 | int k; 25 | do { 26 | k = random.nextInt(); 27 | } while (!filter.add(k)); 28 | int v = random.nextInt(); 29 | keys.add(k); 30 | values.add(v); 31 | map.put(k, v); 32 | } 33 | Assertions.assertEquals(map.count(), COUNT); 34 | 35 | // test asList 36 | List original = map.asList(); 37 | Assertions.assertEquals(original.size(), COUNT); 38 | 39 | // test get and replace 40 | for(int i = 0; i < COUNT; i++) { 41 | Integer k = keys.get(i); 42 | Integer v = values.get(i); 43 | Integer current = map.get(k); 44 | Assertions.assertEquals(current, v); 45 | Integer newValue = current + 1; 46 | map.replace(k, current, newValue); 47 | Integer next = map.get(k); 48 | Assertions.assertEquals(next, newValue); 49 | } 50 | Assertions.assertEquals(map.count(), COUNT); 51 | 52 | // test asList 53 | List l1 = map.asList(); 54 | Assertions.assertEquals(l1.size(), COUNT); 55 | // test remove 56 | for(int i = 0; i < COUNT; i++) { 57 | Integer k = keys.get(i); 58 | Integer v = map.get(k); 59 | Assertions.assertTrue(map.remove(k, v)); 60 | } 61 | Assertions.assertEquals(map.count(), 0); 62 | 63 | // test asList empty 64 | List l2 = map.asList(); 65 | Assertions.assertEquals(l2.size(), 0); 66 | } 67 | 68 | @Test 69 | public void testLinkedMap() { 70 | for(int i = 0; i < ROUNDS; i++) { 71 | IntMap map = IntMap.newLinkedMap(16); 72 | testMap(map); 73 | } 74 | } 75 | 76 | @Test 77 | public void testTreeMap() { 78 | for(int i = 0; i < ROUNDS; i++) { 79 | IntMap map = IntMap.newTreeMap(16); 80 | testMap(map); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/bindings/SystemBinding.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.bindings; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.exception.FrameworkException; 6 | import cn.zorcc.common.util.NativeUtil; 7 | 8 | import java.lang.foreign.FunctionDescriptor; 9 | import java.lang.foreign.Linker; 10 | import java.lang.foreign.MemorySegment; 11 | import java.lang.foreign.ValueLayout; 12 | import java.lang.invoke.MethodHandle; 13 | 14 | /** 15 | * System API which JVM could already provide us 16 | */ 17 | public final class SystemBinding { 18 | private static final MethodHandle mallocHandle; 19 | private static final MethodHandle reallocHandle; 20 | private static final MethodHandle freeHandle; 21 | private static final MethodHandle strlenHandle; 22 | 23 | 24 | static { 25 | mallocHandle = NativeUtil.nativeMethodHandle("malloc", FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.JAVA_LONG), Linker.Option.critical(false)); 26 | reallocHandle = NativeUtil.nativeMethodHandle("realloc", FunctionDescriptor.of(ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_LONG), Linker.Option.critical(false)); 27 | freeHandle = NativeUtil.nativeMethodHandle("free", FunctionDescriptor.ofVoid(ValueLayout.ADDRESS), Linker.Option.critical(false)); 28 | strlenHandle = NativeUtil.nativeMethodHandle("strnlen", FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS, ValueLayout.JAVA_LONG), Linker.Option.critical(true)); 29 | } 30 | 31 | private SystemBinding() { 32 | throw new UnsupportedOperationException(); 33 | } 34 | 35 | public static MemorySegment malloc(long byteSize) { 36 | try { 37 | return (MemorySegment) mallocHandle.invokeExact(byteSize); 38 | } catch (Throwable e) { 39 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 40 | } 41 | } 42 | 43 | public static MemorySegment realloc(MemorySegment ptr, long newSize) { 44 | try{ 45 | return (MemorySegment) reallocHandle.invokeExact(ptr, newSize); 46 | } catch (Throwable e) { 47 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 48 | } 49 | } 50 | 51 | public static void free(MemorySegment ptr) { 52 | try{ 53 | freeHandle.invokeExact(ptr); 54 | } catch (Throwable e) { 55 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 56 | } 57 | } 58 | 59 | public static long strlen(MemorySegment ptr, long available) { 60 | try{ 61 | return (long) strlenHandle.invokeExact(ptr, available); 62 | }catch (Throwable throwable) { 63 | throw new FrameworkException(ExceptionType.NATIVE, Constants.UNREACHED); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/log/ConsoleLogConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.log; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | public final class ConsoleLogConfig { 6 | /** 7 | * Flush threshold for console output 8 | */ 9 | private int flushThreshold = 5; 10 | /** 11 | * Reserved length for log level output 12 | */ 13 | private int levelLen = 5; 14 | /** 15 | * Reserved length for log thread-name output 16 | */ 17 | private int threadNameLen = 10; 18 | /** 19 | * Reserved length for log class-name output 20 | */ 21 | private int classNameLen = 40; 22 | /** 23 | * Console color for log time output 24 | */ 25 | private String timeColor = Constants.BLUE; 26 | /** 27 | * Console color for log time output 28 | */ 29 | private String threadNameColor = Constants.MAGENTA; 30 | /** 31 | * Console color for log time output 32 | */ 33 | private String classNameColor = Constants.CYAN; 34 | /** 35 | * Console color for log time output 36 | */ 37 | private String msgColor = Constants.DEFAULT; 38 | 39 | public int getFlushThreshold() { 40 | return flushThreshold; 41 | } 42 | 43 | public void setFlushThreshold(int flushThreshold) { 44 | this.flushThreshold = flushThreshold; 45 | } 46 | 47 | public int getLevelLen() { 48 | return levelLen; 49 | } 50 | 51 | public void setLevelLen(int levelLen) { 52 | this.levelLen = levelLen; 53 | } 54 | 55 | public int getThreadNameLen() { 56 | return threadNameLen; 57 | } 58 | 59 | public void setThreadNameLen(int threadNameLen) { 60 | this.threadNameLen = threadNameLen; 61 | } 62 | 63 | public int getClassNameLen() { 64 | return classNameLen; 65 | } 66 | 67 | public void setClassNameLen(int classNameLen) { 68 | this.classNameLen = classNameLen; 69 | } 70 | 71 | public String getTimeColor() { 72 | return timeColor; 73 | } 74 | 75 | public void setTimeColor(String timeColor) { 76 | this.timeColor = timeColor; 77 | } 78 | 79 | public String getThreadNameColor() { 80 | return threadNameColor; 81 | } 82 | 83 | public void setThreadNameColor(String threadNameColor) { 84 | this.threadNameColor = threadNameColor; 85 | } 86 | 87 | public String getClassNameColor() { 88 | return classNameColor; 89 | } 90 | 91 | public void setClassNameColor(String classNameColor) { 92 | this.classNameColor = classNameColor; 93 | } 94 | 95 | public String getMsgColor() { 96 | return msgColor; 97 | } 98 | 99 | public void setMsgColor(String msgColor) { 100 | this.msgColor = msgColor; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/network/RefMapTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.network; 2 | 3 | import cn.zorcc.common.Ref; 4 | import cn.zorcc.common.structure.Allocator; 5 | import cn.zorcc.common.util.NativeUtil; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | 9 | import java.lang.foreign.MemorySegment; 10 | import java.lang.foreign.ValueLayout; 11 | import java.util.ArrayList; 12 | import java.util.HashSet; 13 | import java.util.List; 14 | import java.util.Set; 15 | import java.util.concurrent.ThreadLocalRandom; 16 | 17 | public class RefMapTest { 18 | private static final int BATCH = 100000; 19 | private static final int ROUND = 100; 20 | 21 | private static MemorySegment generateData(int first, int second) { 22 | MemorySegment m = Allocator.HEAP.allocate(ValueLayout.JAVA_INT, 2); 23 | NativeUtil.setInt(m, 0, first); 24 | NativeUtil.setInt(m, 4, second); 25 | return m; 26 | } 27 | 28 | @Test 29 | public void test() throws InterruptedException { 30 | List threads = new ArrayList<>(); 31 | for(int cpu = 0; cpu < Runtime.getRuntime().availableProcessors(); cpu++) { 32 | Thread thread = Thread.ofPlatform().start(() -> { 33 | for (int t = 0; t < ROUND; t++) { 34 | PollerNode.RefMap refMap = PollerNode.RefMap.newInstance(16); 35 | List segments = new ArrayList<>(BATCH); 36 | List refs = new ArrayList<>(BATCH); 37 | ThreadLocalRandom random = ThreadLocalRandom.current(); 38 | Set set = new HashSet<>(BATCH); 39 | for (int i = 0; i < BATCH; i++) { 40 | int first = random.nextInt(Byte.MIN_VALUE, Byte.MAX_VALUE); // same prefix could provide more collision 41 | int second; 42 | do { 43 | second = random.nextInt(); 44 | } while (!set.add(second)); // ensure each seg is unique 45 | MemorySegment seg = generateData(first, second); 46 | Ref ref = new Ref(); 47 | refMap.put(seg, ref); 48 | segments.add(seg); 49 | refs.add(ref); 50 | } 51 | for (int i = 0; i < BATCH; i++) { 52 | MemorySegment seg = segments.get(i); 53 | Ref ref = refs.get(i); 54 | Ref r = refMap.get(seg); 55 | Assertions.assertSame(r, ref); 56 | Assertions.assertTrue(refMap.remove(seg, ref)); 57 | Assertions.assertEquals(refMap.count(), BATCH - i - 1); 58 | } 59 | } 60 | }); 61 | threads.add(thread); 62 | } 63 | for (Thread t : threads) { 64 | t.join(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/postgre/PgProvider.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.postgre; 2 | 3 | import cn.zorcc.common.Constants; 4 | import cn.zorcc.common.ExceptionType; 5 | import cn.zorcc.common.bindings.SslBinding; 6 | import cn.zorcc.common.exception.FrameworkException; 7 | import cn.zorcc.common.network.Channel; 8 | import cn.zorcc.common.network.Provider; 9 | import cn.zorcc.common.network.Sentry; 10 | import cn.zorcc.common.util.NativeUtil; 11 | import cn.zorcc.common.util.SslUtil; 12 | 13 | import java.lang.foreign.MemorySegment; 14 | 15 | /** 16 | * PgProvider is just like SslProvider, using a separate ctx 17 | */ 18 | public final class PgProvider implements Provider { 19 | private final MemorySegment ctx; 20 | private final PgConfig pgConfig; 21 | public PgProvider(PgConfig pgConfig) { 22 | verifyPgConfig(pgConfig); 23 | this.pgConfig = pgConfig; 24 | this.ctx = SslBinding.sslCtxNew(SslBinding.tlsMethod()); 25 | if(NativeUtil.checkNullPointer(ctx)) { 26 | throw new FrameworkException(ExceptionType.NETWORK, "SSL ctx initialization failed"); 27 | } 28 | SslUtil.configureCtx(ctx); 29 | switch (pgConfig.getSslMode()) { 30 | case Constants.PG_SSL_PREFER -> SslBinding.setVerify(ctx, Constants.SSL_VERIFY_NONE, MemorySegment.NULL); 31 | case Constants.PG_SSL_VERIFY_CA -> SslBinding.setVerify(ctx, Constants.SSL_VERIFY_PEER, MemorySegment.NULL); 32 | case Constants.PG_SSL_VERIFY_FULL -> SslBinding.setVerify(ctx, Constants.SSL_VERIFY_PEER | Constants.SSL_VERIFY_FAIL_IF_NO_PEER_CERT, MemorySegment.NULL); 33 | default -> throw new FrameworkException(ExceptionType.POSTGRESQL, Constants.UNREACHED); 34 | } 35 | } 36 | 37 | private void verifyPgConfig(PgConfig pgConfig) { 38 | if(pgConfig.getLoc() == null) { 39 | throw new FrameworkException(ExceptionType.POSTGRESQL, "Empty postgresql server location spotted"); 40 | } 41 | String userName = pgConfig.getUserName(); 42 | if(userName == null || userName.isBlank()) { 43 | throw new FrameworkException(ExceptionType.POSTGRESQL, "Empty postgresql server username spotted"); 44 | } 45 | String password = pgConfig.getPassword(); 46 | if(password == null || password.isBlank()) { 47 | throw new FrameworkException(ExceptionType.POSTGRESQL, "Empty postgresql server password spotted"); 48 | } 49 | String sslMode = pgConfig.getSslMode(); 50 | if(!sslMode.equals(Constants.PG_SSL_PREFER) && !sslMode.equals(Constants.PG_SSL_VERIFY_CA) && !sslMode.equals(Constants.PG_SSL_VERIFY_FULL)) { 51 | throw new FrameworkException(ExceptionType.POSTGRESQL, "Unsupported postgresql ssl mode"); 52 | } 53 | } 54 | 55 | @Override 56 | public Sentry create(Channel channel) { 57 | return new PgSentry(channel, ctx, pgConfig); 58 | } 59 | 60 | @Override 61 | public void close() { 62 | SslBinding.sslCtxFree(ctx); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /common/src/main/java/cn/zorcc/common/structure/TaskQueue.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.structure; 2 | 3 | import cn.zorcc.common.ExceptionType; 4 | import cn.zorcc.common.exception.FrameworkException; 5 | 6 | import java.util.Arrays; 7 | import java.util.Iterator; 8 | import java.util.Objects; 9 | import java.util.concurrent.locks.Lock; 10 | import java.util.concurrent.locks.ReentrantLock; 11 | 12 | /** 13 | * Task queue is a queue for multiple producer and single consumer pattern, normal MPSCQueue would heavily use spinWait() and linked list for performance boost 14 | * However, it's hard to design a structure which works well for both platform thread and virtual thread, ReentrantLock might be the best we could do at present time. 15 | */ 16 | public final class TaskQueue { 17 | private static final Object[] EMPTY_ARRAY = {}; 18 | private final Itr EMPTY_ITR = new Itr<>(EMPTY_ARRAY); 19 | private final Lock lock = new ReentrantLock(); 20 | private final Object[] initialElements; 21 | private Object[] elements; 22 | private int index; 23 | 24 | public TaskQueue(int initialSize) { 25 | this.initialElements = this.elements = new Object[initialSize]; 26 | this.index = 0; 27 | } 28 | 29 | /** 30 | * Submit a task to current task queue 31 | */ 32 | public void offer(T element) { 33 | Objects.requireNonNull(element); 34 | lock.lock(); 35 | try{ 36 | if(index == elements.length) { 37 | int newCapacity = elements.length + (elements.length >> 1); 38 | if(newCapacity < 0) { 39 | throw new FrameworkException(ExceptionType.CONTEXT, "Size overflow"); 40 | } 41 | elements = Arrays.copyOf(elements, newCapacity); 42 | } 43 | elements[index++] = element; 44 | }finally { 45 | lock.unlock(); 46 | } 47 | } 48 | 49 | private static class Itr implements Iterator { 50 | private final Object[] array; 51 | private int currentIndex = 0; 52 | 53 | Itr(Object[] array) { 54 | this.array = array; 55 | } 56 | @Override 57 | public boolean hasNext() { 58 | return currentIndex < array.length; 59 | } 60 | @SuppressWarnings("unchecked") 61 | @Override 62 | public E next() { 63 | return (E) array[currentIndex++]; 64 | } 65 | } 66 | 67 | /** 68 | * Poll all the tasks from current task queue, the result are guaranteed to contain non-null elements 69 | */ 70 | public Iterable elements() { 71 | lock.lock(); 72 | try{ 73 | if(index > 0) { 74 | Itr itr = new Itr<>(Arrays.copyOfRange(elements, 0, index)); 75 | elements = initialElements; 76 | index = 0; 77 | return () -> itr; 78 | }else { 79 | return () -> EMPTY_ITR; 80 | } 81 | }finally { 82 | lock.unlock(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/util/VectorTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.util; 2 | 3 | import jdk.incubator.vector.ByteVector; 4 | import jdk.incubator.vector.VectorMask; 5 | import jdk.incubator.vector.VectorOperators; 6 | import jdk.incubator.vector.VectorSpecies; 7 | import org.junit.jupiter.api.Assertions; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import java.util.Arrays; 11 | 12 | public class VectorTest { 13 | private static final VectorSpecies species = ByteVector.SPECIES_PREFERRED; 14 | private static final byte PADDING = (byte) '0'; 15 | private static final byte TARGET = (byte) '1'; 16 | 17 | public static byte[] createArray(int len) { 18 | byte[] bytes = new byte[len]; 19 | Arrays.fill(bytes, PADDING); 20 | bytes[len - 1] = TARGET; 21 | return bytes; 22 | } 23 | 24 | public static int normalSearch(byte[] bytes, int offset) { 25 | for(int i = offset; i < bytes.length; i++) { 26 | if(bytes[i] == TARGET) { 27 | return i; 28 | } 29 | } 30 | return -1; 31 | } 32 | 33 | public static int vectorSearch(byte[] bytes, int offset) { 34 | for(int start = offset; start < bytes.length; start += species.length()) { 35 | VectorMask mask = species.indexInRange(start, bytes.length); 36 | ByteVector vector = ByteVector.fromArray(species, bytes, start, mask); 37 | VectorMask eq = vector.compare(VectorOperators.EQ, TARGET); 38 | int searchIndex = eq.firstTrue(); 39 | if(searchIndex < species.length()) { 40 | return start + searchIndex; 41 | } 42 | } 43 | return -1; 44 | } 45 | 46 | @Test 47 | public void testVectorSearchNonFind() { 48 | for(int i = 1; i < 4 * species.length(); i++) { 49 | byte[] arr = new byte[i]; 50 | Arrays.fill(arr, PADDING); 51 | for(int j = 0; j < i; j++) { 52 | Assertions.assertEquals(vectorSearch(arr, j), -1); 53 | } 54 | } 55 | } 56 | 57 | @Test 58 | public void testVectorSearchFind() { 59 | for(int i = 1; i < 4 * species.length(); i++) { 60 | byte[] arr = createArray(i); 61 | for(int j = 0; j < i; j++) { 62 | Assertions.assertEquals(vectorSearch(arr, j), i - 1); 63 | } 64 | } 65 | } 66 | 67 | @Test 68 | public void testNormalNonFind() { 69 | for(int i = 1; i < 4 * species.length(); i++) { 70 | byte[] arr = new byte[i]; 71 | Arrays.fill(arr, PADDING); 72 | for(int j = 0; j < i; j++) { 73 | Assertions.assertEquals(normalSearch(arr, j), -1); 74 | } 75 | } 76 | } 77 | 78 | @Test 79 | public void testNormalSearch() { 80 | for(int i = 1; i < 4 * species.length(); i++) { 81 | byte[] arr = createArray(i); 82 | for(int j = 0; j < i; j++) { 83 | Assertions.assertEquals(normalSearch(arr, j), i - 1); 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /orm/src/main/java/cn/zorcc/orm/core/PgDataType.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.orm.core; 2 | 3 | import java.math.BigDecimal; 4 | import java.time.*; 5 | import java.util.UUID; 6 | 7 | /** 8 | * pg数据类型对应java中具体类实现 9 | * 驱动默认支持部分常用数据类型,如果需要使用特殊数据类型则请自行添加处理类 10 | * 如果数据类型支持binary且binary形式更高效,驱动将会尽可能使用binary模式传输数据,pg在执行SimpleQuery时返回时会默认选择文本类型 11 | * pg默认对数组的支持是不区分一维数组和多维数组的,在实际使用的情形下很少会使用到数组类型,所以没有实现数组相关的类型匹配 12 | */ 13 | public enum PgDataType { 14 | BOOL(16, true, Boolean.class), 15 | 16 | 17 | INT2(21, true, Short.class), 18 | 19 | 20 | INT4(23, true, Integer.class), 21 | 22 | 23 | INT8(20, true, Long.class), 24 | 25 | 26 | FLOAT4(700, true, Float.class), 27 | 28 | 29 | FLOAT8(701, true, Boolean.class), 30 | 31 | /** 32 | * NUMERIC类型并不是不能使用二进制进行传输,只是二进制传输的方式转化复杂且数据长度显著高于文本形式,故使用Text方式更为高效 33 | * NUMERIC在pg中与DECIMAL等同 34 | */ 35 | NUMERIC(1700, false, BigDecimal.class), 36 | 37 | /** 38 | * 货币类型,默认会保留两位小数 39 | */ 40 | MONEY(790, true, BigDecimal.class), 41 | 42 | /** 43 | * 固定长度字符串,填充空格 44 | */ 45 | CHAR(18, true, String.class), 46 | 47 | /** 48 | * 变长字符串 49 | */ 50 | VARCHAR(1043, true, String.class), 51 | 52 | /** 53 | * 不限制长度字符串,等同于未指定长度的VARCHAR 54 | * NOTE:三种字符串在pg的实现中并没有明显的差距,尽可能使用text类型,除非需要显式限制字符串长度 55 | */ 56 | TEXT(25, true, String.class), 57 | 58 | /** 59 | * 日期,精确至天,占用4字节 60 | */ 61 | DATE(1082, true, LocalDate.class), 62 | 63 | /** 64 | * 不带有时区的当日内时间,占用8字节 65 | */ 66 | TIME(1083, true, LocalTime.class), 67 | 68 | /** 69 | * 带有时区的当日内时间,占用12字节 70 | */ 71 | TIMETZ(1266, true, OffsetTime.class), 72 | 73 | /** 74 | * 不带有时区的时间戳,占用8字节 75 | */ 76 | TIMESTAMP(1114, true, LocalDateTime.class), 77 | 78 | /** 79 | * 带有时区的时间戳,占用8字节 NOTE:尽量使用timestamp with out timezone来完成任务 80 | */ 81 | TIMESTAMPTZ(1184, true, OffsetDateTime.class), 82 | 83 | /** 84 | * UUID类型 85 | */ 86 | UUID(2950, true, UUID.class), 87 | 88 | /** 89 | * json类型 90 | */ 91 | JSON(114, true, String.class), 92 | 93 | /** 94 | * 以二进制形式存储的json类型,处理时不需要解析,同时支持索引,写入稍慢但检索更快 95 | */ 96 | JSONB(3802, true, String.class), 97 | 98 | ; 99 | /** 100 | * pg数据类型id 101 | */ 102 | final int oid; 103 | /** 104 | * 是否使用二进制传输(所有数据类型均可使用二进制传输,但考虑到解析的复杂度NUMERIC仍使用文本形式传输) 105 | */ 106 | final boolean usingBinary; 107 | /** 108 | * 数据库类型对应Java类型 109 | */ 110 | final Class javaType; 111 | 112 | 113 | PgDataType(int oid, boolean usingBinary, Class javaType) { 114 | this.oid = oid; 115 | this.usingBinary = usingBinary; 116 | this.javaType = javaType; 117 | } 118 | 119 | public int getOid() { 120 | return oid; 121 | } 122 | 123 | public boolean isUsingBinary() { 124 | return usingBinary; 125 | } 126 | 127 | public Class getJavaType() { 128 | return javaType; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /common/src/test/java/cn/zorcc/common/context/MetaTest.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.common.context; 2 | 3 | import cn.zorcc.common.Meta; 4 | import cn.zorcc.common.beans.Beta; 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.List; 9 | 10 | public class MetaTest { 11 | private static final int a1 = Integer.MAX_VALUE; 12 | private static final Integer a2 = Integer.MIN_VALUE; 13 | private static final int[] a3 = new int[]{1,2,3}; 14 | private static final Integer[] a4 = new Integer[]{2,3,4}; 15 | private static final String a5 = "hello world"; 16 | private static final List a6 = List.of("abc", "lxc"); 17 | private static final List a7 = List.of(new int[]{1,2,3}, new int[]{3,4,5}); 18 | private static final List a8 = List.of(new Integer[]{1,2,3}, new Integer[]{3,4,5}); 19 | private static final Beta beta = new Beta(); 20 | 21 | static { 22 | beta.setA1(a1); 23 | beta.setA2(a2); 24 | beta.setA3(a3); 25 | beta.setA4(a4); 26 | beta.setA5(a5); 27 | beta.setA6(a6); 28 | beta.setA7(a7); 29 | beta.setA8(a8); 30 | } 31 | @Test 32 | public void testMetaGetter() { 33 | Meta betaMeta = Meta.of(Beta.class); 34 | Assertions.assertEquals(betaMeta.metaInfo("a1").invokeGetter(beta), a1); 35 | Assertions.assertEquals(betaMeta.metaInfo("a2").invokeGetter(beta), a2); 36 | Assertions.assertEquals(betaMeta.metaInfo("a3").invokeGetter(beta), a3); 37 | Assertions.assertEquals(betaMeta.metaInfo("a4").invokeGetter(beta), a4); 38 | Assertions.assertEquals(betaMeta.metaInfo("a5").invokeGetter(beta), a5); 39 | Assertions.assertEquals(betaMeta.metaInfo("a6").invokeGetter(beta), a6); 40 | Assertions.assertEquals(betaMeta.metaInfo("a7").invokeGetter(beta), a7); 41 | Assertions.assertEquals(betaMeta.metaInfo("a8").invokeGetter(beta), a8); 42 | } 43 | 44 | @Test 45 | public void testMetaSetter() { 46 | Meta betaMeta = Meta.of(Beta.class); 47 | Beta b = new Beta(); 48 | betaMeta.metaInfo("a1").setter().accept(b, a1); 49 | Assertions.assertEquals(b.getA1(), a1); 50 | betaMeta.metaInfo("a2").setter().accept(b, a2); 51 | Assertions.assertEquals(b.getA2(), a2); 52 | betaMeta.metaInfo("a3").setter().accept(b, a3); 53 | Assertions.assertEquals(b.getA3(), a3); 54 | betaMeta.metaInfo("a4").setter().accept(b, a4); 55 | Assertions.assertEquals(b.getA4(), a4); 56 | betaMeta.metaInfo("a5").setter().accept(b, a5); 57 | Assertions.assertEquals(b.getA5(), a5); 58 | betaMeta.metaInfo("a6").setter().accept(b, a6); 59 | Assertions.assertEquals(b.getA6(), a6); 60 | betaMeta.metaInfo("a7").setter().accept(b, a7); 61 | Assertions.assertEquals(b.getA7(), a7); 62 | betaMeta.metaInfo("a8").setter().accept(b, a8); 63 | Assertions.assertEquals(b.getA8(), a8); 64 | } 65 | 66 | @Test 67 | public void testMetaConstructor() { 68 | Meta betaMeta = Meta.of(Beta.class); 69 | Beta beta = betaMeta.constructor().get(); 70 | Assertions.assertNotNull(beta); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /http/src/main/java/cn/zorcc/http/HttpConfig.java: -------------------------------------------------------------------------------- 1 | package cn.zorcc.http; 2 | 3 | import cn.zorcc.common.Constants; 4 | 5 | /** 6 | * 网关http配置文件 7 | */ 8 | public class HttpConfig { 9 | /** 10 | * Http端口号 11 | */ 12 | private int port = 8000; 13 | /** 14 | * Http client worker线程数,最低为1 15 | */ 16 | private int httpClientThreads = 1; 17 | /** 18 | * Http client 连接超时时间,单位毫秒 19 | */ 20 | private int httpClientTimeout = 3000; 21 | /** 22 | * Http server worker线程数,如果小于等于0则会使用boss线程 23 | */ 24 | private int httpServerThreads = 4; 25 | /** 26 | * 是否启用WebSocket 27 | */ 28 | private boolean enableWebSocket = false; 29 | /** 30 | * 是否开启https 31 | */ 32 | private boolean usingHttps = false; 33 | /** 34 | * ssl证书文件地址, .crt或.pem格式 35 | */ 36 | private String httpSslCertFile = Constants.EMPTY_STRING; 37 | /** 38 | * ssl证书key文件地址, .key格式 39 | */ 40 | private String httpSslKeyFile = Constants.EMPTY_STRING; 41 | /** 42 | * ssl ca证书文件地址, .crt或.pem格式 43 | */ 44 | private String httpCaCertFile = Constants.EMPTY_STRING; 45 | 46 | public int getPort() { 47 | return port; 48 | } 49 | 50 | public void setPort(int port) { 51 | this.port = port; 52 | } 53 | 54 | public int getHttpClientThreads() { 55 | return httpClientThreads; 56 | } 57 | 58 | public void setHttpClientThreads(int httpClientThreads) { 59 | this.httpClientThreads = httpClientThreads; 60 | } 61 | 62 | public int getHttpClientTimeout() { 63 | return httpClientTimeout; 64 | } 65 | 66 | public void setHttpClientTimeout(int httpClientTimeout) { 67 | this.httpClientTimeout = httpClientTimeout; 68 | } 69 | 70 | public int getHttpServerThreads() { 71 | return httpServerThreads; 72 | } 73 | 74 | public void setHttpServerThreads(int httpServerThreads) { 75 | this.httpServerThreads = httpServerThreads; 76 | } 77 | 78 | public boolean isEnableWebSocket() { 79 | return enableWebSocket; 80 | } 81 | 82 | public void setEnableWebSocket(boolean enableWebSocket) { 83 | this.enableWebSocket = enableWebSocket; 84 | } 85 | 86 | public boolean isUsingHttps() { 87 | return usingHttps; 88 | } 89 | 90 | public void setUsingHttps(boolean usingHttps) { 91 | this.usingHttps = usingHttps; 92 | } 93 | 94 | public String getHttpSslCertFile() { 95 | return httpSslCertFile; 96 | } 97 | 98 | public void setHttpSslCertFile(String httpSslCertFile) { 99 | this.httpSslCertFile = httpSslCertFile; 100 | } 101 | 102 | public String getHttpSslKeyFile() { 103 | return httpSslKeyFile; 104 | } 105 | 106 | public void setHttpSslKeyFile(String httpSslKeyFile) { 107 | this.httpSslKeyFile = httpSslKeyFile; 108 | } 109 | 110 | public String getHttpCaCertFile() { 111 | return httpCaCertFile; 112 | } 113 | 114 | public void setHttpCaCertFile(String httpCaCertFile) { 115 | this.httpCaCertFile = httpCaCertFile; 116 | } 117 | } 118 | --------------------------------------------------------------------------------