Compare commits
101
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cb46fd8ab | ||
|
|
c098b5e442 | ||
|
|
dc8cd290b6 | ||
|
|
17c77d9b31 | ||
|
|
2cf62d8d9a | ||
|
|
0328356758 | ||
|
|
0e1be3f559 | ||
|
|
f2d1364c4b | ||
|
|
3d2043f926 | ||
|
|
e525e740c1 | ||
|
|
0ef72a45fe | ||
|
|
db5dbd3666 | ||
|
|
ca27dd3329 | ||
|
|
37b34ec6f7 | ||
|
|
f869c97fbe | ||
|
|
a27462b1a3 | ||
|
|
8e9abf8451 | ||
|
|
1b40382d56 | ||
|
|
402d9f5b84 | ||
|
|
20779387eb | ||
|
|
7a6bba0f19 | ||
|
|
83dc93aeb1 | ||
|
|
6107bbdb5d | ||
|
|
71f95f8774 | ||
|
|
4108ee087e | ||
|
|
e30bf5cdea | ||
|
|
dce77049b1 | ||
|
|
72ef4f33b0 | ||
|
|
a7176f7851 | ||
|
|
1a0f3197ce | ||
|
|
e34c2ffec7 | ||
|
|
8a10b591ed | ||
|
|
efc2100177 | ||
|
|
a4d57cc97c | ||
|
|
3426702d8f | ||
|
|
8e7a24c971 | ||
|
|
475dda4e9e | ||
|
|
193f3380cb | ||
|
|
d6ac2c5134 | ||
|
|
076513e79b | ||
|
|
b227fc6254 | ||
|
|
ca82042669 | ||
|
|
ec7c0de946 | ||
|
|
391580b9da | ||
|
|
7e7e185968 | ||
|
|
517e64ceff | ||
|
|
7df9a15d3b | ||
|
|
b01f36d263 | ||
|
|
36e555cd13 | ||
|
|
3d0d1c6dba | ||
|
|
f03a055c34 | ||
|
|
bfeb5e362a | ||
|
|
e48f2ec99d | ||
|
|
cec62215e2 | ||
|
|
e361d405c9 | ||
|
|
020cd44cf3 | ||
|
|
c02f3d152a | ||
|
|
b4b9e00f90 | ||
|
|
8f886008ef | ||
|
|
23e4dbfa07 | ||
|
|
114ac2fdc9 | ||
|
|
3bdde53d15 | ||
|
|
bcc4d5fb3d | ||
|
|
e93b5c901f | ||
|
|
ccf8b671bf | ||
|
|
0462c97b76 | ||
|
|
3e23799772 | ||
|
|
2b4119a023 | ||
|
|
da469270e7 | ||
|
|
c9e9be0772 | ||
|
|
2870fefc15 | ||
|
|
cd1a5946b3 | ||
|
|
2cf60d74cc | ||
|
|
10c018e995 | ||
|
|
25b937c096 | ||
|
|
516b9c0462 | ||
|
|
347ec1a7ea | ||
|
|
80f4b4bc1c | ||
|
|
c470984bd2 | ||
|
|
f560eca4d7 | ||
|
|
f9b28dcb7a | ||
|
|
8275423b89 | ||
|
|
86a725227b | ||
|
|
43ec58dfe3 | ||
|
|
922924c31d | ||
|
|
2b7dbb6ad3 | ||
|
|
1c431f542e | ||
|
|
7fa8e4ca47 | ||
|
|
8579c9fdc5 | ||
|
|
ebcb070310 | ||
|
|
f5171d8636 | ||
|
|
8af399ca0f | ||
|
|
ea48dbabe3 | ||
|
|
9c7f712e11 | ||
|
|
e4df7215b0 | ||
|
|
4f404eec24 | ||
|
|
633aa362ff | ||
|
|
bfd837764a | ||
|
|
99f3a845b8 | ||
|
|
49f9f50fdb | ||
|
|
bb25eab078 |
No files matched your search
@@ -25,12 +25,6 @@
|
||||
"commands": [
|
||||
"fake"
|
||||
]
|
||||
},
|
||||
"dotnet-t4": {
|
||||
"version": "3.0.0",
|
||||
"commands": [
|
||||
"t4"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,6 @@
|
||||
"extensions": [
|
||||
"eamodio.gitlens",
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"ms-python.python",
|
||||
"ms-vscode.cmake-tools",
|
||||
"ms-vscode.cpptools",
|
||||
"xaver.clang-format"
|
||||
|
||||
+16
-30
@@ -207,23 +207,17 @@ dotnet_naming_symbols.parameters.applicable_accessibilities = public,internal,pr
|
||||
dotnet_naming_symbols.private_symbols.applicable_kinds = property,method,field,event,delegate
|
||||
dotnet_naming_symbols.private_symbols.applicable_accessibilities = protected,private
|
||||
|
||||
# local symbols
|
||||
dotnet_naming_symbols.local_symbols.applicable_kinds = local
|
||||
|
||||
# parameter symbols
|
||||
dotnet_naming_symbols.parameter_symbols.applicable_kinds = parameter
|
||||
|
||||
# Naming styles
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
dotnet_naming_style.snake_case.required_prefix =
|
||||
dotnet_naming_style.snake_case.required_suffix =
|
||||
dotnet_naming_style.snake_case.word_separator = _
|
||||
dotnet_naming_style.snake_case.capitalization = all_lower
|
||||
|
||||
dotnet_naming_style.camel_case.required_prefix =
|
||||
dotnet_naming_style.camel_case.required_suffix =
|
||||
dotnet_naming_style.camel_case.word_separator =
|
||||
dotnet_naming_style.camel_case.capitalization = camel_case
|
||||
dotnet_naming_style.private_snake_case.required_prefix = _
|
||||
dotnet_naming_style.private_snake_case.required_suffix =
|
||||
dotnet_naming_style.private_snake_case.word_separator = _
|
||||
dotnet_naming_style.private_snake_case.capitalization = all_lower
|
||||
|
||||
dotnet_naming_style.user_types.required_prefix =
|
||||
dotnet_naming_style.user_types.required_suffix =
|
||||
@@ -235,10 +229,6 @@ dotnet_naming_style.interface.required_suffix =
|
||||
dotnet_naming_style.interface.word_separator =
|
||||
dotnet_naming_style.interface.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.local.capitalization = camel_case
|
||||
|
||||
dotnet_naming_style.parameter.capitalization = camel_case
|
||||
|
||||
# rules
|
||||
dotnet_naming_rule.user_types.symbols = user_types
|
||||
dotnet_naming_rule.user_types.style = user_types
|
||||
@@ -248,18 +238,14 @@ dotnet_naming_rule.interfaces.symbols = interface
|
||||
dotnet_naming_rule.interfaces.style = interface_style
|
||||
dotnet_naming_rule.interfaces.severity = suggestion
|
||||
|
||||
dotnet_naming_rule.public_members.symbols = public_symbols
|
||||
dotnet_naming_rule.public_members.style = pascal_case
|
||||
dotnet_naming_rule.public_members.severity = suggestion
|
||||
dotnet_naming_rule.public_members_snake_case.symbols = public_symbols
|
||||
dotnet_naming_rule.public_members_snake_case.style = snake_case
|
||||
dotnet_naming_rule.public_members_snake_case.severity = suggestion
|
||||
|
||||
dotnet_naming_rule.private_members.symbols = private_symbols
|
||||
dotnet_naming_rule.private_members.style = camel_case
|
||||
dotnet_naming_rule.private_members.severity = suggestion
|
||||
dotnet_naming_rule.private_members_snake_case.symbols = private_symbols
|
||||
dotnet_naming_rule.private_members_snake_case.style = private_snake_case
|
||||
dotnet_naming_rule.private_members_snake_case.severity = suggestion
|
||||
|
||||
dotnet_naming_rule.variables_are_camel_case.severity = suggestion
|
||||
dotnet_naming_rule.variables_are_camel_case.symbols = local_symbols
|
||||
dotnet_naming_rule.variables_are_camel_case.style = local
|
||||
|
||||
dotnet_naming_rule.parameters.symbols = parameter_symbols
|
||||
dotnet_naming_rule.parameters.style = parameter
|
||||
dotnet_naming_rule.parameters.symbols = parameters
|
||||
dotnet_naming_rule.parameters.style = snake_case
|
||||
dotnet_naming_rule.parameters.severity = suggestion
|
||||
@@ -46,11 +46,4 @@ SPARKD__SIM_FIX_PORT=8002
|
||||
SPARKD__SHM_SIZE=4gb
|
||||
SPARKD__PYTHON_REQUIREMENTS=requirements.txt
|
||||
|
||||
### PubSubServer ###
|
||||
PUBSUB__CONFIG_DIR=src/DataStreamSuite/PubSubServer/Configurations/Development
|
||||
PUBSUB__SOURCE_DIR=build/Release/bin/net8.0/linux-x64/publish
|
||||
|
||||
### MdPublisher ###
|
||||
MD_PUBLISHER__CONFIG_DIR=src/DataStreamSuite/DataStreamPublisher/Configurations/ReplayMarketData
|
||||
MD_PUBLISHER__SOURCE_DIR=build/Release/bin/net8.0/linux-x64/publish
|
||||
# TODO: add config for other services (pubsub, md-publisher, webapp, api-server, etc.)
|
||||
@@ -11,7 +11,6 @@ cmake-build-debug/
|
||||
**.vscode/*
|
||||
!.vscode/launch.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/*.env
|
||||
.vs
|
||||
obj/
|
||||
*.csproj.user
|
||||
@@ -55,8 +54,6 @@ trace_data/
|
||||
.cache/
|
||||
/src/Spark.Admin.WebApp/tsconfig.*.g.json
|
||||
/src/Spark.Admin.WebApp/src/bin/
|
||||
/src/**/*appsettings.Local.json
|
||||
/src/**/*/Configurations/Local/
|
||||
**/CMakeDeps.cmake
|
||||
**/CMakeDeps_win.cmake
|
||||
.devcontainer/
|
||||
|
||||
Vendored
+9
-161
@@ -14,49 +14,6 @@
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
},
|
||||
{
|
||||
"name": "Api Server",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"preLaunchTask": "Build Api Server (Debug)",
|
||||
"windows": {
|
||||
"program": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"program": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Api Server (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"program": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "DataStreamPublisher",
|
||||
"type": "coreclr",
|
||||
@@ -69,28 +26,11 @@
|
||||
"windows": {
|
||||
"program": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "DataStreamPublisher (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"linux": {
|
||||
"program": "DataStreamPublisher",
|
||||
},
|
||||
"windows": {
|
||||
"program": "DataStreamPublisher.exe",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -142,29 +82,16 @@
|
||||
"name": "DataStreamQueryAnalyzer",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
//"preLaunchTask": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "DataStreamQueryAnalyzer.exe",
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamQueryAnalyzerEnvironment}",
|
||||
"PYTHON_EXE": "${workspaceFolder}/.venv/Scripts/python.exe"
|
||||
},
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal",
|
||||
},
|
||||
{
|
||||
"name": "DataStreamQueryAnalyzer (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"windows": {
|
||||
"program": "DataStreamQueryAnalyzer.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamQueryAnalyzerEnvironment}",
|
||||
"PYTHON_EXE": "${workspaceFolder}/.venv/Scripts/python.exe"
|
||||
},
|
||||
},
|
||||
@@ -188,27 +115,6 @@
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "PubSubServer (Skip Build)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"linux": {
|
||||
"program": "PubSubServer",
|
||||
},
|
||||
"windows": {
|
||||
"program": "PubSubServer.exe",
|
||||
},
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -221,9 +127,6 @@
|
||||
"preLaunchTask": "Build Spark (Debug)",
|
||||
"program": "Spark.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:sparkEnvironment}",
|
||||
}
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -236,9 +139,6 @@
|
||||
"windows": {
|
||||
"program": "Spark.exe",
|
||||
"cwd": "build/Debug/bin/net8.0-windows",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:sparkEnvironment}",
|
||||
}
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
@@ -351,17 +251,6 @@
|
||||
},
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "apiServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Api Server Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
"Staging",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamPublisherConfig",
|
||||
"type": "pickString",
|
||||
@@ -374,16 +263,6 @@
|
||||
],
|
||||
"default": "MarketDataPublisher",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamPublisherEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "DataStreamPublisher Configuration",
|
||||
"options": [
|
||||
"Local",
|
||||
"ReplayMarketData",
|
||||
],
|
||||
"default": "Local",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerConfig",
|
||||
"type": "pickString",
|
||||
@@ -394,37 +273,6 @@
|
||||
],
|
||||
"default": "PubSubServer",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Api Server Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
"Staging",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamQueryAnalyzerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "DataStreamQueryAnalyzer Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sparkEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Spark Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sparkConfigServer",
|
||||
"type": "promptString",
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
PYTHONPATH=/workspaces/spark/build/sparkd-debug-clang/src/lib_python_interop;/workspaces/spark/src/lib_python_interop/python_interop_plugins;/workspaces/spark/tools/py
|
||||
Vendored
+61
-243
@@ -121,57 +121,6 @@
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStreamQueryAnalyzer",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_query_analyzer.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"${input:buildConfiguration}",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_query_analyzer.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"Debug",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build DataStreamQueryAnalyzer (Release)",
|
||||
"group": "build",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "tools/build_data_stream_query_analyzer.cmd",
|
||||
},
|
||||
"args": [
|
||||
"--configuration",
|
||||
"Release",
|
||||
],
|
||||
"icon": {
|
||||
"id": "terminal",
|
||||
"color": "terminal.ansiCyan"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Build Spark",
|
||||
"group": "build",
|
||||
@@ -402,132 +351,9 @@
|
||||
"id": "wrench"
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run Api Server",
|
||||
"dependsOn": "Build Api Server",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"command": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run Api Server (Debug)",
|
||||
"dependsOn": "Build Api Server (Debug)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"command": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run Api Server (Release)",
|
||||
"dependsOn": "Build Api Server (Release)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"command": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run Api Server (Debug | Skip Build)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"command": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run Api Server (Release | Skip Build)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
"command": "spark_api_server.exe",
|
||||
},
|
||||
"linux": {
|
||||
"command": "spark_api_server",
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:apiServerEnvironment}",
|
||||
}
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
"color": "terminal.ansiGreen",
|
||||
},
|
||||
},
|
||||
{
|
||||
"label": "Run DataStreamQueryAnalyzer",
|
||||
"dependsOn": "Build DataStreamQueryAnalyzer",
|
||||
"dependsOn": "Build DataStream",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
@@ -537,7 +363,7 @@
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -547,7 +373,7 @@
|
||||
},
|
||||
{
|
||||
"label": "Run DataStreamQueryAnalyzer (Debug)",
|
||||
"dependsOn": "Build DataStreamQueryAnalyzer (Debug)",
|
||||
"dependsOn": "Build DataStream (Debug)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
@@ -557,7 +383,7 @@
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -567,7 +393,7 @@
|
||||
},
|
||||
{
|
||||
"label": "Run DataStreamQueryAnalyzer (Release)",
|
||||
"dependsOn": "Build DataStreamQueryAnalyzer (Release)",
|
||||
"dependsOn": "Build DataStream (Release)",
|
||||
"type": "process",
|
||||
"command": "",
|
||||
"windows": {
|
||||
@@ -577,7 +403,7 @@
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamQueryAnalyzer/Configurations/DataStreamQueryAnalyzer.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -596,11 +422,12 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -618,11 +445,12 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -640,11 +468,12 @@
|
||||
"windows": {
|
||||
"command": "DataStreamPublisher.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/DataStreamPublisher/Configurations/${input:dataStreamPublisherConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:dataStreamPublisherEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -662,11 +491,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -684,11 +514,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -705,11 +536,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -727,11 +559,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -748,11 +581,12 @@
|
||||
"windows": {
|
||||
"command": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -767,7 +601,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -783,7 +617,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -799,7 +633,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/Release/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -814,7 +648,7 @@
|
||||
"windows": {
|
||||
"command": "Spark.exe",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0-windows"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0-windows"
|
||||
},
|
||||
},
|
||||
"icon": {
|
||||
@@ -839,7 +673,7 @@
|
||||
"${input:sparkConfigQuery}",
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net8.0"
|
||||
"cwd": "${workspaceFolder}/build/${input:buildConfiguration}/bin/net7.0"
|
||||
},
|
||||
"icon": {
|
||||
"id": "run",
|
||||
@@ -920,7 +754,7 @@
|
||||
"${input:sparkTest}"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net8.0",
|
||||
"cwd": "${workspaceFolder}/build/Debug/bin/net7.0",
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -1018,17 +852,6 @@
|
||||
},
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "apiServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "Api Server Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"Local",
|
||||
"Staging",
|
||||
],
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "buildConfiguration",
|
||||
"type": "pickString",
|
||||
@@ -1062,31 +885,26 @@
|
||||
"default": "sparkd-debug-clang",
|
||||
},
|
||||
{
|
||||
"id": "dataStreamPublisherEnvironment",
|
||||
"id": "dataStreamPublisherConfig",
|
||||
"type": "pickString",
|
||||
"description": "Publisher Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"MarketData",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
"MarketDataPublisher",
|
||||
"SimpleEchoClient",
|
||||
"SimpleTestDataPublisher",
|
||||
"TestDataPublisher",
|
||||
],
|
||||
"default": "MarketDataPublisher",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerEnvironment",
|
||||
"id": "pubSubServerConfig",
|
||||
"type": "pickString",
|
||||
"description": "PubSub Configuration",
|
||||
"options": [
|
||||
"Development",
|
||||
"EchoServer",
|
||||
"Local",
|
||||
"Production",
|
||||
"ProductionAws",
|
||||
"Staging",
|
||||
"PubSubServer",
|
||||
"SimpleEchoClient",
|
||||
],
|
||||
"default": "Development",
|
||||
"default": "PubSubServer",
|
||||
},
|
||||
{
|
||||
"id": "sparkConfigQuery",
|
||||
|
||||
+5
-4
@@ -21,7 +21,7 @@ set(
|
||||
# SHARED_MEMORY_PREFIX serves as a kind of namespace so multiple applications
|
||||
# can run simultaneously without fighting over the same shm files (e.g., sparkd,
|
||||
# api server, etc.).
|
||||
set(SHARED_MEMORY_PREFIX "\${BTS_SHARED_MEMORY_PREFIX}" CACHE STRING "Prefix to use when creating shared memory files")
|
||||
set(SHARED_MEMORY_PREFIX "bts" CACHE STRING "Prefix to use when creating shared memory files")
|
||||
set(EXTERNALS_BIN "${EXTERNALS_ROOT}/bin")
|
||||
set(EXTERNALS_INCLUDE "${EXTERNALS_ROOT}/include")
|
||||
set(EXTERNALS_LIB "${EXTERNALS_ROOT}/lib/$<CONFIG>")
|
||||
@@ -40,8 +40,9 @@ include_directories(BEFORE SYSTEM ${EXTERNALS_INCLUDE} ${EXTERNALS_ROOT}/include
|
||||
link_directories(${EXTERNALS_LIB})
|
||||
|
||||
add_compile_definitions(SHARED_MEMORY_PREFIX="${SHARED_MEMORY_PREFIX}")
|
||||
if(DEFINED APP_DATA_DIR)
|
||||
add_compile_definitions(APP_DATA_DIR="${APP_DATA_DIR}")
|
||||
add_compile_definitions(APP_DATA_DIR="${APP_DATA_DIR}")
|
||||
if(DEFINED APP_DATA_DIR_OVERRIDE)
|
||||
add_compile_definitions(APP_DATA_DIR_OVERRIDE="${APP_DATA_DIR_OVERRIDE}")
|
||||
endif()
|
||||
add_compile_definitions(EXPORT_MD_CONSUMER="${EXPORT_MD_CONSUMER}")
|
||||
if(WIN32)
|
||||
@@ -116,7 +117,7 @@ else()
|
||||
if (BUILD_SPARKD)
|
||||
add_subdirectory(src/lib_python_interop)
|
||||
add_subdirectory(src/lib_onixs_fix)
|
||||
add_subdirectory(src/lib_binance)
|
||||
add_subdirectory(src/lib_binance_execution)
|
||||
add_subdirectory(src/lib_okx_execution)
|
||||
add_subdirectory(src/app_sparkd)
|
||||
add_subdirectory(src/data_files)
|
||||
|
||||
+22
-6
@@ -20,6 +20,8 @@
|
||||
"SPARK_CMAKE_CXX_FLAGS": "/MP /WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR": "${dollar}{APPDATA}/bts",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_DATA_DIR}",
|
||||
"CMAKE_CXX_FLAGS": "$env{SPARK_CMAKE_CXX_FLAGS}",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "$env{SPARK_CMAKE_CXX_FLAGS} /MTd",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "$env{SPARK_CMAKE_CXX_FLAGS} /MT",
|
||||
@@ -34,7 +36,8 @@
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
},
|
||||
"SHARED_MEMORY_PREFIX": "spark"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -50,6 +53,8 @@
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"platform": "",
|
||||
"APP_DATA_DIR": "${dollar}{HOME}/sparkdata",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARKD_DATA_DIR}",
|
||||
"CMAKE_BUILD_WITH_INSTALL_RPATH": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -72,7 +77,8 @@
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
},
|
||||
"SHARED_MEMORY_PREFIX": "sparkd"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -153,7 +159,11 @@
|
||||
{
|
||||
"name": "spark-api-server-windows",
|
||||
"inherits": "spark",
|
||||
"displayName": "Spark Api Server (Windows)"
|
||||
"displayName": "Spark Api Server (Windows)",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_API_SERVER_DATA_DIR}",
|
||||
"SHARED_MEMORY_PREFIX": "spark_api_server"
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
@@ -162,6 +172,7 @@
|
||||
"displayName": "Spark Api Server (Linux)",
|
||||
"generator": "Ninja Multi-Config",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{SPARK_API_SERVER_DATA_DIR}",
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -218,8 +229,10 @@
|
||||
"description": "Data Stream utils ported over from Edge",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR": "${dollar}{APPDATA}/bts/DataStream",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{DATA_STREAM_DATA_DIR}",
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0;${sourceDir}/build/$<CONFIG>/bin/net8.0-windows"
|
||||
"SHARED_MEMORY_PREFIX": "data_stream"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -235,6 +248,8 @@
|
||||
"inherits": "sparkd",
|
||||
"generator": "Ninja Multi-Config",
|
||||
"cacheVariables": {
|
||||
"APP_DATA_DIR": "${dollar}{HOME}/.local/share/DataStream",
|
||||
"APP_DATA_DIR_OVERRIDE": "${dollar}{DATA_STREAM_DATA_DIR}",
|
||||
"BUILD_ADMIN_WEB_APP": {
|
||||
"type": "BOOL",
|
||||
"value": "OFF"
|
||||
@@ -252,11 +267,12 @@
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -DDEBUG",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers --std=c++20 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3",
|
||||
"CONFIG_DEFAULTS_PATH": "spark/config/profiles/default/*.conf;spark/config/profiles/data_stream/*.conf",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net8.0",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/net7.0",
|
||||
"EXPORT_MD_CONSUMER": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
}
|
||||
},
|
||||
"SHARED_MEMORY_PREFIX": "data_stream"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -42,10 +42,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.ColumnExpressions", "sr
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStream", "src\DataStreamSuite\DataStream\DataStream.csproj", "{39AEA075-6457-46C0-8821-1158BE6EFA57}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sdk", "sdk", "{56ACFCD1-60C7-4E2C-B90D-B1F95ECE33A1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Spark.Sdk", "src\sdk\Bts.Spark.Sdk\Bts.Spark.Sdk.csproj", "{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -198,14 +194,6 @@ Global
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -230,7 +218,5 @@ Global
|
||||
{39AEA075-6457-46C0-8821-1158BE6EFA57} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{9F6D7DE8-185B-4C1D-B809-3314D092DF28} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{6BD3F6D8-B6FC-44E8-B8FE-06352F638B9B} = {C09ED521-D2DF-40BC-A76F-EB3CB870B2F6}
|
||||
{56ACFCD1-60C7-4E2C-B90D-B1F95ECE33A1} = {267F81EF-A8AB-49FD-9F56-D7EC3C1F7C7C}
|
||||
{ADA9E802-8EFA-4E72-8E9A-6AA1E4181184} = {56ACFCD1-60C7-4E2C-B90D-B1F95ECE33A1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+51
-69
@@ -29,43 +29,36 @@ function(Protobuf_Generate_Cpp)
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
OUTPUT "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
COMMAND
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
ARGS
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR} ${_proto_include_cli_args} ${ABS_FIL}
|
||||
${Protobuf_PROTOC_EXECUTABLE} ARGS --cpp_out=${_ARGS_CXX_OUT_DIR} ${_proto_include_cli_args} ${ABS_FIL}
|
||||
DEPENDS ${ABS_FIL}
|
||||
COMMENT "Running C++ protocol buffer compiler on ${FIL}"
|
||||
VERBATIM
|
||||
)
|
||||
VERBATIM)
|
||||
endforeach()
|
||||
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
${${_ARGS_CXX_HEADERS}}
|
||||
PROPERTIES
|
||||
GENERATED TRUE
|
||||
)
|
||||
set_source_files_properties(${${_ARGS_CXX_SOURCES}} ${${_ARGS_CXX_HEADERS}} PROPERTIES GENERATED TRUE)
|
||||
|
||||
# remove some warnings from protobuf generated files
|
||||
if(WIN32)
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "/wd4309 /wd4838"
|
||||
)
|
||||
set_source_files_properties(${${_ARGS_CXX_SOURCES}} PROPERTIES COMPILE_FLAGS
|
||||
"/wd4309 /wd4838")
|
||||
else()
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-unused-parameter -Wno-effc++ -Wno-pedantic -Wno-sign-compare -Wno-uninitialized"
|
||||
COMPILE_FLAGS
|
||||
"-Wno-unused-parameter -Wno-effc++ -Wno-pedantic -Wno-sign-compare -Wno-uninitialized"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_SOURCES}
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS}
|
||||
${${_ARGS_CXX_HEADERS}}
|
||||
PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(Service_Compiler_Generate_Cpp)
|
||||
@@ -99,51 +92,40 @@ function(Service_Compiler_Generate_Cpp)
|
||||
list(APPEND ${_ARGS_CXX_HEADERS} "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h")
|
||||
|
||||
set(TEMPLATES
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/client.pb.cc
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/client.pb.h
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/server.pb.cc
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/server.pb.h
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/client.pb.cc
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/client.pb.h
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/server.pb.cc
|
||||
${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/templates/cpp/server.pb.h
|
||||
)
|
||||
|
||||
set(_plugin_py ${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/plugin.py)
|
||||
if(WIN32)
|
||||
set(_plugin_cmd ${CMAKE_SOURCE_DIR}/src/lib_spark/spark/api/service_compiler/plugin.cmd)
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h"
|
||||
OUTPUT "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h"
|
||||
COMMAND SET PYTHONPATH=${SPARK_PYTHON}
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/.venv/Scripts/activate.bat
|
||||
COMMAND
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
ARGS
|
||||
--cpp_out=${_ARGS_CXX_OUT_DIR}
|
||||
--plugin=protoc-gen-service=${_plugin_cmd}
|
||||
--service_out=lang=cpp:${_ARGS_CXX_OUT_DIR}
|
||||
-I ${PROTOBUF_INCLUDE_DIRS}
|
||||
-I ${_protobuf_src_dir}
|
||||
${ABS_FIL}
|
||||
DEPENDS
|
||||
${ABS_FIL}
|
||||
${TEMPLATES}
|
||||
${_plugin_cmd}
|
||||
${_plugin_py}
|
||||
${Protobuf_PROTOC_EXECUTABLE} ARGS --cpp_out=${_ARGS_CXX_OUT_DIR}
|
||||
--plugin=protoc-gen-service=${_plugin_cmd}
|
||||
--service_out=lang=cpp:${_ARGS_CXX_OUT_DIR} -I
|
||||
${PROTOBUF_INCLUDE_DIRS} -I ${_protobuf_src_dir} ${ABS_FIL}
|
||||
DEPENDS ${ABS_FIL} ${TEMPLATES} ${_plugin_cmd} ${_plugin_py}
|
||||
COMMENT "Running C++ service compiler on ${FIL}"
|
||||
VERBATIM
|
||||
)
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h"
|
||||
OUTPUT "${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.client.pb.h"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.cc"
|
||||
"${_ARGS_CXX_OUT_DIR}/${FIL_WE}.server.pb.h"
|
||||
COMMAND ${CMAKE_SOURCE_DIR}/tools/venv_exec.sh
|
||||
ARGS
|
||||
${Protobuf_PROTOC_EXECUTABLE}
|
||||
@@ -151,32 +133,32 @@ function(Service_Compiler_Generate_Cpp)
|
||||
--plugin=protoc-gen-service=${_plugin_py}
|
||||
--service_out=lang=cpp,make_file_name=${ABS_FIL}:${_ARGS_CXX_OUT_DIR}
|
||||
${_proto_include_cli_args} ${ABS_FIL}
|
||||
DEPENDS
|
||||
${ABS_FIL}
|
||||
${TEMPLATES}
|
||||
${_plugin_py}
|
||||
DEPENDS ${ABS_FIL} ${TEMPLATES} ${_plugin_py}
|
||||
COMMENT "Running C++ service compiler on ${FIL}"
|
||||
VERBATIM
|
||||
)
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
endforeach()
|
||||
|
||||
# remove some warnings from protobuf generated files
|
||||
if(WIN32)
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "/wd4309 /wd4838"
|
||||
)
|
||||
set_source_files_properties(${${_ARGS_CXX_SOURCES}} PROPERTIES COMPILE_FLAGS
|
||||
"/wd4309 /wd4838")
|
||||
else()
|
||||
set_source_files_properties(
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "-Wno-unused-parameter -Wno-effc++ -Wno-pedantic -Wno-sign-compare -Wno-uninitialized"
|
||||
COMPILE_FLAGS
|
||||
"-Wno-unused-parameter -Wno-effc++ -Wno-pedantic -Wno-sign-compare -Wno-uninitialized"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(${_ARGS_CXX_SOURCES} ${${_ARGS_CXX_SOURCES}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS} ${${_ARGS_CXX_HEADERS}} PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_SOURCES}
|
||||
${${_ARGS_CXX_SOURCES}}
|
||||
PARENT_SCOPE)
|
||||
set(${_ARGS_CXX_HEADERS}
|
||||
${${_ARGS_CXX_HEADERS}}
|
||||
PARENT_SCOPE)
|
||||
|
||||
endfunction()
|
||||
|
||||
+20
-111
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
sparkd:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/.local/share/bts/sparkd/data
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
|
||||
build:
|
||||
dockerfile: src/app_sparkd/Dockerfile
|
||||
args:
|
||||
@@ -12,20 +12,16 @@ services:
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
command: >
|
||||
sh -c "
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/.local/share/bts/sparkd/data
|
||||
if [ -e "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log" ]; then
|
||||
mv "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log" "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/sparkdata/data
|
||||
if [ -e "/home/bts/sparkdata/data/logging.sparkd/log" ]; then
|
||||
mv "/home/bts/sparkdata/data/logging.sparkd/log" "/home/bts/sparkdata/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
|
||||
fi
|
||||
if [ -e "/home/bts/.local/share/bts/sparkd/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/.local/share/bts/sparkd/conf/.env.local'
|
||||
if [ -e "/home/bts/sparkdata/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/sparkdata/conf/.env.local'
|
||||
set -a
|
||||
. /home/bts/.local/share/bts/sparkd/conf/.env.local
|
||||
. /home/bts/sparkdata/conf/.env.local
|
||||
set +a
|
||||
fi
|
||||
if [ -d /home/bts/.local/share/bts/sparkd/conf/plugins ]; then
|
||||
echo 'Copying /home/bts/.local/share/bts/sparkd/conf/plugins to runtime dir (/home/bts/bin)'
|
||||
cp -r /home/bts/.local/share/bts/sparkd/conf/plugins /home/bts/bin/
|
||||
fi
|
||||
./sparkd run"
|
||||
env_file:
|
||||
- .env
|
||||
@@ -41,8 +37,8 @@ services:
|
||||
|
||||
sparkd-symbols:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/.local/share/bts/sparkd/data
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/.local/share/bts/sparkd/conf
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/sparkdata/conf
|
||||
build:
|
||||
dockerfile: src/app_sparkd/Dockerfile
|
||||
args:
|
||||
@@ -53,22 +49,18 @@ services:
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
command: >
|
||||
sh -c "
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/.local/share/bts/sparkd
|
||||
if [ -e "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log" ]; then
|
||||
mv "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log" "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/sparkdata
|
||||
if [ -e "/home/bts/sparkdata/data/logging.sparkd/log" ]; then
|
||||
mv "/home/bts/sparkdata/data/logging.sparkd/log" "/home/bts/sparkdata/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
|
||||
fi
|
||||
ls -alh /home/bts/.local/share/bts/sparkd/conf/
|
||||
cat /home/bts/.local/share/bts/sparkd/conf/.env.local
|
||||
if [ -e "/home/bts/.local/share/bts/sparkd/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/.local/share/bts/sparkd/conf/.env.local'
|
||||
ls -alh /home/bts/sparkdata/conf/
|
||||
cat /home/bts/sparkdata/conf/.env.local
|
||||
if [ -e "/home/bts/sparkdata/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/sparkdata/conf/.env.local'
|
||||
set -a
|
||||
. /home/bts/.local/share/bts/sparkd/conf/.env.local
|
||||
. /home/bts/sparkdata/conf/.env.local
|
||||
set +a
|
||||
fi
|
||||
if [ -d /home/bts/.local/share/bts/sparkd/conf/plugins ]; then
|
||||
echo 'Copying /home/bts/.local/share/bts/sparkd/conf/plugins to runtime dir (/home/bts/bin)'
|
||||
cp -r /home/bts/.local/share/bts/sparkd/conf/plugins /home/bts/bin/
|
||||
fi
|
||||
./sparkd run"
|
||||
env_file:
|
||||
- .env
|
||||
@@ -91,10 +83,10 @@ services:
|
||||
- type: volume
|
||||
read_only: true
|
||||
source: sparkd_data
|
||||
target: /home/bts/.local/share/bts/sparkd/data/logging.sparkd
|
||||
target: /home/bts/sparkdata/data/logging.sparkd
|
||||
volume:
|
||||
subpath: logging
|
||||
command: ["tail", "-f", "/home/bts/.local/share/bts/sparkd/data/logging.sparkd/log"]
|
||||
subpath: logging.sparkd
|
||||
command: ["tail", "-f", "/home/bts/sparkdata/data/logging.sparkd/log"]
|
||||
|
||||
sparkd-ping-test:
|
||||
depends_on:
|
||||
@@ -109,89 +101,6 @@ services:
|
||||
RUN apt-get update && apt-get -y install iputils-ping
|
||||
command: [ "ping", "sparkd" ]
|
||||
|
||||
pubsub:
|
||||
volumes:
|
||||
- ${PUBSUB__DATA_DIR:-pubsub_data}:/home/bts/.local/share/bts/PubSubServer/data
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/PubSubServer/Dockerfile
|
||||
args:
|
||||
- SOURCE_DIR=${PUBSUB__SOURCE_DIR}
|
||||
- CONFIG_DIR=${PUBSUB__CONFIG_DIR}
|
||||
ports:
|
||||
- 22019:22019
|
||||
command: >
|
||||
sh -c "
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/.local/share/bts/PubSubServer
|
||||
if [ -e "/home/bts/.local/share/bts/PubSubServer/data/logging.PubSubServer/log" ]; then
|
||||
mv "/home/bts/.local/share/bts/PubSubServer/data/logging.PubSubServer/log" "/home/bts/.local/share/bts/PubSubServer/data/logging.PubSubServer/log_$(date '+%Y%m%d-%H%M')"
|
||||
fi
|
||||
if [ -e "/home/bts/.local/share/bts/PubSubServer/conf/.env" ]; then
|
||||
echo 'Sourcing /home/bts/.local/share/bts/PubSubServer/conf/.env'
|
||||
set -a
|
||||
. /home/bts/.local/share/bts/PubSubServer/conf/.env
|
||||
set +a
|
||||
fi
|
||||
if [ -e "/home/bts/.local/share/bts/PubSubServer/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/.local/share/bts/PubSubServer/conf/.env.local'
|
||||
set -a
|
||||
. /home/bts/.local/share/bts/PubSubServer/conf/.env.local
|
||||
set +a
|
||||
fi
|
||||
./PubSubServer"
|
||||
env_file:
|
||||
- .env
|
||||
- ${PUBSUB__CONFIG_DIR}/.env
|
||||
|
||||
md-publisher:
|
||||
volumes:
|
||||
- ${MD_PUBLISHER__DATA_DIR:-md_publisher_data}:/home/bts/.local/share/bts/DataStreamPublisher/data
|
||||
- historic_md:/home/bts/.local/share/bts/databento
|
||||
build:
|
||||
dockerfile: src/DataStreamSuite/DataStreamPublisher/Dockerfile
|
||||
args:
|
||||
- SOURCE_DIR=${MD_PUBLISHER__SOURCE_DIR}
|
||||
- CONFIG_DIR=${MD_PUBLISHER__CONFIG_DIR}
|
||||
command: >
|
||||
sh -c "
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/.local/share/bts/DataStreamPublisher
|
||||
if [ -e "/home/bts/.local/share/bts/DataStreamPublisher/data/logging.DataStreamPublisher/log" ]; then
|
||||
mv "/home/bts/.local/share/bts/DataStreamPublisher/data/logging.DataStreamPublisher/log" "/home/bts/.local/share/bts/DataStreamPublisher/data/logging.DataStreamPublisher/log_$(date '+%Y%m%d-%H%M')"
|
||||
fi
|
||||
if [ -e "/home/bts/.local/share/bts/DataStreamPublisher/conf/.env" ]; then
|
||||
echo 'Sourcing /home/bts/.local/share/bts/DataStreamPublisher/conf/.env'
|
||||
set -a
|
||||
. /home/bts/.local/share/bts/DataStreamPublisher/conf/.env
|
||||
set +a
|
||||
fi
|
||||
if [ -e "/home/bts/.local/share/bts/DataStreamPublisher/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/.local/share/bts/DataStreamPublisher/conf/.env.local'
|
||||
set -a
|
||||
. /home/bts/.local/share/bts/DataStreamPublisher/conf/.env.local
|
||||
set +a
|
||||
fi
|
||||
dockerize -wait tcp://pubsub:22019 -timeout 10s ./DataStreamPublisher"
|
||||
env_file:
|
||||
- .env
|
||||
- ${MD_PUBLISHER__CONFIG_DIR}/.env
|
||||
|
||||
api-server:
|
||||
depends_on:
|
||||
- sparkd
|
||||
ports:
|
||||
- 8008:8008
|
||||
- 9443:9443
|
||||
build:
|
||||
dockerfile: src/client/spark_api_server/Dockerfile
|
||||
command: [ "dockerize", "-wait", "tcp://sparkd:8000", "-timeout", "10s", "./spark_api_server", "run" ]
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Staging
|
||||
|
||||
volumes:
|
||||
sparkd_data:
|
||||
name: "sparkd_${SPARKD__CONFIG_PORT:-8000}"
|
||||
pubsub_data:
|
||||
name: "pubsub_22019"
|
||||
md_publisher_data:
|
||||
name: "md_publisher_22019"
|
||||
historic_md:
|
||||
name: "historic_md"
|
||||
Submodule
+1
Submodule docker/linux added at 6537812262.
Submodule
+1
Submodule docker/windows added at de7d40c09d.
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.200",
|
||||
"rollForward": "latestMajor"
|
||||
}
|
||||
}
|
||||
+103
-164
@@ -1,164 +1,103 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32922.545
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStreamCore", "src\DataStreamSuite\DataStreamCore\DataStreamCore.csproj", "{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataStream", "src\DataStreamSuite\DataStream\DataStream.csproj", "{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedStreams", "src\DataStreamSuite\SharedStreams\SharedStreams.csproj", "{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PubSub", "src\DataStreamSuite\PubSub\PubSub.csproj", "{51C40BA9-F226-4A35-939D-1ED6F5FF7299}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4564E677-343A-46CB-AF02-AFC4E38BF94B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "client", "client", "{56A8A70A-DA03-4CED-A144-EC10F1379FD8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataStreamSuite", "DataStreamSuite", "{915EF238-CA0D-4E73-AF50-88CB3F29C7AD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Extensions.Hosting", "src\DataStreamSuite\Bts.Extensions.Hosting\Bts.Extensions.Hosting.csproj", "{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
Release|x64 = Release|x64
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E4F491F-C688-43C4-88DA-AC92BC5FA1B8}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{2AC54ADC-3246-427E-9CA9-FEA2DBCB9432}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E96E5CC-7791-40B3-A8A1-C34FBB736B3B}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.Release|x64.Build.0 = Release|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{51C40BA9-F226-4A35-939D-1ED6F5FF7299}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{56A8A70A-DA03-4CED-A144-EC10F1379FD8} = {4564E677-343A-46CB-AF02-AFC4E38BF94B}
|
||||
{915EF238-CA0D-4E73-AF50-88CB3F29C7AD} = {4564E677-343A-46CB-AF02-AFC4E38BF94B}
|
||||
{4E0E51AA-7B59-4808-B7CC-9EAEDF397460} = {915EF238-CA0D-4E73-AF50-88CB3F29C7AD}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32922.545
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_websocket", "src\client\spark_websocket\spark_websocket.csproj", "{3201359D-C071-4089-9EDE-B04D759F1508}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api_server", "src\client\spark_api_server\spark_api_server.csproj", "{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
Release|x64 = Release|x64
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Debug|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.Release|x64.Build.0 = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{3201359D-C071-4089-9EDE-B04D759F1508}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Debug|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.ActiveCfg = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.MinSizeRel|x64.Build.0 = Debug|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.Release|x64.Build.0 = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{2B8C5D01-FF78-4BFA-B332-5E430586DAF9}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -8,6 +8,7 @@
|
||||
public int Integer;
|
||||
public double Real;
|
||||
public string Identifier;
|
||||
public DateTime DateTime;
|
||||
public ImmutableList<IArithmeticExpression> Arguments;
|
||||
public ImmutableList<Assignment> Assignments;
|
||||
public IArithmeticExpression Argument;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace BCG
|
||||
@@ -12,7 +10,6 @@ namespace BCG
|
||||
rk.SetValue (name, value.ToString ());
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static double getValue (RegistryKey rk, string name)
|
||||
{
|
||||
object v = rk.GetValue (name);
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
namespace Bts.BooleanExpressions;
|
||||
|
||||
using bts;
|
||||
|
||||
class BooleanExpression : IBooleanExpression {
|
||||
readonly Func<IDictionary<string, object?>, bool> evaluate;
|
||||
|
||||
public BooleanExpression(Func<IDictionary<string, object?>, bool> evaluate) =>
|
||||
this.evaluate = evaluate;
|
||||
|
||||
public bool Evaluate(IDictionary<string, object?> env) =>
|
||||
evaluate(env);
|
||||
public bool Evaluate(IDictionary<string, object?> env) {
|
||||
try {
|
||||
return evaluate(env);
|
||||
} catch (Exception ex) {
|
||||
Log.assert(false, $"BooleanExpression.Evaluate failed: {ex}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,11 @@ IsOfType '/'
|
||||
|
||||
%%
|
||||
|
||||
{StringConstant} {
|
||||
yylval.String = yytext.Substring(1, yytext.Length - 2).Replace(@"\'", "'");
|
||||
return (int)Token.STRING_CONSTANT;
|
||||
}
|
||||
|
||||
{BooleanConstant} {
|
||||
yylval.Boolean = yytext.ToLower() switch {
|
||||
"true" => true,
|
||||
@@ -57,11 +62,6 @@ IsOfType '/'
|
||||
return (int)Token.BOOLEAN_CONSTANT;
|
||||
}
|
||||
|
||||
{StringConstant} {
|
||||
yylval.String = yytext.Substring(1, yytext.Length - 2).Replace(@"\'", "'");
|
||||
return (int)Token.STRING_CONSTANT;
|
||||
}
|
||||
|
||||
{NullConstant} {
|
||||
yylval.Null = DBNull.Value;
|
||||
return (int)Token.NULL_CONSTANT;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,71 +0,0 @@
|
||||
namespace Bts.Extensions.Hosting;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
public static class HostBuilderExtensions {
|
||||
public static IHostBuilder CreateBtsBuilder(string[] args) {
|
||||
// Obtain calling assembly name here, rather than in the lambda where it is actually needed,
|
||||
// because want the name of the assembly that called this function, not the assembly that will eventually invoke
|
||||
// the lambda...that will be the Microsoft.Extensions.Hosting assembly.
|
||||
// Get the name of the assembly that called this function. That will act as the "appsettings"
|
||||
// json file prefix
|
||||
var exeName = GetCallingAssemblyName();
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.ConfigureAppConfiguration((context, configBuilder) =>
|
||||
ConfigureApp(configBuilder, context.HostingEnvironment.EnvironmentName, exeName));
|
||||
}
|
||||
|
||||
public static void ConfigureApp(IConfigurationBuilder configBuilder, string? environment = null, string? prefix = null) {
|
||||
var baseFileName = prefix is null ? "appsettings" : $"{prefix}.appsettings";
|
||||
AddJsonFile($"{baseFileName}.json");
|
||||
if (environment is not null) {
|
||||
AddJsonFile($"{baseFileName}.{environment}.json");
|
||||
}
|
||||
|
||||
var cfg = configBuilder.Build().GetSection("config")?.Value;
|
||||
if (!SetBasePath(cfg)) {
|
||||
AddJsonFile(cfg);
|
||||
}
|
||||
|
||||
bool SetBasePath(string? path) {
|
||||
if (!Directory.Exists(path)) {
|
||||
return false;
|
||||
}
|
||||
configBuilder.SetBasePath(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddJsonFile(string? path) {
|
||||
if (!File.Exists(path)) {
|
||||
return false;
|
||||
}
|
||||
configBuilder.AddJsonFile(path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void ConfigureLogging(ILoggingBuilder loggingBuilder, ILoggerProvider loggerProvider) =>
|
||||
loggingBuilder.AddFilter("Microsoft", LogLevel.Warning)
|
||||
.AddFilter("System", LogLevel.Warning)
|
||||
.AddFilter("NToastNotify", LogLevel.Warning)
|
||||
.AddProvider(loggerProvider)
|
||||
.AddSimpleConsole(opts => {
|
||||
opts.SingleLine = true;
|
||||
opts.TimestampFormat = "yyyy-MM-dd HH:mm:ss.ffffff|";
|
||||
})
|
||||
.AddDebug();
|
||||
|
||||
public static string GetCallingAssemblyName() =>
|
||||
new StackTrace()
|
||||
.GetFrame(2)
|
||||
?.GetMethod()
|
||||
?.Module
|
||||
?.Assembly
|
||||
?.GetName()
|
||||
?.Name
|
||||
?? throw new InvalidOperationException("Failed to determine name of calling assembly (calling method is null)");
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,28 +0,0 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Provides facilities to compare hosts for equality.
|
||||
/// <para>
|
||||
/// This class doesn't implement IEqualityComparer because a consistent hash code cannot be
|
||||
/// guarenteed for equivalent host strings. The equals impl relies on Dns.GetHostAddresses, which
|
||||
/// is non-determinstic (implementations that depends on mutable properties face a similar problem).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class HostComparer {
|
||||
public static bool Equals(string? x, string? y) {
|
||||
if (x is null) {
|
||||
return y is null;
|
||||
}
|
||||
if (y is null) {
|
||||
return false;
|
||||
}
|
||||
return Dns.GetHostAddresses(x).Intersect(
|
||||
Dns.GetHostAddresses(y), IpAddressComparer.Instance).Any();
|
||||
}
|
||||
|
||||
public static bool Equals(IPHostEntry x, IPHostEntry y) =>
|
||||
x.AddressList.Intersect(y.AddressList, IpAddressComparer.Instance).Any();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// Compares ip addresses. Unlike the default comparer, v4 and equivalent v6 addresses are
|
||||
/// considered equal.
|
||||
/// </summary>
|
||||
public class IpAddressComparer : IEqualityComparer<IPAddress> {
|
||||
public static IEqualityComparer<IPAddress> Instance { get; } = new IpAddressComparer();
|
||||
|
||||
public bool Equals(IPAddress? x, IPAddress? y) {
|
||||
if (x is null) {
|
||||
return y is null;
|
||||
}
|
||||
if (y is null) {
|
||||
return false;
|
||||
}
|
||||
return x.Equals(y) ||
|
||||
(x.IsIPv4MappedToIPv6 && x.MapToIPv4().Equals(y)) ||
|
||||
(y.IsIPv4MappedToIPv6 && y.MapToIPv4().Equals(x));
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] IPAddress address) =>
|
||||
address.IsIPv4MappedToIPv6
|
||||
// Return consistent hash code for v4 and equivalent v6
|
||||
? address.MapToIPv4().GetHashCode()
|
||||
: address.GetHashCode();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
public class IpHostEntryJsonConverter : JsonConverter<IPHostEntry> {
|
||||
public override IPHostEntry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, IPHostEntry value, JsonSerializerOptions options) {
|
||||
writer.WriteStartObject();
|
||||
// HostName
|
||||
writer.WriteString(nameof(value.HostName), value.HostName);
|
||||
// Aliases
|
||||
writer.WritePropertyName("Aliases");
|
||||
writer.WriteStartArray();
|
||||
foreach (var alias in value.Aliases) {
|
||||
writer.WriteStringValue(alias);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
// Addresses
|
||||
writer.WritePropertyName("Addresses");
|
||||
writer.WriteStartArray();
|
||||
foreach (var address in value.AddressList) {
|
||||
writer.WriteStringValue(address.ToString());
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
/// <summary>
|
||||
/// This class seriailzes IpHostEntry to json (string). A common buffer is used to reduce memory
|
||||
/// allocations on repeated calls to <see cref="Serialize"/>. For that reason, this class is NOT
|
||||
/// thread safe.
|
||||
/// </summary>
|
||||
public class IpHostEntryJsonSerializer {
|
||||
readonly MemoryStream buffer = new();
|
||||
readonly IpHostEntryJsonConverter converter;
|
||||
|
||||
public IpHostEntryJsonSerializer(IpHostEntryJsonConverter? converter = null) =>
|
||||
this.converter = converter ?? new() { };
|
||||
|
||||
public string? Serialize(IPHostEntry dp, JsonSerializerOptions? opts = null) {
|
||||
opts ??= JsonSerializerOptions.Default;
|
||||
buffer.Position = 0;
|
||||
buffer.SetLength(0);
|
||||
using (var jsonWriter = new Utf8JsonWriter(buffer)) {
|
||||
converter.Write(jsonWriter, dp, opts);
|
||||
}
|
||||
var bytes = buffer.GetBuffer();
|
||||
var span = new ArraySegment<byte>(bytes, 0, (int)buffer.Length);
|
||||
return Encoding.UTF8.GetString(span);
|
||||
}
|
||||
|
||||
public void Serialize(IPHostEntry dp, Utf8JsonWriter jsonWriter, JsonSerializerOptions? opts = null) {
|
||||
opts ??= JsonSerializerOptions.Default;
|
||||
buffer.Position = 0;
|
||||
buffer.SetLength(0);
|
||||
converter.Write(jsonWriter, dp, opts);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
namespace Bts.Net;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
public static partial class IpUtils {
|
||||
static readonly Regex ipv4Regex = new(string.Join('.', @"(((0|1)\d)|(2\d)|\d)?\d"));
|
||||
|
||||
// public static void ParseUri(string str, out string? scheme, out string? host, out string? port, out string? path, out string? queryParams) {
|
||||
// if (Uri.TryCreate(str, UriKind.Absolute, out var uri)) {
|
||||
// }
|
||||
// }
|
||||
|
||||
// public static bool AreEndpointsEqual(Uri? x, Uri? y) {
|
||||
// if (x is null) {
|
||||
// return y is null;
|
||||
// }
|
||||
// if (y is null) {
|
||||
// return false;
|
||||
// }
|
||||
// if (x.IsAbsoluteUri != y.IsAbsoluteUri) {
|
||||
// return false;
|
||||
// }
|
||||
// if (x.IsAbsoluteUri) {
|
||||
// if (x.Scheme != y.Scheme) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// string? xHost = null;
|
||||
// }
|
||||
|
||||
// static string ResolveHostIpv4(Uri uri) {
|
||||
// // switch (uri.HostNameType) {
|
||||
// // case UriHostNameType.IPv4:
|
||||
// // return uri.Host;
|
||||
// // case UriHostNameType.Dns:
|
||||
// // break;
|
||||
// // case UriHostNameType.IPv6:
|
||||
// // var addresses = Dns.GetHostAddresses(uri.Host);
|
||||
// // foreach (var address in addresses) {
|
||||
// // if (address.IsIPv4MappedToIPv6) {
|
||||
// // return address.MapToIPv4().Address;
|
||||
// // }
|
||||
// // }
|
||||
// // break;
|
||||
// // }
|
||||
// var hostAddresses = Dns.GetHostAddresses(uri.Host);
|
||||
// foreach (IPAddress address in hostAddresses) {
|
||||
// if (address.Equals(remoteEndPoint.Address) ||
|
||||
// (address.IsIPv4MappedToIPv6 && address.MapToIPv4().Equals(remoteEndPoint.Address)) ||
|
||||
// (remoteEndPoint.Address.IsIPv4MappedToIPv6 && remoteEndPoint.Address.MapToIPv4().Equals(address))) {
|
||||
// isMatch = true;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// public static bool AreEndpointsEqual(string? x, string? y) {
|
||||
// if (x == y) {
|
||||
// return true;
|
||||
// }
|
||||
// if (x is null) {
|
||||
// return y is null;
|
||||
// }
|
||||
// if (y is null) {
|
||||
// return false;
|
||||
// }
|
||||
// var xUri = new Uri(x);
|
||||
// var yUri = new Uri(y);
|
||||
// // return xUri.Equals(yUri);
|
||||
// }
|
||||
|
||||
public static bool IsIpv4(string host) {
|
||||
host = removeSchemaFromUrl(host);
|
||||
host = removePortFromUrl(host);
|
||||
return ipv4Regex.IsMatch(host);
|
||||
}
|
||||
|
||||
static string removeSchemaFromUrl(string url) {
|
||||
var i = url.IndexOf("://");
|
||||
return i < 0 ? url : url.Substring(i + 3);
|
||||
}
|
||||
|
||||
static string removePortFromUrl(string url) {
|
||||
var match = MyRegex().Match(url);
|
||||
return match.Success
|
||||
? string.Concat(url.AsSpan(0, match.Index), url.AsSpan(match.Index + match.Length))
|
||||
: url;
|
||||
}
|
||||
|
||||
[GeneratedRegex(":\\d{1,4}")]
|
||||
private static partial Regex MyRegex();
|
||||
}
|
||||
@@ -7,11 +7,14 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="YaccLexTools" Version="1.2.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
|
||||
<ProjectReference Include="..\ExpressionCore\ExpressionCore.csproj" />
|
||||
<ProjectReference Include="..\..\client\spark_core\spark_core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Label="ColumnMapExpression">
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
[DataStreamUserRespresentation("AddColumnsStream")]
|
||||
public class AddColumnsStream: ViewStream {
|
||||
public AddColumnsStream(ViewStream parent_str, string add_col_expr) {
|
||||
ViewStream rs = new BCG.AddColumnsStream(parent_str, add_col_expr);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class BlueAddIndexColumnTable : IBlueRowCollection {
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly IList<object?>[] columnValues;
|
||||
readonly int count;
|
||||
|
||||
BlueAddIndexColumnTable(IBlueTableSchema schema, IList<object?>[] columnValues, int? count = null) {
|
||||
this.schema = schema;
|
||||
this.columnValues = columnValues;
|
||||
this.count = count ?? columnValues[0].Count;
|
||||
}
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
public int Count => count;
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
id > 0 && id <= count
|
||||
? GetRow(id - 1)
|
||||
: throw new KeyNotFoundException();
|
||||
|
||||
public static BlueAddIndexColumnTable Create(string tableName, ColumnInfo[] columnInfos, IList<object?>[] columnValues) {
|
||||
if (columnInfos.Any(c => c.colName == "id")) {
|
||||
throw new ArgumentException("'id' column already exists", nameof(columnInfos));
|
||||
}
|
||||
if (columnInfos.Length != columnValues.Length) {
|
||||
throw new ArgumentException("columnValues length differs from columnInfos length", nameof(columnValues));
|
||||
}
|
||||
int count = columnValues.FirstOrDefault()?.Count ?? 0;
|
||||
var origCols = columnInfos;
|
||||
var origColValues = columnValues;
|
||||
columnInfos = new ColumnInfo[origCols.Length + 1];
|
||||
columnInfos[0] = new ColumnInfo("id", 0, typeof(int));
|
||||
columnValues = new IList<object?>[origCols.Length + 1];
|
||||
columnValues[0] = new StepList<int>(1, 1, count).WrapSelector(id => (object?)id, null);
|
||||
for (int i = 1; i < columnInfos.Length; i++) {
|
||||
columnInfos[i] = new ColumnInfo(origCols[i - 1].colName, i, origCols[i - 1].colType);
|
||||
columnValues[i] = origColValues[i - 1];
|
||||
}
|
||||
var schema = new BlueTableSchema(columnInfos, tableName);
|
||||
return new(schema, columnValues, count);
|
||||
}
|
||||
|
||||
public static BlueAddIndexColumnTable Create(IBlueTableSchema schema, IList<object?>[] columnValues) {
|
||||
int count = columnValues.FirstOrDefault()?.Count ?? 0;
|
||||
int? idColIdx = schema.TryResolveIndices("id");
|
||||
var idColValues = new StepList<int>(1, 1, count).WrapSelector(id => (object?)id, null);
|
||||
var columnInfos = schema.columnInfo;
|
||||
if (idColIdx.HasValue) {
|
||||
// Replace existing id column. columnValues may or may not contain the old ids (if its
|
||||
// length is one less column than that of columnInfos, it doesn't contain them).
|
||||
switch (columnValues.Length - schema.columnInfo.Length) {
|
||||
case 0:
|
||||
columnValues[idColIdx.Value] = idColValues;
|
||||
break;
|
||||
case -1:
|
||||
columnValues = ArrayHelper.InsertExact(columnValues, idColIdx.Value, true, idColValues);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("ColumnInfos length disagrees with columnValues length");
|
||||
}
|
||||
} else {
|
||||
if (columnValues.Length != columnInfos.Length) {
|
||||
throw new ArgumentException("ColumnInfos length disagrees with columnValues length");
|
||||
}
|
||||
var origColInfos = columnInfos;
|
||||
columnInfos = new ColumnInfo[columnInfos.Length + 1];
|
||||
columnInfos[0] = new("id", 0, typeof(int));
|
||||
for (int i = 1; i < columnInfos.Length; i++) {
|
||||
var c = origColInfos[i - 1];
|
||||
columnInfos[i] = new(c.colName, c.colNo + 1, c.colType);
|
||||
}
|
||||
columnValues = ArrayHelper.InsertExact(columnValues, 0, true, idColValues);
|
||||
}
|
||||
return new(new BlueTableSchema(schema.tableName, columnInfos), columnValues);
|
||||
}
|
||||
|
||||
public bool containsID(int id) =>
|
||||
id > 0 && id <= count;
|
||||
|
||||
public IList<object?> GetColumn(int index) =>
|
||||
columnValues[index];
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new BlueRowColumnWrapper(schema, index, columnValues);
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
return id > 0 && id <= count && BlueRowEqualityComparer.Equals(GetRow(id - 1), item)
|
||||
? id - 1
|
||||
: -1;
|
||||
}
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
int count = Count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
yield return GetRow(i);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public class BlueIndexedColumnTable : IBlueRowCollection {
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly IList<object?>[] columnValues;
|
||||
readonly Dictionary<int, int> rowIdToIndex;
|
||||
|
||||
public BlueIndexedColumnTable(IBlueTableSchema schema, IList<object?>[] columnValues) {
|
||||
this.schema = schema;
|
||||
this.columnValues = columnValues;
|
||||
int idColumnIndex = schema.ResolveIndices("id");
|
||||
rowIdToIndex = columnValues[idColumnIndex]
|
||||
.Select((idObj, idx) => new KeyValuePair<int, int>(ExceptionAssert.Argument.Is<int>(idObj), idx))
|
||||
.ToDictionary();
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
rowIdToIndex.TryGetValue(id, out var idx)
|
||||
? GetRow(idx)
|
||||
: throw new KeyNotFoundException();
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
public int Count => rowIdToIndex.Count;
|
||||
|
||||
public bool containsID(int id) =>
|
||||
rowIdToIndex.ContainsKey(id);
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
int count = Count;
|
||||
for (int i = 0; i < count; i++) {
|
||||
yield return GetRow(i);
|
||||
}
|
||||
}
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
new BlueRowColumnWrapper(schema, index, columnValues);
|
||||
|
||||
public int IndexOf(IBlueRow item) =>
|
||||
rowIdToIndex.TryGetValue(item.Id(), out var idx) && BlueRowEqualityComparer.Equals(GetRow(idx), item)
|
||||
? idx
|
||||
: -1;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using BCG;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class BlueRowColumnWrapper : IBlueRow {
|
||||
readonly int index;
|
||||
readonly IList<object?>[] columns;
|
||||
|
||||
public BlueRowColumnWrapper(IBlueTableSchema schema, int index, IList<object?>[] columns) {
|
||||
this.schema = schema;
|
||||
this.index = index;
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public object? this[int index] =>
|
||||
columns[index][this.index];
|
||||
|
||||
public IBlueTableSchema schema { get; }
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using System;
|
||||
|
||||
using BCG;
|
||||
|
||||
[DataStreamUserRespresentation("CSVReaderStream")]
|
||||
public class CSVReaderStream : ViewStream {
|
||||
public CSVReaderStream(string file_name)
|
||||
: this(file_name, false) { }
|
||||
public CSVReaderStream(string file_name, bool guess_schema) {
|
||||
ViewStream rs = new BCG.CSVReaderStream(file_name);
|
||||
if (guess_schema) {
|
||||
rs = new SchemaGuesserStream(rs);
|
||||
}
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
|
||||
[DataStreamUserRespresentation("CSVSaverStream")]
|
||||
public class CSVSaverStream: ViewStream {
|
||||
public CSVSaverStream(ViewStream parent_str, string file_name) {
|
||||
BCG.CSVSaverStream rs = new BCG.CSVSaverStream(parent_str, file_name, true, Int32.MaxValue, false);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace BCG {
|
||||
[DataStreamUserRespresentation("CountStream")]
|
||||
[DataStreamUserRespresentation("count")]
|
||||
public class CountStream : ViewStream {
|
||||
private DataPacket myLastFiredDataPacket;
|
||||
private IBlueTableSchema mySchema = new BlueTableSchema("count",
|
||||
@@ -14,6 +14,9 @@ namespace BCG {
|
||||
myVS = vs;
|
||||
}
|
||||
|
||||
public CountStream(string tableName)
|
||||
: this(new TableStream(tableName)) { }
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
myVS.onChange += new ChangeDelegate(myHandleChanges);
|
||||
}
|
||||
|
||||
@@ -3,34 +3,36 @@ namespace bts.BlueOrb {
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
[DataStreamUserRespresentation("FilterStream")]
|
||||
public class FilterStream : ViewStream {
|
||||
public class RegExpFilter : IStreamFilter {
|
||||
private Regex[] myRegExps;
|
||||
private string[] myCols;
|
||||
|
||||
public RegExpFilter(string col, string regExp)
|
||||
: this(new string[] { col }, new string[] { regExp }) { }
|
||||
public class RegExpFilter : IStreamFilter {
|
||||
private Regex[] myRegExps;
|
||||
private string[] myCols;
|
||||
|
||||
public RegExpFilter(string[] cols, string[] regExps) {
|
||||
myCols = cols;
|
||||
myRegExps = new Regex[regExps.Length];
|
||||
for (int i = 0; i < regExps.Length; i++)
|
||||
myRegExps[i] = new Regex(regExps[i]);
|
||||
}
|
||||
public RegExpFilter(string col, string regExp)
|
||||
: this(new string[] { col }, new string[] { regExp }) { }
|
||||
|
||||
#region IStreamFilter Members
|
||||
public bool filter(IBlueRow dr) {
|
||||
bool rv = true;
|
||||
for (int i = 0; i < myCols.Length; i++) {
|
||||
rv &= myRegExps[i].IsMatch(dr[myCols[i]] is DBNull ? "" : dr[myCols[i]].ToString());
|
||||
if (!rv)
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endregion
|
||||
public RegExpFilter(string[] cols, string[] regExps) {
|
||||
myCols = cols;
|
||||
myRegExps = new Regex[regExps.Length];
|
||||
for (int i = 0; i < regExps.Length; i++)
|
||||
myRegExps[i] = new Regex(regExps[i]);
|
||||
}
|
||||
|
||||
#region IStreamFilter Members
|
||||
public bool filter(IBlueRow dr) {
|
||||
bool rv = true;
|
||||
for (int i = 0; i < myCols.Length; i++) {
|
||||
rv &= myRegExps[i].IsMatch(dr[myCols[i]] is DBNull ? "" : dr[myCols[i]].ToString());
|
||||
if (!rv)
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
//[DataStreamUserReprsentation("FilterStream")]
|
||||
public class FilterStream : ViewStream {
|
||||
private BlueTable myLastFiredRows;
|
||||
private IBlueRowCollection myLastReceivedRows;
|
||||
private IStreamFilter myFilter;
|
||||
|
||||
@@ -34,8 +34,7 @@ namespace bts.BlueOrb {
|
||||
if (out_rows != null && out_rows.Count > 0) {
|
||||
rv = rv ?? new BlueTable(out_rows.ElementAt(0).schema);
|
||||
}
|
||||
if (rv != null)
|
||||
rv.addRows(out_rows);
|
||||
rv.addRows(out_rows);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -62,24 +61,20 @@ namespace bts.BlueOrb {
|
||||
Func<List<IBlueRow>, List<IBlueRow>> evaluate_func)
|
||||
: this(main_stream, new DelNonIncGroupByEvaluator(groupby_cols_func, evaluate_func)) { }
|
||||
|
||||
public GroupByStream(ViewStream parent_str, string groupby_cols, string standard_group_by_text)
|
||||
: this(parent_str, groupby_cols, standard_group_by_text, String.Empty) { }
|
||||
public GroupByStream(ViewStream parent_str, string groupby_col, string standard_group_by_text)
|
||||
: this(parent_str, groupby_col, standard_group_by_text, String.Empty) { }
|
||||
|
||||
// this is the main constructor that does everything
|
||||
public GroupByStream(ViewStream parent_str, string groupby_cols, string standard_group_by_ops, string optional_sort_col) {
|
||||
public GroupByStream(ViewStream parent_str, string groupby_col, string standard_group_by_ops, string optional_sort_col) {
|
||||
MultiRowOpHelper std_group_by = MultiRowOpHelper.parse_ops(standard_group_by_ops);
|
||||
Func<string[]> groupby_cols_func = () => {
|
||||
if (String.IsNullOrEmpty(groupby_cols))
|
||||
return null;
|
||||
return groupby_cols.Split(',').Select(x => x.Trim()).ToArray();
|
||||
return String.IsNullOrEmpty(groupby_col) ? null : new string[] { groupby_col };
|
||||
};
|
||||
Func<List<IBlueRow>, List<IBlueRow>> evaluate_func = (group_rows) => {
|
||||
if (!String.IsNullOrEmpty(optional_sort_col))
|
||||
group_rows.Sort((r1, r2) => BlueDataUtility.compare_rows(r2, r1, optional_sort_col));
|
||||
// this si where the group by aggregation happens
|
||||
IBlueRow rv = MultiRowOpHelper.group_by_compute(group_rows, std_group_by);
|
||||
if (rv == null)
|
||||
return new List<IBlueRow>();
|
||||
return new IBlueRow[] { rv }.ToList();
|
||||
};
|
||||
ViewStream rs = new GroupByStream(parent_str, groupby_cols_func, evaluate_func);
|
||||
@@ -110,9 +105,6 @@ namespace bts.BlueOrb {
|
||||
/// reducing
|
||||
_timer.Restart();
|
||||
IBlueRowCollection total_state = _groupby_func.evaluate(grouped_rows);
|
||||
if (total_state == null)
|
||||
// mayeb returna n empty table ?
|
||||
return;
|
||||
_timer.Stop();
|
||||
var applyElapsedMs = _timer.ElapsedMilliseconds;
|
||||
_n_total_fires++;
|
||||
@@ -121,7 +113,9 @@ namespace bts.BlueOrb {
|
||||
Log.DataFlow.info(
|
||||
$"Time to evaluate {grouped_rows.Count} groups {_timer.ElapsedMilliseconds}ms, ratio {_n_expensive_fires}/{_n_total_fires}");
|
||||
}
|
||||
myFireEvent(new DataPacket(total_state, total_state, myLastValue == null ? new BlueTable(total_state.schema) : (myLastValue as DataPacket).newRows));
|
||||
// TODO,
|
||||
if (total_state != null)
|
||||
myFireEvent(new DataPacket(total_state, total_state, myLastValue == null ? new BlueTable(total_state.schema) : (myLastValue as DataPacket).newRows));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BCG;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
public interface INonIncJoinInlineMapper
|
||||
{
|
||||
IBlueTableSchema get_output_schema(IBlueTableSchema schema);
|
||||
|
||||
IBlueRowCollection map_rows(IBlueRowCollection rows);
|
||||
|
||||
event MapperChangeDelegate onMapperChange;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using mbts;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using BCG;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
internal class NonIncJoinBookkeeper : IDisposable {
|
||||
public Action on_new_data;
|
||||
private readonly NonIncJoinSpec _join_spec;
|
||||
private readonly int _join_position;
|
||||
private readonly int _start_index_in_output;
|
||||
private readonly BlueRowHasher _row_hasher;
|
||||
private readonly bool _is_left_most;
|
||||
private readonly bool _is_tag_along;
|
||||
private int _n_total_fires = 0, _n_expensive_fires = 0;
|
||||
|
||||
private IBlueTableSchema _schema = null;
|
||||
private IDictionary<int, IBlueRow> _row_map = new Dictionary<int, IBlueRow>();
|
||||
private List<Pair<int, IBlueRow>> _row_list = new List<Pair<int, IBlueRow>>();
|
||||
private IBlueRow _solitary_row = null;
|
||||
|
||||
private int[] _join_col_indices = null,
|
||||
_data_col_indices = null;
|
||||
|
||||
public NonIncJoinBookkeeper(NonIncJoinSpec the_join_spec, int join_position, int start_index_in_output, BlueRowHasher row_hasher) {
|
||||
_join_spec = the_join_spec;
|
||||
_join_position = join_position;
|
||||
_start_index_in_output = start_index_in_output;
|
||||
_row_hasher = row_hasher;
|
||||
_is_left_most = _join_position == 0;
|
||||
_is_tag_along = _join_spec.join_col_names.Length == 0;
|
||||
}
|
||||
|
||||
private bool _filled_missing_data = false;
|
||||
private void _fill_missing_data(DataPacket dp) {
|
||||
if (_filled_missing_data)
|
||||
return;
|
||||
Func<string[], bool> null_or_empty = (str_arr) => {
|
||||
if (str_arr == null || str_arr.Length == 0)
|
||||
return true;
|
||||
foreach (string s in str_arr) {
|
||||
if (!String.IsNullOrEmpty(s)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
Func<string[], string[]> remove_bad_cols = (col_names) => {
|
||||
HashSet<string> schema_col_map = new HashSet<string>(dp.schema.columnNames);
|
||||
List<string> cols_list = new List<string>(col_names);
|
||||
cols_list.RemoveWhere(c => !schema_col_map.Contains(c));
|
||||
return cols_list.ToArray();
|
||||
};
|
||||
if (null_or_empty(_join_spec.data_col_names)) {
|
||||
_join_spec.data_col_names = dp.schema.columnNames;
|
||||
}
|
||||
_join_spec.data_col_names = remove_bad_cols(_join_spec.data_col_names);
|
||||
if (null_or_empty(_join_spec.data_col_names)) {
|
||||
_join_spec.data_col_names = dp.schema.columnNames;
|
||||
}
|
||||
if (null_or_empty(_join_spec.projected_col_names)) {
|
||||
_join_spec.projected_col_names = _join_spec.data_col_names;
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
_join_spec.stream.onChange += _on_stream_cb;
|
||||
}
|
||||
|
||||
public void _on_stream_cb(object dp_obj) {
|
||||
//Log.Gen.info($"NonIncJoinBookkeeper._on_stream_cb dp_obj: {dp_obj}");
|
||||
var timer = Stopwatch.StartNew();
|
||||
DataPacket dp = (DataPacket)dp_obj;
|
||||
_fill_missing_data(dp);
|
||||
if (_schema == null) {
|
||||
_schema = dp.schema;
|
||||
_join_col_indices = BlueDataUtility.get_column_indices(_schema, _join_spec.join_col_names);
|
||||
_data_col_indices = BlueDataUtility.get_column_indices(_schema, _join_spec.data_col_names);
|
||||
}
|
||||
|
||||
if (_is_left_most) {
|
||||
_row_list.Clear();
|
||||
foreach (IBlueRow r in dp.newRows)
|
||||
_row_list.Add(new Pair<int, IBlueRow>(_row_hasher.get_hash(r, _join_col_indices), r));
|
||||
} else {
|
||||
if (_is_tag_along)
|
||||
_solitary_row = BlueDataUtility.extractRow(dp.newRows, 0);
|
||||
else {
|
||||
_row_map.Clear();
|
||||
foreach (IBlueRow r in dp.newRows)
|
||||
_row_map[_row_hasher.get_hash(r, _join_col_indices)] = r;
|
||||
}
|
||||
}
|
||||
timer.Stop();
|
||||
_n_total_fires++;
|
||||
if (timer.ElapsedMilliseconds >= 50) {
|
||||
_n_expensive_fires++;
|
||||
Log.Gen.info($"NonIncJoinBookkeepingData._on_stream_cb {dp.newRows.Count} rows {_join_col_indices.Length} "
|
||||
+ $"key cols {_join_position} join pos time {timer.Elapsed} ratio {_n_expensive_fires}/{_n_total_fires}");
|
||||
}
|
||||
if (on_new_data != null)
|
||||
on_new_data();
|
||||
}
|
||||
|
||||
public bool is_ready { get { return _schema != null; } }
|
||||
|
||||
public void constribute_cols_to_schema(List<ColumnInfo> cis) {
|
||||
for (int i = 0; i < _join_spec.data_col_names.Length; i++)
|
||||
cis.Add(new ColumnInfo(_join_spec.projected_col_names[i], cis.Count, _schema[_join_spec.data_col_names[i]].colType));
|
||||
}
|
||||
|
||||
public List<Pair<int, IBlueRow>> get_list() { return _row_list; }
|
||||
|
||||
public void copy_master_row_to_output_row(int row_index, object[] output_row) {
|
||||
IBlueRow this_row = _row_list[row_index].second;
|
||||
BlueDataUtility.copy_to_row(this_row, _data_col_indices, output_row, _start_index_in_output);
|
||||
}
|
||||
|
||||
public void copy_matching_row_to_output_row(int row_hash, object[] output_row) {
|
||||
if (_is_tag_along) {
|
||||
if (_solitary_row != null)
|
||||
BlueDataUtility.copy_to_row(_solitary_row, _data_col_indices, output_row, _start_index_in_output);
|
||||
else
|
||||
copy_dbnull_to_output_row(output_row);
|
||||
} else {
|
||||
IBlueRow this_row = null;
|
||||
if (_row_map.TryGetValue(row_hash, out this_row))
|
||||
BlueDataUtility.copy_to_row(this_row, _data_col_indices, output_row, _start_index_in_output);
|
||||
else
|
||||
copy_dbnull_to_output_row(output_row);
|
||||
}
|
||||
}
|
||||
|
||||
private void copy_dbnull_to_output_row(object[] output_row) {
|
||||
for (int i = 0; i < _data_col_indices.Length; i++)
|
||||
output_row[i + _start_index_in_output] = DBNull.Value;
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
public void Dispose() { _join_spec.stream.onChange -= _on_stream_cb; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using BCG;
|
||||
|
||||
using mbts;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
// this a collection of spec, theres no joining logic in here
|
||||
public class NonIncJoinSpec {
|
||||
public ViewStream stream;
|
||||
// join col names are the names on which the streams are joined (for equality),
|
||||
// data col names are the names in the original stream
|
||||
// projected col names are their new names, ie if its x:l_x, then x is in the
|
||||
// data_col_names and l_x in projected cols
|
||||
public string[] join_col_names, data_col_names, projected_col_names;
|
||||
|
||||
public NonIncJoinSpec() { }
|
||||
|
||||
public NonIncJoinSpec(ViewStream the_stream, string[] the_join_col_names, string[] the_data_col_names)
|
||||
: this(the_stream, the_join_col_names, the_data_col_names, the_data_col_names) { }
|
||||
|
||||
public NonIncJoinSpec(ViewStream the_stream, string[] the_join_col_names, string[] the_data_col_names, string[] the_projected_col_names) {
|
||||
stream = the_stream;
|
||||
join_col_names = the_join_col_names;
|
||||
data_col_names = the_data_col_names;
|
||||
projected_col_names = the_projected_col_names;
|
||||
}
|
||||
|
||||
public static NonIncJoinSpec[] from_triplet(params Triplet<ViewStream, string, string>[] join_specs) {
|
||||
List<NonIncJoinSpec> rv = new List<NonIncJoinSpec>();
|
||||
foreach (Triplet<ViewStream, string, string> r in join_specs) {
|
||||
string[] keys = String.IsNullOrEmpty(r.second) ? new string[] { } : r.second.Split(' ');
|
||||
string[] visible_cols = r.third.Split(' ');
|
||||
List<string> data_col_names = new List<string>(), mapped_col_names = new List<string>();
|
||||
foreach (string s in visible_cols) {
|
||||
string[] toks = s.Split(':');
|
||||
if (toks.Length == 1) {
|
||||
data_col_names.Add(toks[0]);
|
||||
mapped_col_names.Add(toks[0]);
|
||||
} else if (toks.Length == 2) {
|
||||
data_col_names.Add(toks[0]);
|
||||
mapped_col_names.Add(toks[1]);
|
||||
}
|
||||
}
|
||||
rv.Add(new NonIncJoinSpec(r.first, keys, data_col_names.ToArray(), mapped_col_names.ToArray()));
|
||||
}
|
||||
return rv.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
Func<string[], string> arr_txt = (a) => {
|
||||
string rv = "";
|
||||
foreach (string s in a) {
|
||||
rv += "{s} ";
|
||||
}
|
||||
rv = rv.Trim();
|
||||
return rv;
|
||||
};
|
||||
string rv = $"stream: {stream} join_col_names: {arr_txt(join_col_names)} data_col_names: {arr_txt(data_col_names)} projected_col_names: {arr_txt(projected_col_names)}";
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
using bts;
|
||||
|
||||
using mbts;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using BCG;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
[DataStreamUserRespresentation("JoinStream")]
|
||||
public class NonIncJoinStream : ViewStream, BCG.Utilities.General.IWorker {
|
||||
private readonly NonIncJoinSpec[] _join_specs;
|
||||
private readonly INonIncJoinInlineMapper _output_mapper;
|
||||
private readonly BlueRowHasher _row_hasher;
|
||||
private readonly TimeSpan _throttle_period;
|
||||
private readonly ViewStreamDatabase _vsd;
|
||||
|
||||
private List<NonIncJoinBookkeeper> _book_keeping_data = new List<NonIncJoinBookkeeper>();
|
||||
private IBlueTableSchema _output_schema = null;
|
||||
private DateTime _last_fire_time = DateTime.MinValue;
|
||||
private bool _is_dirty = false;
|
||||
|
||||
public NonIncJoinStream(ViewStream left, string left_join_cols, string left_proj,
|
||||
ViewStream right, string right_join_cols, string right_proj)
|
||||
: this(new Triplet<ViewStream, string, string>[]
|
||||
{
|
||||
new Triplet<ViewStream, string, string> (left, left_join_cols, left_proj),
|
||||
new Triplet<ViewStream, string, string> (right, right_join_cols, right_proj)
|
||||
}) { }
|
||||
|
||||
public NonIncJoinStream(params Triplet<ViewStream, string, string>[] join_specs)
|
||||
: this(NonIncJoinSpec.from_triplet(join_specs), null, 0) { }
|
||||
|
||||
public NonIncJoinStream(ViewStreamDatabase vsd, INonIncJoinInlineMapper output_mapper, int throttles_ms,
|
||||
params Triplet<ViewStream, string, string>[] join_specs)
|
||||
: this(vsd, NonIncJoinSpec.from_triplet(join_specs), output_mapper, throttles_ms) {
|
||||
}
|
||||
|
||||
public NonIncJoinStream(NonIncJoinSpec[] join_specs, INonIncJoinInlineMapper output_mapper, int throttles_ms = 0)
|
||||
: this(ViewStreamDatabase.instance, join_specs, output_mapper, throttles_ms) { }
|
||||
|
||||
public NonIncJoinStream(ViewStreamDatabase vsd, NonIncJoinSpec[] join_specs, INonIncJoinInlineMapper output_mapper, int throttles_ms = 0) {
|
||||
_join_specs = join_specs;
|
||||
_output_mapper = output_mapper;
|
||||
_row_hasher = new BlueRowHasher(_join_specs[0].join_col_names.Length);
|
||||
_throttle_period = throttles_ms == 0 ? TimeSpan.Zero : new TimeSpan(0, 0, 0, 0, throttles_ms);
|
||||
_vsd = vsd;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
int data_col_no = 1;
|
||||
for (int jp = 0; jp < _join_specs.Length; jp++) {
|
||||
NonIncJoinBookkeeper s = new NonIncJoinBookkeeper(_join_specs[jp], jp, data_col_no, _row_hasher);
|
||||
//Log.Gen.info($"NonIncJoinStream.myOnFirstSubscriber jp: {jp} spec: {_join_specs[jp]}");
|
||||
data_col_no += _join_specs[jp].data_col_names.Length;
|
||||
s.on_new_data += _stream_callback;
|
||||
_book_keeping_data.Add(s);
|
||||
}
|
||||
if (_output_mapper != null)
|
||||
_output_mapper.onMapperChange += _on_mapper_change;
|
||||
_vsd.addWorker(this);
|
||||
foreach (var bkd in _book_keeping_data)
|
||||
bkd.init();
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
|
||||
d.Dispose();
|
||||
if (_output_mapper != null)
|
||||
_output_mapper.onMapperChange -= _on_mapper_change;
|
||||
_vsd.removeWorker(this);
|
||||
}
|
||||
|
||||
private void _stream_callback() {
|
||||
//Log.Gen.info("NonIncJoinStream._stream_callback received callback");
|
||||
_is_dirty = true;
|
||||
doWork();
|
||||
}
|
||||
|
||||
private void _on_mapper_change() {
|
||||
_is_dirty = true;
|
||||
doWork();
|
||||
}
|
||||
|
||||
private bool _is_ready() {
|
||||
bool rv = true;
|
||||
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
|
||||
rv &= d.is_ready;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private void _construct_schema() {
|
||||
if (_output_schema == null) {
|
||||
List<ColumnInfo> cis = new List<ColumnInfo>(new ColumnInfo[] { new ColumnInfo("id", 0, typeof(int)) });
|
||||
foreach (NonIncJoinBookkeeper d in _book_keeping_data)
|
||||
d.constribute_cols_to_schema(cis);
|
||||
_output_schema = new BlueTableSchema("NonIncJoinStream", cis.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private int _n_total_fires = 0, _n_expensive_fires = 0;
|
||||
private void _form_and_fire() {
|
||||
//Log.Gen.info($"NonIncJoinStream._form_and_fire _is_ready(): {_is_ready()}");
|
||||
if (_is_ready()) {
|
||||
_construct_schema();
|
||||
var timer = Stopwatch.StartNew();
|
||||
IList<Pair<int, IBlueRow>> left_row_list = _book_keeping_data[0].get_list();
|
||||
List<object[]> output_rows = new List<object[]>();
|
||||
|
||||
for (int i = 0; i < left_row_list.Count; i++) {
|
||||
object[] or = new object[_output_schema.columnInfo.Length];
|
||||
or[0] = i;
|
||||
output_rows.Add(or);
|
||||
}
|
||||
|
||||
for (int ji = 0; ji < _book_keeping_data.Count; ji++) {
|
||||
NonIncJoinBookkeeper bk_data = _book_keeping_data[ji];
|
||||
for (int i = 0; i < left_row_list.Count; i++) {
|
||||
if (ji == 0)
|
||||
bk_data.copy_master_row_to_output_row(i, output_rows[i]);
|
||||
else
|
||||
bk_data.copy_matching_row_to_output_row(left_row_list[i].first, output_rows[i]);
|
||||
}
|
||||
}
|
||||
IBlueRowCollection dp_output_rows = _apply_map(new SequentialIDBlueTable(_output_schema, output_rows));
|
||||
timer.Stop();
|
||||
_n_total_fires++;
|
||||
//if (timer.ElapsedMilliseconds >= 250) {
|
||||
_n_expensive_fires++;
|
||||
//string log_msg = $"Join and map time for {_book_keeping_data.Count} "
|
||||
// + $"tables {timer.Elapsed.TotalMilliseconds} msecs, ratio {_n_expensive_fires}/{_n_total_fires}";
|
||||
//Log.Gen.info(log_msg);
|
||||
//}
|
||||
var dp_out = BlueDataUtility.build_dp_inc(dp_output_rows, myLastValue as DataPacket, true);
|
||||
myFireEvent(dp_out);
|
||||
//myFireEvent(new DataPacket(dp_output_rows, dp_output_rows, myLastValue == null ? new BlueTable(_output_schema) : (myLastValue as DataPacket).newRows));
|
||||
}
|
||||
}
|
||||
|
||||
private IBlueRowCollection _apply_map(IBlueRowCollection unmapped_rows) {
|
||||
if (_output_mapper != null) {
|
||||
IBlueRowCollection output_rows;
|
||||
var timer = Stopwatch.StartNew();
|
||||
output_rows = _output_mapper.map_rows(unmapped_rows);
|
||||
timer.Stop();
|
||||
if (timer.ElapsedMilliseconds >= 50) {
|
||||
Log.Gen.info($"Time to map {unmapped_rows.Count} rows into {output_rows.Count} rows {timer.Elapsed}");
|
||||
}
|
||||
return output_rows;
|
||||
} else {
|
||||
return unmapped_rows;
|
||||
}
|
||||
}
|
||||
|
||||
public void doWork() {
|
||||
//Log.Gen.info($"NonIncJoinStream.doWork _last_fire_time: {_last_fire_time} _is_dirty: {_is_dirty}");
|
||||
if (DateTime.Now - _last_fire_time >= _throttle_period && _is_dirty) {
|
||||
_is_dirty = false;
|
||||
_last_fire_time = DateTime.Now;
|
||||
_form_and_fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
using RowHash = System.Int32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using System.Data.Entity.Core.Mapping;
|
||||
|
||||
[DataStreamUserRespresentation("JoinStream")]
|
||||
public class SimpleJoinStream : ViewStream {
|
||||
public class JoinBookkeepingData {
|
||||
// initialized in cons
|
||||
private readonly List<string> _join_col_names;
|
||||
private readonly bool _is_left;
|
||||
private readonly BlueRowHasher _hasher;
|
||||
// initialized on first udpate
|
||||
private IBlueTableSchema _schema;
|
||||
private int[] _join_cols;
|
||||
private IDictionary<RowHash, List<IBlueRow>> _hash_row_map = new Dictionary<RowHash, List<IBlueRow>>();
|
||||
|
||||
public JoinBookkeepingData(ViewStream vs, List<string> join_cols, bool is_left, BlueRowHasher row_hasher) {
|
||||
_join_col_names = join_cols.Where(c => !String.IsNullOrEmpty(c)).ToList();
|
||||
_is_left = is_left;
|
||||
_hasher = row_hasher;
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema => _schema;
|
||||
|
||||
public IDictionary<RowHash, List<IBlueRow>> rows => _hash_row_map;
|
||||
|
||||
public List<IBlueRow> get_matching_rows(int hash) {
|
||||
List<IBlueRow> rv = null;
|
||||
_hash_row_map.TryGetValue(hash, out rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
private RowHash _get_hash(IBlueRow r) {
|
||||
if (_join_cols == null || _join_cols.Length == 0) {
|
||||
return 0;
|
||||
}
|
||||
return _hasher.get_hash(r, _join_cols);
|
||||
}
|
||||
|
||||
public void update_data(DataPacket dp) {
|
||||
if (!ready) {
|
||||
_schema = dp.newRows.schema;
|
||||
_join_cols = _join_col_names.Count == 0 ? new int[] { } : _join_col_names.Select(n => dp.schema[n].colNo).ToArray();
|
||||
}
|
||||
_hash_row_map.Clear();
|
||||
foreach (IBlueRow r in dp.newRows) {
|
||||
int hash = _get_hash(r);
|
||||
List<IBlueRow> hash_rows = null;
|
||||
if (!_hash_row_map.TryGetValue(hash, out hash_rows)) {
|
||||
hash_rows = new List<IBlueRow>();
|
||||
_hash_row_map.Add(hash, hash_rows);
|
||||
}
|
||||
hash_rows.Add(r);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ready {
|
||||
get {
|
||||
return _schema != null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private ViewStream _ls, _rs;
|
||||
private JoinBookkeepingData _ldata, _rdata;
|
||||
private ViewStreamDatabase _vsd;
|
||||
private IBlueTableSchema _schema = null;
|
||||
|
||||
public SimpleJoinStream(ViewStream ls, string ljc, ViewStream rs, string rjc) :
|
||||
this(ViewStreamDatabase.instance, ls, ljc, rs, rjc) { }
|
||||
|
||||
public SimpleJoinStream(ViewStreamDatabase vsd, ViewStream ls, string ljc, ViewStream rs, string rjc) {
|
||||
_ls = ls;
|
||||
_rs = rs;
|
||||
List<string> lj_col_list = ljc.Split(',').Where(x => !String.IsNullOrEmpty(x)).ToList();
|
||||
List<string> rj_col_list = rjc.Split(',').Where(x => !String.IsNullOrEmpty(x)).ToList();
|
||||
Log.assert(lj_col_list.Count == rj_col_list.Count);
|
||||
int n_cols = lj_col_list.Count;
|
||||
BlueRowHasher hasher = new BlueRowHasher(n_cols);
|
||||
_ldata = new JoinBookkeepingData(ls, lj_col_list, true, hasher);
|
||||
_rdata = new JoinBookkeepingData(rs, rj_col_list, false, hasher);
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_ls.onChange += _ls_onchange;
|
||||
_rs.onChange += _rs_onchange;
|
||||
}
|
||||
|
||||
private void _ls_onchange(object dp_obj) {
|
||||
DataPacket dp = dp_obj as DataPacket;
|
||||
_ldata.update_data(dp);
|
||||
_form_and_fire();
|
||||
}
|
||||
|
||||
private void _rs_onchange(object dp_obj) {
|
||||
DataPacket dp = dp_obj as DataPacket;
|
||||
_rdata.update_data(dp);
|
||||
_form_and_fire();
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
_ls.onChange -= _ls_onchange;
|
||||
_rs.onChange -= _rs_onchange;
|
||||
}
|
||||
|
||||
private void _build_schema() {
|
||||
if (_schema != null)
|
||||
return;
|
||||
List<ColumnInfo> cis = new List<ColumnInfo>();
|
||||
cis.Add(new ColumnInfo("id", 0, TypeCode.Int32));
|
||||
foreach (ColumnInfo ci in _ldata.schema.columnInfo) {
|
||||
string col_name = _rdata.schema.contains_column(ci.colName) ? $"left_{ci.colName}" : ci.colName;
|
||||
cis.Add(new ColumnInfo(col_name, cis.Count, ci.colType));
|
||||
}
|
||||
foreach (ColumnInfo ci in _rdata.schema.columnInfo) {
|
||||
string col_name = _ldata.schema.contains_column(ci.colName) ? $"right_{ci.colName}" : ci.colName;
|
||||
cis.Add(new ColumnInfo(col_name, cis.Count, ci.colType));
|
||||
}
|
||||
_schema = new BlueTableSchema($"{_ldata.schema.tableName}_join_{_rdata.schema.tableName}", cis.ToArray());
|
||||
}
|
||||
|
||||
private void _form_and_fire() {
|
||||
if (!_ldata.ready || !_rdata.ready)
|
||||
return;
|
||||
_build_schema();
|
||||
List<object[]> res_rows = new List<object[]>();
|
||||
|
||||
Action<object[], IBlueRow, bool> copy_row = (rval, r, is_left) => {
|
||||
int offset = 1;
|
||||
JoinBookkeepingData sdata = _ldata;
|
||||
if (is_left) {
|
||||
offset = 1;
|
||||
sdata = _ldata;
|
||||
} else {
|
||||
sdata = _rdata;
|
||||
offset = 1 + _ldata.schema.columnInfo.Length;
|
||||
}
|
||||
for (int i = 0; i < sdata.schema.columnInfo.Length; i++) {
|
||||
rval[offset + i] = r[i];
|
||||
}
|
||||
};
|
||||
Func<int, IBlueRow, object[]> build_row_array = (id, l_row) => {
|
||||
object[] rv = new object[_schema.columnNames.Length];
|
||||
for (int i = 0; i < _schema.columnNames.Length; i++) {
|
||||
rv[i] = DBNull.Value;
|
||||
}
|
||||
rv[0] = id;
|
||||
copy_row(rv, l_row, true);
|
||||
return rv;
|
||||
};
|
||||
// this is where the join happens
|
||||
foreach (var kv in _ldata.rows) {
|
||||
RowHash hash = kv.Key;
|
||||
List<IBlueRow> l_rows = kv.Value;
|
||||
List<IBlueRow> r_rows = _rdata.get_matching_rows(hash);
|
||||
|
||||
foreach (IBlueRow lr in l_rows) {
|
||||
if (r_rows != null) {
|
||||
foreach (IBlueRow r in r_rows) {
|
||||
object[] rowvals = build_row_array(res_rows.Count, lr);
|
||||
copy_row(rowvals, r, false);
|
||||
res_rows.Add(rowvals);
|
||||
}
|
||||
} else {
|
||||
object[] rowvals = build_row_array(res_rows.Count, lr);
|
||||
res_rows.Add(rowvals);
|
||||
}
|
||||
}
|
||||
}
|
||||
BlueTable rv = new BlueTable(_schema);
|
||||
foreach (object[] rval in res_rows) {
|
||||
rv.addRow(new BlueRow(_schema, rval));
|
||||
}
|
||||
var dp = BlueDataUtility.build_dp(rv, myLastValue as DataPacket);
|
||||
myFireEvent(dp);
|
||||
}
|
||||
}
|
||||
|
||||
[DataStreamUserRespresentation("FullJoinStream")]
|
||||
public class FullJoinStream : ViewStream {
|
||||
public FullJoinStream(ViewStream l_str, string ljcs, ViewStream r_str, string rjcs) {
|
||||
ViewStream js = new SimpleJoinStream(l_str, ljcs, r_str, rjcs);
|
||||
ViewStream rs = new bts.BlueOrb.FilterStream(js, r => !DBNull.Value.Equals(r["right_id"]));
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,20 +43,20 @@ namespace bts.BlueOrb {
|
||||
_last_fire_time = DateTime.Now;
|
||||
IBlueRow nr = new BlueRow(_schema, _id++, _last_fire_time,
|
||||
_last_fire_time.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
_table = _table.Add(nr);
|
||||
_table.add_row(nr);
|
||||
var dp = BlueDataUtility.build_dp_inc(_table, myLastValue as DataPacket);
|
||||
myFireEvent(dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal class MSecondStream : TimeUnitStream {
|
||||
public class MSecondStream : TimeUnitStream {
|
||||
public MSecondStream(int intervalInms, int size)
|
||||
: base(DateTime.Now, new TimeSpan(0, 0, 0, 0, intervalInms), size, ViewStreamDatabase.instance) { }
|
||||
|
||||
protected override DateTime myRoundTime(DateTime dt) { return dt; }
|
||||
}
|
||||
|
||||
internal class DisplayableMillisecondStream : ViewStream, IStreamMapper {
|
||||
public class DisplayableMillisecondStream : ViewStream, IStreamMapper {
|
||||
private IBlueTableSchema mySchema = new BlueTableSchema("ms",
|
||||
new ColumnInfo("id", 0, typeof(int)),
|
||||
new ColumnInfo("time", 1, typeof(string)));
|
||||
|
||||
@@ -20,14 +20,13 @@ namespace bts.BlueOrb {
|
||||
Sum,
|
||||
EdgeDiff,
|
||||
EdgeDiffPercentage,
|
||||
//IsEdgeDiff,
|
||||
}
|
||||
public class MultiRowOpHelper {
|
||||
// input + op
|
||||
public readonly List<Tuple<string, MultiRowOp>> operations;
|
||||
|
||||
public static MultiRowOpHelper parse_ops(string text) {
|
||||
// text is inp_col: op, inp_col: op, inp_col:op
|
||||
// ex: "open:First, close:Last, high:Max, low:Min, volume:Sum")
|
||||
List<Tuple<string, MultiRowOp>> rv = new List<Tuple<string, MultiRowOp>>();
|
||||
string[] calcs = text.Split(',');
|
||||
foreach (string c in calcs) {
|
||||
@@ -72,35 +71,6 @@ namespace bts.BlueOrb {
|
||||
return or;
|
||||
}
|
||||
|
||||
// aggregates multiple rows into one, used by MultiRowRollingMathStream
|
||||
public static IBlueRow group_by_compute(List<IBlueRow> rows, int start_idx, int n_rows, MultiRowOpHelper parameters) {
|
||||
if (rows.Count() == 0) {
|
||||
return null;
|
||||
}
|
||||
IBlueRow ir = rows.ElementAt(start_idx);
|
||||
IBlueTableSchema in_schema = ir.schema;
|
||||
IBlueTableSchema out_schema = in_schema;
|
||||
// out_col vs inp_cal + type
|
||||
IDictionary<string, Tuple<string, MultiRowOp>> out_col_map =
|
||||
new Dictionary<string, Tuple<string, MultiRowOp>>();
|
||||
foreach (var t in parameters.operations) {
|
||||
string out_col_name = $"{t.Item1}_{t.Item2}".ToLower();
|
||||
out_schema = out_schema.add_column(TypeCode.Double, out_col_name);
|
||||
out_col_map[out_col_name] = t;
|
||||
}
|
||||
MutableBlueRow or = new MutableBlueRow(out_schema, ir);
|
||||
foreach (var kv in out_col_map) {
|
||||
string out_col_name = kv.Key;
|
||||
string in_col_name = kv.Value.Item1;
|
||||
MultiRowOp op = kv.Value.Item2;
|
||||
IEnumerable<double> col_vals = BlueDataUtility.get_colvalues<double>(rows, start_idx, n_rows, in_col_name);
|
||||
double comp_res = compute_op(col_vals, op);
|
||||
or.setValue(out_col_name, comp_res);
|
||||
or.setValue("id", ir["id"]);
|
||||
}
|
||||
return or;
|
||||
}
|
||||
|
||||
// rolling_rows are the rolling window of rows. the 0th row is the one thats gettin
|
||||
// calculated. rows 1 - n-1 are its window rows. the schema is based on the operations.
|
||||
|
||||
@@ -137,27 +107,15 @@ namespace bts.BlueOrb {
|
||||
case MultiRowOp.Min:
|
||||
return col_vals.Min<double>();
|
||||
case MultiRowOp.Mean:
|
||||
return MathNet.Numerics.Statistics.Statistics.Mean(col_vals);
|
||||
return col_vals.Sum() / col_vals.Count();
|
||||
case MultiRowOp.Sum:
|
||||
return col_vals.Sum();
|
||||
case MultiRowOp.Median:
|
||||
return MathNet.Numerics.Statistics.Statistics.Median(col_vals);
|
||||
//case MultiRowOp.Mode:
|
||||
// return MathNet.Numerics.Statistics.Statistics.(col_vals);
|
||||
case MultiRowOp.First:
|
||||
return col_vals.First();
|
||||
case MultiRowOp.Last:
|
||||
return col_vals.Last();
|
||||
case MultiRowOp.StdDev:
|
||||
return MathNet.Numerics.Statistics.Statistics.StandardDeviation(col_vals);
|
||||
case MultiRowOp.EdgeDiff:
|
||||
return col_vals.First() - col_vals.Last();
|
||||
case MultiRowOp.EdgeDiffPercentage: {
|
||||
double first = col_vals.First();
|
||||
double last = col_vals.Last();
|
||||
return ((first - last) / last) * 100.0;
|
||||
return col_vals.First() - col_vals.Last();
|
||||
}
|
||||
default:
|
||||
// TODO
|
||||
Log.assert(false);
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
[DataStreamUserRespresentation("MultiRowRollingMathStream")]
|
||||
public class MultiRowRollingMathStream : ViewStream {
|
||||
private ViewStream _sorted_parent_str;
|
||||
private MultiRowOpHelper _op;
|
||||
private int _rolling_window_sz;
|
||||
public MultiRowRollingMathStream(ViewStream parent_str, string op_txt, string sort_exp, int rolling_window_sz) {
|
||||
_sorted_parent_str = new SortStream(parent_str, sort_exp);
|
||||
_op = MultiRowOpHelper.parse_ops(op_txt);
|
||||
_rolling_window_sz = rolling_window_sz;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_sorted_parent_str.onChange += _parent_str_onchange;
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
_sorted_parent_str.onChange -= _parent_str_onchange;
|
||||
}
|
||||
|
||||
private void _parent_str_onchange(object dp_obj) {
|
||||
DataPacket dp = dp_obj as DataPacket;
|
||||
var rows = dp.newRows.to_list();
|
||||
BlueTable out_table = null;
|
||||
for (int i = 0; i < rows.Count; i++) {
|
||||
var out_r = MultiRowOpHelper.group_by_compute(rows, i, _rolling_window_sz, _op);
|
||||
if (out_table == null)
|
||||
out_table = new BlueTable(out_r.schema);
|
||||
out_table.addRow(out_r);
|
||||
}
|
||||
var dp_out = BlueDataUtility.build_dp_inc(out_table, myLastValue as DataPacket, true);
|
||||
myFireEvent(dp_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public interface IParquetColumnReader : IDisposable {
|
||||
IList<object?> Read();
|
||||
IList<object?> Read(int? start, int? stop);
|
||||
}
|
||||
|
||||
public interface IParquetColumnReader<TLogical, TPhysical> : IParquetColumnReader {
|
||||
new IList<TLogical?> Read();
|
||||
new IList<TLogical?> Read(int? start, int? stop);
|
||||
|
||||
IList<object?> IParquetColumnReader.Read() =>
|
||||
Read().WrapSelector(v => (object?)v, null);
|
||||
|
||||
IList<object?> IParquetColumnReader.Read(int? start, int? stop) =>
|
||||
Read(start, stop).WrapSelector(v => (object?)v, null);
|
||||
}
|
||||
|
||||
public interface IParquetColumnReader<T> : IParquetColumnReader<T, T> {
|
||||
new IList<T?> Read();
|
||||
|
||||
IList<object?> IParquetColumnReader.Read() =>
|
||||
Read().WrapSelector(v => (object?)v, null);
|
||||
}
|
||||
@@ -1,507 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public static class ParquetAdapter {
|
||||
public static IParquetColumnReader GetColumnReader(this RowGroupReader rowGroupReader, int index, Type? colType = null) {
|
||||
int rowCount = checked((int)rowGroupReader.MetaData.NumRows);
|
||||
var colReader = rowGroupReader.Column(index);
|
||||
return getColumnReader(colReader, rowCount, colType: colType);
|
||||
}
|
||||
|
||||
public static IList<object?>[] ReadColumns(this ParquetFileReader fileReader) {
|
||||
var schema = fileReader.FileMetaData.Schema.ToBlueSchema("parquetReader");
|
||||
var colInfos = schema.columnInfo;
|
||||
var colTypes = Array.ConvertAll(colInfos, c => c.colType);
|
||||
var colValues = new IList<object?>[fileReader.FileMetaData.NumColumns];
|
||||
int rowCount = checked((int)fileReader.FileMetaData.NumRows);
|
||||
for (int i = 0; i < colValues.Length; i++) {
|
||||
colValues[i] = new List<object?>(rowCount);
|
||||
}
|
||||
int rowGroupCount = fileReader.FileMetaData.NumRowGroups;
|
||||
for (int rowGroup = 0; rowGroup < rowGroupCount; ++rowGroup) {
|
||||
using var rowGroupReader = fileReader.RowGroup(rowGroup);
|
||||
rowGroupReader.ReadColumnsTo(ref colValues, colTypes);
|
||||
}
|
||||
return colValues;
|
||||
}
|
||||
|
||||
public static IList<object?>[] ReadColumns(this ParquetFileReader fileReader, int? start, int? stop) {
|
||||
if (!start.HasValue && !stop.HasValue) {
|
||||
return ReadColumns(fileReader);
|
||||
}
|
||||
var schema = fileReader.FileMetaData.ToBlueSchema("parquetReader");
|
||||
var colInfos = schema.columnInfo;
|
||||
var colTypes = Array.ConvertAll(colInfos, c => c.colType);
|
||||
var colValues = new IList<object?>[fileReader.FileMetaData.NumColumns];
|
||||
int rowCount = checked((int)fileReader.FileMetaData.NumRows);
|
||||
start ??= 0;
|
||||
stop ??= rowCount;
|
||||
var sliceLength = stop.Value - start.Value;
|
||||
for (int i = 0; i < colValues.Length; i++) {
|
||||
colValues[i] = new List<object?>(sliceLength);
|
||||
}
|
||||
int numRowGroups = fileReader.FileMetaData.NumRowGroups;
|
||||
int? numRowsPerGroup = null;
|
||||
int rowIdx = 0;
|
||||
for (int rowGroup = 0; rowGroup < numRowGroups; ++rowGroup) {
|
||||
if (stop.Value <= rowIdx) {
|
||||
break;
|
||||
}
|
||||
using var rowGroupReader = fileReader.RowGroup(rowGroup);
|
||||
int numRowsInGroup = checked((int)rowGroupReader.MetaData.NumRows);
|
||||
numRowsPerGroup ??= numRowsInGroup;
|
||||
if (rowGroup < numRowGroups - 1) {
|
||||
Log.assert(numRowsInGroup == numRowsPerGroup.Value);
|
||||
} else {
|
||||
Log.assert(numRowsInGroup <= numRowsPerGroup.Value);
|
||||
}
|
||||
int startIdx = start.Value - rowIdx;
|
||||
int stopIdx = stop.Value - rowIdx;
|
||||
rowIdx += numRowsInGroup;
|
||||
if (startIdx >= numRowsInGroup) {
|
||||
continue;
|
||||
}
|
||||
startIdx = Math.Max(0, startIdx);
|
||||
stopIdx = Math.Min(stopIdx, numRowsInGroup);
|
||||
int n = rowGroupReader.ReadColumnsTo(ref colValues, colTypes, startIdx, stopIdx);
|
||||
Log.assert(n == (stopIdx - startIdx));
|
||||
}
|
||||
return colValues;
|
||||
}
|
||||
|
||||
public static int ReadColumnsTo(this RowGroupReader rowGroupReader, ref IList<object?>[] columnValues, Type[] colTypes) {
|
||||
int rowCount = checked((int)rowGroupReader.MetaData.NumRows);
|
||||
for (int colIdx = rowGroupReader.MetaData.NumColumns - 1; colIdx > -1; colIdx--) {
|
||||
using var colReader = rowGroupReader.GetColumnReader(colIdx, colTypes[colIdx]);
|
||||
columnValues[colIdx].AddRange(colReader.Read());
|
||||
}
|
||||
return rowCount;
|
||||
}
|
||||
|
||||
public static int ReadColumnsTo(this RowGroupReader rowGroupReader, ref IList<object?>[] columnValues, Type[] colTypes, int? start, int? stop) {
|
||||
if (!start.HasValue && !stop.HasValue) {
|
||||
return ReadColumnsTo(rowGroupReader, ref columnValues, colTypes);
|
||||
}
|
||||
int numRows = checked((int)rowGroupReader.MetaData.NumRows);
|
||||
if (start.HasValue && start.Value >= numRows) {
|
||||
return 0;
|
||||
}
|
||||
int? readRowCount = null;
|
||||
for (int colIdx = rowGroupReader.MetaData.NumColumns - 1; colIdx > -1; colIdx--) {
|
||||
using var colReader = rowGroupReader.GetColumnReader(colIdx, colTypes[colIdx]);
|
||||
var colVals = colReader.Read(start, stop);
|
||||
readRowCount ??= colVals.Count;
|
||||
Log.assert(readRowCount == colVals.Count);
|
||||
columnValues[colIdx].AddRange(colVals);
|
||||
}
|
||||
return readRowCount ?? throw new ArgumentException("Row group has no columns", nameof(rowGroupReader));
|
||||
}
|
||||
|
||||
static IParquetColumnReader getColumnReader(ColumnReader reader, int bufferSize = 4096, Type? colType = null) {
|
||||
var desc = reader.ColumnDescriptor;
|
||||
var logicalType = desc.LogicalType;
|
||||
return logicalType.Type switch {
|
||||
LogicalTypeEnum.Int => IntReader(),
|
||||
LogicalTypeEnum.String => new ParquetColumnReader<string?>(reader, bufferSize),
|
||||
LogicalTypeEnum.Date => new ParquetColumnReader<DateTime?>(reader, bufferSize),
|
||||
LogicalTypeEnum.Decimal => DecimalReader(),
|
||||
LogicalTypeEnum.Timestamp => TimestampReader(),
|
||||
LogicalTypeEnum.None => DefaultReader(),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
IParquetColumnReader DefaultReader() {
|
||||
return desc.PhysicalType switch {
|
||||
PhysicalType.Boolean => new ParquetColumnReader<bool?>(reader, bufferSize),
|
||||
PhysicalType.Int32 => new ParquetColumnReader<int?>(reader, bufferSize),
|
||||
PhysicalType.Int64 => new ParquetColumnReader<long?>(reader, bufferSize),
|
||||
PhysicalType.Float => new ParquetColumnReader<float?>(reader, bufferSize),
|
||||
PhysicalType.Double => new ParquetColumnReader<double?>(reader, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
IParquetColumnReader TimestampReader() {
|
||||
var tlt = ExceptionAssert.of_type<TimestampLogicalType>(logicalType);
|
||||
return new ParquetColumnReader<DateTimeNanos?, DateTime?>(reader, dtn => dtn?.DateTime, bufferSize);
|
||||
}
|
||||
|
||||
IParquetColumnReader IntReader() {
|
||||
var ilt = ExceptionAssert.of_type<IntLogicalType>(logicalType);
|
||||
if (!ilt.IsSigned) {
|
||||
if (colType is null) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<byte?>(reader, bufferSize),
|
||||
16 => new ParquetColumnReader<ushort?>(reader, bufferSize),
|
||||
32 => new ParquetColumnReader<uint?>(reader, bufferSize),
|
||||
64 => new ParquetColumnReader<ulong?>(reader, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(byte)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<byte?>(reader, bufferSize),
|
||||
16 => new ParquetColumnReader<ushort?, byte?>(reader, v => v.HasValue ? checked((byte)v.Value) : null, bufferSize),
|
||||
32 => new ParquetColumnReader<uint?, ushort?>(reader, v => v.HasValue ? checked((byte)v.Value) : null, bufferSize),
|
||||
64 => new ParquetColumnReader<ulong?, ushort?>(reader, v => v.HasValue ? checked((byte)v.Value) : null, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(ushort)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<byte?, ushort?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
16 => new ParquetColumnReader<ushort?>(reader, bufferSize),
|
||||
32 => new ParquetColumnReader<uint?, ushort?>(reader, v => v.HasValue ? checked((ushort)v.Value) : null, bufferSize),
|
||||
64 => new ParquetColumnReader<ulong?, ushort?>(reader, v => v.HasValue ? checked((ushort)v.Value) : null, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(uint)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<byte?, uint?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
16 => new ParquetColumnReader<ushort?, uint?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
32 => new ParquetColumnReader<uint?>(reader, bufferSize),
|
||||
64 => new ParquetColumnReader<ulong?, uint?>(reader, v => v.HasValue ? checked((uint)v.Value) : null, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(ulong)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<byte?, ulong?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
16 => new ParquetColumnReader<ushort?, ulong?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
32 => new ParquetColumnReader<uint?, ulong?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
64 => new ParquetColumnReader<ulong?>(reader, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
throw new NotImplementedException($"Expected signed int column type, but got {colType}");
|
||||
} else {
|
||||
if (colType is null) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<sbyte?>(reader, bufferSize),
|
||||
16 => new ParquetColumnReader<short?>(reader, bufferSize),
|
||||
32 => new ParquetColumnReader<int?>(reader, bufferSize),
|
||||
64 => new ParquetColumnReader<long?>(reader, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(sbyte)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<sbyte?>(reader, bufferSize),
|
||||
16 => new ParquetColumnReader<short?, sbyte?>(reader, v => v.HasValue ? checked((sbyte)v.Value) : null, bufferSize),
|
||||
32 => new ParquetColumnReader<int?, sbyte?>(reader, v => v.HasValue ? checked((sbyte)v.Value) : null, bufferSize),
|
||||
64 => new ParquetColumnReader<long?, sbyte?>(reader, v => v.HasValue ? checked((sbyte)v.Value) : null, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(short)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<char?, short?>(reader, v => v.HasValue ? checked((short)v.Value) : null, bufferSize),
|
||||
16 => new ParquetColumnReader<short?>(reader, bufferSize),
|
||||
32 => new ParquetColumnReader<int?, short?>(reader, v => v.HasValue ? checked((short)v.Value) : null, bufferSize),
|
||||
64 => new ParquetColumnReader<long?, short?>(reader, v => v.HasValue ? checked((short)v.Value) : null, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(int)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<char?, int?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
16 => new ParquetColumnReader<short?, int?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
32 => new ParquetColumnReader<int?>(reader, bufferSize),
|
||||
64 => new ParquetColumnReader<long?, int?>(reader, v => v.HasValue ? checked((int)v.Value) : null, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
} else if (colType == typeof(long)) {
|
||||
return ilt.BitWidth switch {
|
||||
8 => new ParquetColumnReader<char?, long?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
16 => new ParquetColumnReader<short?, long?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
32 => new ParquetColumnReader<int?, long?>(reader, v => v.HasValue ? v.Value : null, bufferSize),
|
||||
64 => new ParquetColumnReader<long?>(reader, bufferSize),
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
throw new NotImplementedException($"Expected unsigned int column type, but got {colType}");
|
||||
}
|
||||
}
|
||||
|
||||
IParquetColumnReader DecimalReader() {
|
||||
var dlt = ExceptionAssert.of_type<DecimalLogicalType>(logicalType);
|
||||
return new ParquetColumnReader<double?>(reader, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static IColumnWriter GetColumnWriter(TypeCode typeCode, ColumnWriter writer, int bufferSize = 4096) {
|
||||
return typeCode switch {
|
||||
TypeCode.Boolean => new ColumnWriter<bool?>(writer, bufferSize),
|
||||
TypeCode.SByte => new ColumnWriter<sbyte?>(writer, bufferSize, GetInt8Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.Int16 => new ColumnWriter<short?>(writer, bufferSize, GetInt16Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.Int32 => new ColumnWriter<int?>(writer, bufferSize, GetInt32Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.Int64 => new ColumnWriter<long?>(writer, bufferSize, GetInt64Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.Byte => new ColumnWriter<byte?>(writer, bufferSize, GetUInt8Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.UInt16 => new ColumnWriter<ushort?>(writer, bufferSize, GetUInt16Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.UInt32 => new ColumnWriter<uint?>(writer, bufferSize, GetUInt32Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.UInt64 => new ColumnWriter<ulong?>(writer, bufferSize, GetUInt64Converter((IntLogicalType)writer.ColumnDescriptor.LogicalType)),
|
||||
TypeCode.Single => new ColumnWriter<float?>(writer, bufferSize),
|
||||
TypeCode.Double => new ColumnWriter<double?>(writer, bufferSize),
|
||||
TypeCode.DateTime => new ColumnWriter<DateTimeNanos?>(writer, bufferSize, ConvertDateTimeObj),
|
||||
TypeCode.String => new ColumnWriter<string?>(writer, bufferSize),
|
||||
_ => throw new NotSupportedException($"Unsupported column TypeCode {typeCode}"),
|
||||
};
|
||||
|
||||
static DateTimeNanos? ConvertDateTimeObj(object? obj) {
|
||||
if (obj is DateTime dt) {
|
||||
return new(dt);
|
||||
}
|
||||
if (obj is DateTimeNanos dtn) {
|
||||
return dtn;
|
||||
}
|
||||
throw new InvalidCastException($"Unable to convert object of type {obj?.GetType()} to DateTimeNanos");
|
||||
}
|
||||
}
|
||||
|
||||
public static Func<object?, sbyte?> GetInt8Converter(IntLogicalType logicalType) =>
|
||||
GetInt8Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, sbyte?> GetInt8Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj as sbyte?,
|
||||
16 => obj => obj is short v ? checked((sbyte)v) : null,
|
||||
32 => obj => obj is int v ? checked((sbyte)v) : null,
|
||||
64 => obj => obj is long v ? checked((sbyte)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? checked((sbyte)v) : null,
|
||||
16 => obj => obj is ushort v ? checked((sbyte)v) : null,
|
||||
32 => obj => obj is uint v ? checked((sbyte)v) : null,
|
||||
64 => obj => obj is ulong v ? checked((sbyte)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, short?> GetInt16Converter(IntLogicalType logicalType) =>
|
||||
GetInt16Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, short?> GetInt16Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? v : null,
|
||||
16 => obj => obj as short?,
|
||||
32 => obj => obj is int v ? checked((short)v) : null,
|
||||
64 => obj => obj is long v ? checked((short)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? v : null,
|
||||
16 => obj => obj is ushort v ? checked((short)v) : null,
|
||||
32 => obj => obj is uint v ? checked((short)v) : null,
|
||||
64 => obj => obj is ulong v ? checked((short)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, int?> GetInt32Converter(IntLogicalType logicalType) =>
|
||||
GetInt32Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, int?> GetInt32Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? v : null,
|
||||
16 => obj => obj is short v ? v : null,
|
||||
32 => obj => obj as int?,
|
||||
64 => obj => obj is long v ? checked((int)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? v : null,
|
||||
16 => obj => obj is ushort v ? v : null,
|
||||
32 => obj => obj is uint v ? checked((int)v) : null,
|
||||
64 => obj => obj is ulong v ? checked((int)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, long?> GetInt64Converter(IntLogicalType logicalType) =>
|
||||
GetInt64Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, long?> GetInt64Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? v : null,
|
||||
16 => obj => obj is short v ? v : null,
|
||||
32 => obj => obj is int v ? v : null,
|
||||
64 => obj => obj as long?,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? v : null,
|
||||
16 => obj => obj is ushort v ? v : null,
|
||||
32 => obj => obj is uint v ? v : null,
|
||||
64 => obj => obj is ulong v ? checked((long)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, byte?> GetUInt8Converter(IntLogicalType logicalType) =>
|
||||
GetUInt8Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, byte?> GetUInt8Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? checked((byte)v) : null,
|
||||
16 => obj => obj is short v ? checked((byte)v) : null,
|
||||
32 => obj => obj is int v ? checked((byte)v) : null,
|
||||
64 => obj => obj is long v ? checked((byte)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj as byte?,
|
||||
16 => obj => obj is ushort v ? checked((byte)v) : null,
|
||||
32 => obj => obj is uint v ? checked((byte)v) : null,
|
||||
64 => obj => obj is ulong v ? checked((byte)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, ushort?> GetUInt16Converter(IntLogicalType logicalType) =>
|
||||
GetUInt16Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, ushort?> GetUInt16Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? checked((ushort)v) : null,
|
||||
16 => obj => obj is short v ? checked((ushort)v) : null,
|
||||
32 => obj => obj is int v ? checked((ushort)v) : null,
|
||||
64 => obj => obj is long v ? checked((ushort)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? v : null,
|
||||
16 => obj => obj is ushort v ? v : null,
|
||||
32 => obj => obj is uint v ? checked((ushort)v) : null,
|
||||
64 => obj => obj is ulong v ? checked((ushort)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, uint?> GetUInt32Converter(IntLogicalType logicalType) =>
|
||||
GetUInt32Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, uint?> GetUInt32Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? checked((uint)v) : null,
|
||||
16 => obj => obj is short v ? checked((uint)v) : null,
|
||||
32 => obj => obj is int v ? checked((uint)v) : null,
|
||||
64 => obj => obj is long v ? checked((uint)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? v : null,
|
||||
16 => obj => obj is ushort v ? v : null,
|
||||
32 => obj => obj is uint v ? v : null,
|
||||
64 => obj => obj is ulong v ? checked((uint)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static Func<object?, ulong?> GetUInt64Converter(IntLogicalType logicalType) =>
|
||||
GetUInt64Converter(logicalType.IsSigned, logicalType.BitWidth);
|
||||
|
||||
public static Func<object?, ulong?> GetUInt64Converter(bool isSigned, int bitWidth) =>
|
||||
isSigned
|
||||
? bitWidth switch {
|
||||
8 => obj => obj is sbyte v ? checked((ulong)v) : null,
|
||||
16 => obj => obj is short v ? checked((ulong)v) : null,
|
||||
32 => obj => obj is int v ? checked((ulong)v) : null,
|
||||
64 => obj => obj is long v ? checked((ulong)v) : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
}
|
||||
: bitWidth switch {
|
||||
8 => obj => obj is byte v ? v : null,
|
||||
16 => obj => obj is ushort v ? v : null,
|
||||
32 => obj => obj is uint v ? v : null,
|
||||
64 => obj => obj is ulong v ? v : null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
|
||||
public static string ColumnEnumTypeKey(string colName) =>
|
||||
$"{colName}.EnumType";
|
||||
|
||||
public static KeyValuePair<string, string> ColumnEnumTypeEntry(string colName, Type enumType) {
|
||||
if (enumType.IsNullable()) {
|
||||
enumType = enumType.GetGenericArguments()[0];
|
||||
}
|
||||
if (!enumType.IsEnum) {
|
||||
throw new ArgumentException($"Must be enum type (actually {enumType})", nameof(enumType));
|
||||
}
|
||||
return new(ColumnEnumTypeKey(colName), enumType.ToString());
|
||||
}
|
||||
|
||||
public static Type? GetColumnEnumType(IReadOnlyDictionary<string, string>? keyValueMetadata, string columnName) {
|
||||
if (keyValueMetadata is not null) {
|
||||
var key = ColumnEnumTypeKey(columnName);
|
||||
if (keyValueMetadata.TryGetValue(key, out var typeName)) {
|
||||
return Type.GetType(typeName);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public interface IColumnWriter : IDisposable {
|
||||
void Write(IReadOnlyCollection<object?> values);
|
||||
}
|
||||
|
||||
public interface IColumnWriter<T> : IColumnWriter {
|
||||
void Write(IReadOnlyCollection<T?> values);
|
||||
}
|
||||
|
||||
class ColumnWriter<T> : IColumnWriter<T> {
|
||||
readonly T?[] buffer;
|
||||
readonly LogicalColumnWriter<T> writer;
|
||||
readonly Func<object?, T?> convert;
|
||||
|
||||
public ColumnWriter(ColumnWriter writer, int bufferSize)
|
||||
: this(writer, new T?[bufferSize]) { }
|
||||
|
||||
public ColumnWriter(ColumnWriter writer, int bufferSize, Func<object?, T?> convert)
|
||||
: this(writer, new T?[bufferSize], convert) { }
|
||||
|
||||
public ColumnWriter(ColumnWriter writer, T?[] buffer)
|
||||
: this(writer, buffer, obj => (T?)obj) { }
|
||||
|
||||
public ColumnWriter(ColumnWriter writer, T?[] buffer, Func<object?, T?> convert) {
|
||||
this.buffer = buffer;
|
||||
this.writer = writer.LogicalWriter<T>();
|
||||
this.convert = convert;
|
||||
}
|
||||
|
||||
public void Write(IReadOnlyCollection<T?> values) {
|
||||
if (buffer.Length == 0) {
|
||||
throw new InvalidOperationException("Cannot write because buffer length is 0");
|
||||
}
|
||||
var count = values.Count;
|
||||
var nPages = count / buffer.Length;
|
||||
using var en = values.GetEnumerator();
|
||||
for (int pg = 0; pg < nPages; pg++) {
|
||||
for (int i = 0; i < buffer.Length; i++) {
|
||||
Log.assert(en.MoveNext(), "Enumeration failed before reaching expected count");
|
||||
buffer[i] = en.Current;
|
||||
}
|
||||
writer.WriteBatch(buffer!);
|
||||
}
|
||||
var remainder = count - nPages * buffer.Length;
|
||||
if (remainder != 0) {
|
||||
for (int i = 0; i < remainder; i++) {
|
||||
Log.assert(en.MoveNext(), "Enumeration failed before reaching expected count");
|
||||
buffer[i] = en.Current;
|
||||
}
|
||||
writer.WriteBatch(buffer!, 0, remainder);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() =>
|
||||
writer.Dispose();
|
||||
|
||||
void IColumnWriter.Write(IReadOnlyCollection<object?> values) =>
|
||||
Write(ReadOnlySelectorCollection.Create(values, convert));
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
class ParquetColumnReader<T> : IParquetColumnReader<T> {
|
||||
protected readonly LogicalColumnReader<T> reader;
|
||||
protected readonly T?[] buffer;
|
||||
|
||||
public ParquetColumnReader(ColumnReader reader, int bufferSize)
|
||||
: this(reader, new T?[bufferSize]) { }
|
||||
|
||||
protected ParquetColumnReader(ColumnReader reader, T?[] buffer) {
|
||||
this.buffer = buffer;
|
||||
this.reader = reader.LogicalReader<T>();
|
||||
}
|
||||
|
||||
~ParquetColumnReader() =>
|
||||
Dispose();
|
||||
|
||||
public IList<T?> Read() {
|
||||
if (buffer.Length == 0) {
|
||||
throw new InvalidOperationException("Cannot write because buffer length is 0");
|
||||
}
|
||||
int n = reader.ReadBatch(buffer!);
|
||||
return buffer.WrapSubRange(0, n);
|
||||
}
|
||||
|
||||
public IList<T?> Read(int? start, int? stop) {
|
||||
if (buffer.Length == 0) {
|
||||
throw new InvalidOperationException("Cannot write because buffer length is 0");
|
||||
}
|
||||
start ??= 0;
|
||||
stop ??= buffer.Length;
|
||||
int length = stop.Value - start.Value;
|
||||
if (length <= 0) {
|
||||
return new List<T?>(0);
|
||||
}
|
||||
if (start.Value > 0) {
|
||||
var nSkipped = checked((int)reader.Skip(start.Value));
|
||||
Log.assert(nSkipped >= 0 && nSkipped <= start.Value);
|
||||
if (nSkipped < start.Value) {
|
||||
return new List<T?>(0);
|
||||
}
|
||||
}
|
||||
int n = reader.ReadBatch(buffer!, 0, length);
|
||||
return buffer.WrapSubRange(0, n);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class ParquetColumnReader<TIn, TOut> : IParquetColumnReader<TOut> {
|
||||
readonly Func<TIn, TOut?> convert;
|
||||
readonly LogicalColumnReader<TIn> reader;
|
||||
readonly TIn[] buffer;
|
||||
|
||||
public ParquetColumnReader(ColumnReader reader, Func<TIn, TOut?> convert, int bufferSize)
|
||||
: this(reader, convert, new TIn[bufferSize]) { }
|
||||
|
||||
public ParquetColumnReader(ColumnReader reader, Func<TIn, TOut?> convert, TIn[] buffer) {
|
||||
this.convert = convert;
|
||||
this.reader = reader.LogicalReader<TIn>();
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
~ParquetColumnReader() =>
|
||||
Dispose();
|
||||
|
||||
public IList<TOut?> Read() {
|
||||
if (buffer.Length == 0) {
|
||||
throw new InvalidOperationException("Cannot write because buffer length is 0");
|
||||
}
|
||||
int n = reader.ReadBatch(buffer!);
|
||||
return buffer.WrapSelector(convert, null).WrapSubRange(0, n);
|
||||
}
|
||||
|
||||
public IList<TOut?> Read(int? start, int? stop) {
|
||||
if (buffer.Length == 0) {
|
||||
throw new InvalidOperationException("Cannot write because buffer length is 0");
|
||||
}
|
||||
start ??= 0;
|
||||
stop ??= buffer.Length;
|
||||
int length = stop.Value - start.Value;
|
||||
if (length <= 0) {
|
||||
return new List<TOut?>(0);
|
||||
}
|
||||
if (start.Value > 0) {
|
||||
var nSkipped = checked((int)reader.Skip(start.Value));
|
||||
Log.assert(nSkipped >= 0 && nSkipped <= start.Value);
|
||||
if (nSkipped < start.Value) {
|
||||
return new List<TOut?>(0);
|
||||
}
|
||||
}
|
||||
int n = reader.ReadBatch(buffer!, 0, length);
|
||||
return buffer.WrapSelector(convert, null).WrapSubRange(0, n);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using Microsoft.Scripting.Utils;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
public static class ParquetExtensions {
|
||||
public static int RowCount(this FileMetaData fileMetaData) =>
|
||||
checked((int)fileMetaData.NumRows);
|
||||
|
||||
public static IBlueTableSchema ToBlueSchema(this SchemaDescriptor schemaDescriptor, string tableName = "parquet", IReadOnlyDictionary<string, string>? keyValueMetadata = null) {
|
||||
var colInfos = new ColumnInfo[schemaDescriptor.NumColumns];
|
||||
for (int i = 0; i < colInfos.Length; i++) {
|
||||
colInfos[i] = schemaDescriptor.BlueColumn(i, keyValueMetadata);
|
||||
}
|
||||
return new BlueTableSchema(tableName, colInfos);
|
||||
}
|
||||
|
||||
public static IBlueTableSchema ToBlueSchema(this FileMetaData fileMetaData, string tableName = "parquet") =>
|
||||
ToBlueSchema(fileMetaData.Schema, tableName, fileMetaData.KeyValueMetadata);
|
||||
|
||||
public static ColumnInfo BlueColumn(this SchemaDescriptor schemaDescriptor, int index, IReadOnlyDictionary<string, string>? keyValueMetadata = null) {
|
||||
var c = schemaDescriptor.Column(index);
|
||||
var lt = c.LogicalType;
|
||||
if (lt.Type == LogicalTypeEnum.Enum) {
|
||||
var enumType = ParquetAdapter.GetColumnEnumType(keyValueMetadata, c.Name);
|
||||
if (enumType is not null) {
|
||||
return new(c.Name, index, enumType);
|
||||
}
|
||||
}
|
||||
return new(c.Name, index, getTypeCode(c.LogicalType, c.PhysicalType));
|
||||
}
|
||||
|
||||
public static IBlueRowCollection ReadBlueTable(this ParquetFileReader fileReader, int? start = null, int? stop = null) {
|
||||
var schema = fileReader.FileMetaData.ToBlueSchema("parquetReader");
|
||||
var colInfos = schema.columnInfo;
|
||||
IBlueRowCollection? rv;
|
||||
if (!schema.columnInfo.Any(c => c.colName == "id")) {
|
||||
rv = BlueAddIndexColumnTable.Create(schema, fileReader.ReadColumns(start, stop));
|
||||
} else {
|
||||
rv = new BlueIndexedColumnTable(schema, fileReader.ReadColumns(start, stop));
|
||||
}
|
||||
Log.assert(!schema.columnInfo.Any(c => c is null));
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static (Column[] Column, IReadOnlyDictionary<string, string> Meta) ToParquetSchema(this IBlueTableSchema schema) {
|
||||
var blueColumns = schema.columnInfo;
|
||||
var parquetColumns = new Column[blueColumns.Length];
|
||||
var parquetMeta = new Dictionary<string, string>();
|
||||
KeyValuePair<string, string>[] parquetColMeta;
|
||||
for (int i = 0; i < blueColumns.Length; i++) {
|
||||
(parquetColumns[i], parquetColMeta) = ToParquetColumn(blueColumns[i]);
|
||||
parquetMeta.AddRange(parquetColMeta);
|
||||
}
|
||||
return (parquetColumns, parquetMeta);
|
||||
}
|
||||
|
||||
public static (Column Column, KeyValuePair<string, string>[] Meta) ToParquetColumn(this ColumnInfo columnInfo) {
|
||||
var colType = columnInfo.colType;
|
||||
bool isNullable = colType.IsNullable();
|
||||
if (isNullable) {
|
||||
colType = colType.GetGenericArguments()[0];
|
||||
}
|
||||
KeyValuePair<string, string>[] meta;
|
||||
TypeCode typeCode;
|
||||
var colName = columnInfo.colName;
|
||||
if (colType.IsEnum) {
|
||||
typeCode = colType.GetEnumUnderlyingType().GetTypeCode();
|
||||
meta = new[] { ParquetAdapter.ColumnEnumTypeEntry(columnInfo.colName, colType) };
|
||||
} else {
|
||||
typeCode = colType.GetTypeCode();
|
||||
meta = Array.Empty<KeyValuePair<string, string>>();
|
||||
}
|
||||
return (ToParquetColumn(colName, typeCode), meta);
|
||||
|
||||
static Column ToParquetColumn(string colName, TypeCode typeCode) =>
|
||||
typeCode switch {
|
||||
TypeCode.Boolean => new Column<bool?>(colName),
|
||||
TypeCode.Byte => new Column<byte?>(colName),
|
||||
TypeCode.Int16 => new Column<short?>(colName),
|
||||
TypeCode.Int32 => new Column<int?>(colName),
|
||||
TypeCode.Int64 => new Column<long?>(colName),
|
||||
TypeCode.UInt16 => new Column<ushort?>(colName),
|
||||
TypeCode.UInt32 => new Column<uint?>(colName),
|
||||
TypeCode.UInt64 => new Column<ulong?>(colName),
|
||||
TypeCode.Single => new Column<float?>(colName),
|
||||
TypeCode.Double => new Column<double?>(colName),
|
||||
TypeCode.DateTime => new Column<DateTimeNanos?>(colName),
|
||||
TypeCode.String => new Column<string?>(colName),
|
||||
_ => throw new NotSupportedException($"Unsupported column TypeCode {typeCode}"),
|
||||
};
|
||||
}
|
||||
|
||||
static TypeCode getTypeCode(LogicalType logicalType, PhysicalType physicalType) {
|
||||
return logicalType.Type switch {
|
||||
// LogicalTypeEnum.Int => TypeCode.Int32,
|
||||
// LogicalTypeEnum.Decimal => TypeCode.Double,
|
||||
LogicalTypeEnum.Date or LogicalTypeEnum.Time or LogicalTypeEnum.Timestamp => TypeCode.DateTime,
|
||||
LogicalTypeEnum.String => TypeCode.String,
|
||||
LogicalTypeEnum.Int => FromInt(),
|
||||
LogicalTypeEnum.Decimal => FromDecimal(),
|
||||
_ => FromPhysicalType(),
|
||||
};
|
||||
|
||||
TypeCode FromPhysicalType() =>
|
||||
physicalType switch {
|
||||
PhysicalType.Boolean => TypeCode.Boolean,
|
||||
PhysicalType.Int32 => TypeCode.Int32,
|
||||
PhysicalType.Int64 => TypeCode.Int64,
|
||||
PhysicalType.Float => TypeCode.Single,
|
||||
PhysicalType.Double => TypeCode.Double,
|
||||
_ => throw new NotImplementedException($"TypeCode not implemented for {logicalType} (logical) {physicalType} (physical)"),
|
||||
};
|
||||
|
||||
TypeCode FromInt() {
|
||||
var ilt = (IntLogicalType)logicalType;
|
||||
var bitWidth = ilt.BitWidth;
|
||||
return ilt.IsSigned ? FromSignedInt() : FromUnsignedInt();
|
||||
|
||||
TypeCode FromSignedInt() =>
|
||||
bitWidth switch {
|
||||
8 => TypeCode.SByte,
|
||||
16 => TypeCode.Int16,
|
||||
32 => TypeCode.Int32,
|
||||
64 => TypeCode.Int64,
|
||||
_ => throw new NotSupportedException($"Bit width not supported for signed int ({bitWidth})"),
|
||||
};
|
||||
|
||||
TypeCode FromUnsignedInt() =>
|
||||
bitWidth switch {
|
||||
8 => TypeCode.Byte,
|
||||
16 => TypeCode.UInt16,
|
||||
32 => TypeCode.UInt32,
|
||||
64 => TypeCode.UInt64,
|
||||
_ => throw new NotSupportedException($"Bit width not supported for unsigned int ({bitWidth})"),
|
||||
};
|
||||
}
|
||||
|
||||
TypeCode FromDecimal() {
|
||||
var dlt = (DecimalLogicalType)logicalType;
|
||||
var scale = dlt.Scale;
|
||||
var precision = dlt.Precision;
|
||||
return scale switch {
|
||||
0 => throw new NotSupportedException($"Scale not supported for decimal ({scale})"),
|
||||
_ => TypeCode.Double,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
public class ParquetGroupTable : IBlueRowCollection, IDisposable {
|
||||
readonly RowGroupReader reader;
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly bool leaveOpen;
|
||||
readonly int fullCount;
|
||||
readonly object syncRoot = new();
|
||||
readonly int? start;
|
||||
readonly int? stop;
|
||||
readonly int startIndex;
|
||||
readonly int stopIndex;
|
||||
readonly int idColumnIndex;
|
||||
readonly int idColumnIndexInFile;
|
||||
readonly Func<int, int>? rowIdFactory;
|
||||
DataCache? dataCacheBacking;
|
||||
|
||||
public ParquetGroupTable(
|
||||
RowGroupReader reader,
|
||||
IBlueTableSchema schema,
|
||||
int? start = null,
|
||||
int? stop = null,
|
||||
int idColumnIndex = -1,
|
||||
int idColumnIndexInFile = -1,
|
||||
Func<int, int>? rowIdFactory = null,
|
||||
bool leaveOpen = false
|
||||
) {
|
||||
this.reader = reader;
|
||||
this.schema = schema;
|
||||
this.start = start;
|
||||
this.stop = stop;
|
||||
this.idColumnIndex = idColumnIndex;
|
||||
this.idColumnIndexInFile = idColumnIndexInFile;
|
||||
this.rowIdFactory = rowIdFactory;
|
||||
this.leaveOpen = leaveOpen;
|
||||
fullCount = checked((int)reader.MetaData.NumRows);
|
||||
Log.assert(fullCount >= 0);
|
||||
startIndex = SliceList.GetStartIndex(start, fullCount, true);
|
||||
stopIndex = SliceList.GetStopIndex(stop, fullCount, true);
|
||||
stopIndex = Math.Max(stopIndex, startIndex);
|
||||
Log.assert(
|
||||
startIndex >= 0
|
||||
&& startIndex <= fullCount
|
||||
&& stopIndex >= 0
|
||||
&& stopIndex <= fullCount
|
||||
&& stopIndex >= startIndex);
|
||||
}
|
||||
|
||||
~ParquetGroupTable() =>
|
||||
Dispose();
|
||||
|
||||
public int Count => stopIndex - startIndex;
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
DataCache dataCache =>
|
||||
EnsureInit();
|
||||
|
||||
public IBlueRow this[int id] => dataCache[id];
|
||||
|
||||
public bool containsID(int id) =>
|
||||
dataCache.RowIdToIndex.ContainsKey(id);
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
dataCache.Rows[index];
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int id = item.Id();
|
||||
return dataCache.RowIdToIndex.TryGetValue(id, out var idx) && BlueRowEqualityComparer.Equals(dataCache.Rows[idx], item)
|
||||
? idx
|
||||
: -1;
|
||||
}
|
||||
|
||||
public bool TryGetValue(int id, [NotNullWhen(true)] out IBlueRow? row) {
|
||||
if (dataCache.RowIdToIndex.TryGetValue(id, out var idx)) {
|
||||
row = dataCache.Rows[idx];
|
||||
return true;
|
||||
}
|
||||
row = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
for (int i = 0; i < dataCache.Rows.Length; i++) {
|
||||
yield return dataCache.Rows[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
if (!leaveOpen) {
|
||||
reader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(dataCacheBacking))]
|
||||
internal DataCache EnsureInit() {
|
||||
if (dataCacheBacking.HasValue) {
|
||||
return dataCacheBacking.Value;
|
||||
}
|
||||
lock (syncRoot) {
|
||||
if (dataCacheBacking.HasValue) {
|
||||
return dataCacheBacking.Value;
|
||||
}
|
||||
var rows = new IBlueRow[Count];
|
||||
int numColumns = reader.MetaData.NumColumns;
|
||||
var blueColumns = schema.columnInfo;
|
||||
Log.assert((blueColumns.Length - numColumns) switch {
|
||||
0 or 1 => true,
|
||||
_ => false,
|
||||
});
|
||||
var columnValues = allocateColumnValues(
|
||||
reader, blueColumns.Length, Count, idColumnIndex, idColumnIndexInFile, startIndex, stopIndex, rowIdFactory);
|
||||
var rowIdToIndex = new Dictionary<int, int>();
|
||||
for (int i = 0; i < rows.Length; i++) {
|
||||
rows[i] = new BlueRowColumnWrapper(schema, i, columnValues);
|
||||
}
|
||||
dataCacheBacking = new(rows, rowIdToIndex, columnValues);
|
||||
}
|
||||
return dataCacheBacking.Value;
|
||||
}
|
||||
|
||||
static IList<object?>[] allocateColumnValues(
|
||||
RowGroupReader reader,
|
||||
int numColumns,
|
||||
int numRows,
|
||||
int idColIdx,
|
||||
int idColIdxInFile,
|
||||
int startIndex,
|
||||
int stopIndex,
|
||||
Func<int, int>? idFactory
|
||||
) {
|
||||
if (idColIdx < 0 || idColIdx >= numColumns) {
|
||||
throw new ArgumentException("Id column index out of bounds", nameof(idColIdx));
|
||||
}
|
||||
var columnValues = new IList<object?>[numColumns];
|
||||
if (idColIdxInFile == -1) {
|
||||
// Generate ids (there is no id column in the file)
|
||||
ArgumentNullException.ThrowIfNull(idFactory);
|
||||
for (int i = 0; i < numColumns; i++) {
|
||||
if (i < idColIdx) {
|
||||
ReadColumn(i, i);
|
||||
} else if (i == idColIdx) {
|
||||
columnValues[idColIdx] = new StepList<int>(0, 1, numRows).WrapSelector(idx => (object?)idFactory(idx), null);
|
||||
} else {
|
||||
ReadColumn(i - 1, i);
|
||||
}
|
||||
}
|
||||
} else if (idFactory is not null) {
|
||||
// Generate ids (skip id column in the file)
|
||||
for (int i = 0; i < numColumns; i++) {
|
||||
if (i == idColIdx) {
|
||||
columnValues[idColIdx] = new StepList<int>(0, 1, numRows).WrapSelector(idx => (object?)idFactory(idx), null);
|
||||
} else {
|
||||
if (i > idColIdx && i < idColIdxInFile) {
|
||||
ReadColumn(i - 1, i);
|
||||
} else if (i > idColIdxInFile && i < idColIdx) {
|
||||
ReadColumn(i + 1, i);
|
||||
} else {
|
||||
ReadColumn(i, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Get ids from the file (output table id column index may differ from file)
|
||||
// Case 1) File id col index > output
|
||||
// src cols: a, b, c, d, (id), e, f, ...
|
||||
// dst cols: a, b, (id), c, d, e, f, ...
|
||||
//
|
||||
// Case 2) File id col index == output
|
||||
// src cols: a, b, (id), c, d, e, f, ...
|
||||
// dst cols: a, b, (id), c, d, e, f, ...
|
||||
//
|
||||
// Case 3) File id col index < output
|
||||
// src cols: a, b, (id), c, d, e, f, ...
|
||||
// dst cols: a, b, c, d, (id), e, f, ...
|
||||
|
||||
for (int i = 0; i < numColumns; i++) {
|
||||
if (i == idColIdx) {
|
||||
ReadColumn(idColIdxInFile, idColIdx);
|
||||
} else if (i > idColIdx && i < idColIdxInFile) {
|
||||
ReadColumn(i - 1, i);
|
||||
} else if (i > idColIdxInFile && i < idColIdx) {
|
||||
ReadColumn(i, i - 1);
|
||||
} else {
|
||||
ReadColumn(i, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return columnValues;
|
||||
|
||||
void ReadColumn(int srcIdx, int dstIdx) {
|
||||
using var colReader = reader.GetColumnReader(srcIdx);
|
||||
columnValues[dstIdx] = colReader.Read(startIndex, stopIndex);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
|
||||
internal readonly struct DataCache {
|
||||
public readonly IBlueRow[] Rows;
|
||||
public readonly Dictionary<int, int> RowIdToIndex;
|
||||
public readonly IList<object?>[] ColumnValues;
|
||||
|
||||
public DataCache(IBlueRow[] rows, Dictionary<int, int> rowIdToIndex, IList<object?>[] columnValues) {
|
||||
Rows = rows;
|
||||
RowIdToIndex = rowIdToIndex;
|
||||
ColumnValues = columnValues;
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] =>
|
||||
Rows[RowIdToIndex[id]];
|
||||
|
||||
public IBlueRow GetRow(int index) =>
|
||||
Rows[index];
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.PubSub;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
[DataStreamUserRespresentation(false)]
|
||||
public class ParquetReaderStream : ViewStream {
|
||||
readonly string file;
|
||||
readonly int? start;
|
||||
readonly int? stop;
|
||||
readonly IWorkScheduler workScheduler;
|
||||
IBlueRowCollection? table;
|
||||
IDisposable? workerSub;
|
||||
|
||||
public ParquetReaderStream(string file, IWorkScheduler workScheduler) {
|
||||
this.file = file;
|
||||
this.workScheduler = workScheduler;
|
||||
}
|
||||
|
||||
public ParquetReaderStream(string file, int? start, int? stop, IWorkScheduler workScheduler) {
|
||||
this.file = file;
|
||||
this.start = start;
|
||||
this.stop = stop;
|
||||
this.workScheduler = workScheduler;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Start();
|
||||
var worker = new AnonymousWorker(DoWork);
|
||||
workScheduler.Add(worker);
|
||||
workerSub = Disposable.Create(() => workScheduler.Remove(worker));
|
||||
|
||||
async void Start() {
|
||||
try {
|
||||
Volatile.Write(ref table, await ParquetTableReader.ReadAsync(file, start, stop));
|
||||
} catch (Exception ex) {
|
||||
Log.DataFlow.error($"[parquet_reader_stream_err.json]{{ \"err\": \"{ex}\" }}");
|
||||
}
|
||||
}
|
||||
|
||||
void DoWork() {
|
||||
var table = Volatile.Read(ref this.table);
|
||||
if (table is null) {
|
||||
return;
|
||||
}
|
||||
Disposable.dispose_thread_safe(ref workerSub);
|
||||
if (table.schema.columnInfo.Length > 1) {
|
||||
myFireEvent(new DataPacket(table, table, new BlueTableImmutable(table.schema)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose_thread_safe(ref workerSub);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// namespace Bts.DataStream.Parquet;
|
||||
|
||||
// using BCG;
|
||||
|
||||
// using global::Parquet.Data;
|
||||
|
||||
// public class ParquetRow : IBlueRow {
|
||||
// readonly int id;
|
||||
// readonly int rowIndex;
|
||||
// readonly DataColumn[] data;
|
||||
|
||||
// public ParquetRow(int id, int rowIndex, DataColumn[] data, IBlueTableSchema schema) {
|
||||
// this.id = id;
|
||||
// this.rowIndex = rowIndex;
|
||||
// this.data = data;
|
||||
// Schema = schema;
|
||||
// }
|
||||
|
||||
// public object? this[int index] =>
|
||||
// index == 0
|
||||
// ? id
|
||||
// : data[index - 1].Data.GetValue(rowIndex);
|
||||
|
||||
// public IBlueTableSchema Schema { get; }
|
||||
// IBlueTableSchema IBlueRow.schema => Schema;
|
||||
// }
|
||||
@@ -1,145 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class ParquetTable : IBlueRowCollection, IDisposable {
|
||||
readonly SortedList<int, ParquetGroupTable> groups = new();
|
||||
readonly int fullCount;
|
||||
readonly IBlueTableSchema schema;
|
||||
readonly ParquetFileReader? reader;
|
||||
readonly int startIndex;
|
||||
readonly int stopIndex;
|
||||
|
||||
public ParquetTable(ParquetFileReader reader, string tableName = "parquet", int? start = null, int? stop = null, bool leaveOpen = false) {
|
||||
schema = reader.FileMetaData.ToBlueSchema(tableName);
|
||||
int idColIdx;
|
||||
if (schema.TryResolveIndices("id", out int idColIdxInFile)) {
|
||||
idColIdx = idColIdxInFile;
|
||||
} else {
|
||||
var origCols = schema.columnInfo;
|
||||
var cols = new ColumnInfo[origCols.Length + 1];
|
||||
idColIdx = 0;
|
||||
cols[0] = new("id", 0, typeof(int));
|
||||
for (int i = 0; i < origCols.Length; i++) {
|
||||
var c = origCols[i];
|
||||
cols[i + 1] = new(c.colName, i + 1, c.colType);
|
||||
}
|
||||
schema = new BlueTableSchema(cols, schema.tableName);
|
||||
}
|
||||
fullCount = checked((int)reader.FileMetaData.NumRows);
|
||||
Log.assert(fullCount >= 0);
|
||||
startIndex = SliceList.GetStartIndex(start, fullCount, true);
|
||||
stopIndex = SliceList.GetStopIndex(stop, fullCount, true);
|
||||
stopIndex = Math.Max(stopIndex, startIndex);
|
||||
Log.assert(startIndex >= 0 && startIndex <= fullCount && stopIndex >= 0 && stopIndex <= fullCount && stopIndex >= startIndex);
|
||||
int numRowGroups = reader.FileMetaData.NumRowGroups;
|
||||
int rowGroupLastIdx = 0;
|
||||
object syncRoot = new();
|
||||
for (int i = 0; i < numRowGroups && rowGroupLastIdx < Count; i++) {
|
||||
int? grpStart = start.HasValue ? startIndex - rowGroupLastIdx : null;
|
||||
int? grpStop = stop.HasValue ? stopIndex - rowGroupLastIdx : null;
|
||||
int offset = rowGroupLastIdx;
|
||||
var grp = new ParquetGroupTable(reader.RowGroup(i), schema, grpStart, grpStop, idColIdx, idColIdxInFile, GetAutoId);
|
||||
if (grp.Count == 0) {
|
||||
continue;
|
||||
}
|
||||
rowGroupLastIdx += grp.Count;
|
||||
groups.Add(rowGroupLastIdx, grp);
|
||||
|
||||
int GetAutoId(int index) =>
|
||||
index + offset;
|
||||
}
|
||||
Parallel.For(0, groups.Count, i => groups.GetValueAtIndex(i).EnsureInit());
|
||||
if (!leaveOpen) {
|
||||
this.reader = reader;
|
||||
}
|
||||
}
|
||||
|
||||
~ParquetTable() =>
|
||||
Dispose();
|
||||
|
||||
public IBlueTableSchema Schema => schema;
|
||||
|
||||
public int Count => stopIndex - startIndex;
|
||||
|
||||
IBlueTableSchema IBlueRowCollection.schema => schema;
|
||||
|
||||
public IBlueRow this[int index] {
|
||||
get {
|
||||
foreach (var grp in groups.Values) {
|
||||
if (grp.TryGetValue(index, out var r)) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
public static ParquetTable FromFile(string path, int? start = null, int? stop = null, string tableName = "parquet") =>
|
||||
new(new(path), tableName, start, stop, false);
|
||||
|
||||
public IBlueRow GetRow(int index) {
|
||||
if (index < 0 || index >= Count) {
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
int rowGroupIdx = groups.Keys.BinarySearch(index);
|
||||
if (rowGroupIdx < 0) {
|
||||
rowGroupIdx = ~rowGroupIdx;
|
||||
}
|
||||
Log.assert(rowGroupIdx <= groups.Count);
|
||||
var grp = groups[rowGroupIdx];
|
||||
int idxWithinGrp = index;
|
||||
if (rowGroupIdx > 0) {
|
||||
idxWithinGrp -= groups.Keys[rowGroupIdx - 1];
|
||||
}
|
||||
return grp[idxWithinGrp];
|
||||
}
|
||||
|
||||
public bool containsID(int id) =>
|
||||
groups.Values.Any(rgl => rgl.containsID(id));
|
||||
|
||||
public int IndexOf(IBlueRow item) {
|
||||
int idx;
|
||||
int grpFirstIdx = 0;
|
||||
foreach (var (grpLastIdx, grp) in groups) {
|
||||
idx = grp.IndexOf(item);
|
||||
if (idx >= 0) {
|
||||
return idx + grpFirstIdx;
|
||||
}
|
||||
grpFirstIdx = grpLastIdx;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public IEnumerator<IBlueRow> GetEnumerator() {
|
||||
foreach (var rgl in groups.Values) {
|
||||
foreach (var r in rgl) {
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
groups.Values.DisposeAll();
|
||||
reader?.Dispose();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#nullable enable
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class ParquetTableReader {
|
||||
public static Task<IBlueRowCollection> ReadAsync(Stream stream, bool leaveOpen = false, int? start = null, int? stop = null) =>
|
||||
Task.Run(() => Read(stream, leaveOpen, start, stop));
|
||||
|
||||
public static Task<IBlueRowCollection> ReadAsync(string path, int? start = null, int? stop = null) =>
|
||||
Task.Run(() => Read(path, start, stop));
|
||||
|
||||
public static IBlueRowCollection Read(Stream stream, bool leaveOpen = false, int? start = null, int? stop = null) {
|
||||
using var fileReader = new ParquetFileReader(stream, leaveOpen);
|
||||
var rv = fileReader.ReadBlueTable(start, stop);
|
||||
rv.schema.Validate();
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static IBlueRowCollection Read(string path, int? start = null, int? stop = null) {
|
||||
IBlueRowCollection rv = ParquetTable.FromFile(path, start, stop);
|
||||
rv.schema.Validate();
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using bts;
|
||||
|
||||
using ParquetSharp;
|
||||
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class ParquetTableWriter {
|
||||
public static Task WriteAsync(IBlueRowCollection blueRows, Stream outStream, bool leaveOpen = false) =>
|
||||
Task.Run(() => Write(blueRows, outStream, leaveOpen));
|
||||
|
||||
public static void Write(IBlueRowCollection blueRows, Stream outStream, bool leaveOpen = false) {
|
||||
var (parquetColumns, parquetMeta) = blueRows.schema.ToParquetSchema();
|
||||
using var schema = Column.CreateSchemaNode(parquetColumns);
|
||||
using var writerProps = createWriterProperties();
|
||||
using var writer = new ParquetFileWriter(outStream, schema, writerProps, keyValueMetadata: parquetMeta, leaveOpen: leaveOpen);
|
||||
using var rowGroup = writer.AppendRowGroup();
|
||||
for (int i = 0; i < blueRows.schema.columnInfo.Length; i++) {
|
||||
var col = blueRows.schema.columnInfo[i];
|
||||
Log.assert(col.colNo == i);
|
||||
using var colWriter = ParquetAdapter.GetColumnWriter(col.type_code(), rowGroup.NextColumn());
|
||||
colWriter.Write(blueRows.GetColumn(i));
|
||||
}
|
||||
writer.Close();
|
||||
}
|
||||
|
||||
static WriterProperties createWriterProperties(Compression compression = Compression.Snappy) {
|
||||
using var builder = new WriterPropertiesBuilder();
|
||||
builder.Compression(compression);
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
namespace Bts.DataStream.Parquet;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.collections;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.PubSub;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Threading;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
[DataStreamUserRespresentation(false)]
|
||||
public class ParquetWriterStream : ViewStream {
|
||||
readonly string file;
|
||||
readonly ViewStream inputStream;
|
||||
readonly IWorkScheduler workScheduler;
|
||||
readonly AtomicGate gate = new();
|
||||
IDataPacket? pendingOutput;
|
||||
IDisposable? dispose;
|
||||
|
||||
public ParquetWriterStream(ViewStream inputStream, string file, IWorkScheduler workScheduler) {
|
||||
this.inputStream = inputStream;
|
||||
this.file = file;
|
||||
this.workScheduler = workScheduler;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
BlueTableImmutable.DataPacketBuilder? outputBuilder = null;
|
||||
bool isFirstUpdate = false;
|
||||
var worker = new AnonymousWorker(DoWork);
|
||||
inputStream.onChange += OnInputStreamChange;
|
||||
workScheduler.Add(worker);
|
||||
dispose = Disposable.Create(Dispose);
|
||||
|
||||
void Dispose() {
|
||||
workScheduler.Remove(worker);
|
||||
inputStream.onChange -= OnInputStreamChange;
|
||||
}
|
||||
|
||||
void OnInputStreamChange(object? dpObj) {
|
||||
var dp = ExceptionAssert.Argument.Is<IDataPacket>(dpObj);
|
||||
using (gate.BeginTransaction()) {
|
||||
outputBuilder ??= new BlueTableImmutable(dp.Schema).ToDataPacketBuilder();
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
outputBuilder.AddOrUpdate(r);
|
||||
}
|
||||
foreach (IBlueRow r in dp.deletedRows) {
|
||||
outputBuilder.Remove(r.Id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async void DoWork() {
|
||||
using (gate.BeginTransaction()) {
|
||||
if (outputBuilder is null) {
|
||||
return;
|
||||
}
|
||||
if (pendingOutput is not null) {
|
||||
myFireEvent(pendingOutput);
|
||||
pendingOutput = null;
|
||||
}
|
||||
var dp = outputBuilder.ToDataPacket();
|
||||
if (isFirstUpdate) {
|
||||
isFirstUpdate = false;
|
||||
} else if (!dp.HasChanges()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
using var outStream = File.OpenWrite(file);
|
||||
await ParquetTableWriter.WriteAsync(dp.newRows, outStream);
|
||||
}
|
||||
// Fire the update at the beginning of the next doWork call so it happens on the
|
||||
// 'work' thread.
|
||||
pendingOutput = dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose_thread_safe(ref dispose);
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using ProtoBuf;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@@ -23,7 +26,7 @@ namespace bts.BlueOrb {
|
||||
#endregion
|
||||
|
||||
|
||||
#region Row with mappings build in
|
||||
#region Row with mapipings build in
|
||||
internal class NewProjectRow : IBlueRow {
|
||||
#region IBlueRow members
|
||||
private ProjectData _project_data;
|
||||
@@ -132,30 +135,38 @@ namespace bts.BlueOrb {
|
||||
return new NewProjectRow(_project_data, row);
|
||||
}
|
||||
|
||||
// this is where most of the logic is, in terms of translating cols
|
||||
private static ProjectData _create_project_data(IBlueTableSchema input_schema,
|
||||
string project_expression) {
|
||||
project_expression = project_expression.Trim();
|
||||
string[] project_toks = project_expression.Split(' ', ',');
|
||||
string[] project_toks = project_expression.Split(' ');
|
||||
HashSet<string> removed_cols = new HashSet<string>();
|
||||
Dictionary<string, string> orig_to_mapped = new Dictionary<string, string>();
|
||||
Dictionary<string, string> mapped_to_orig_map = new Dictionary<string, string>();
|
||||
Dictionary<string, string> orig_to_mapped = new Dictionary<string, string>();
|
||||
// by default every col will show up, so if we have the projection as (a:a1)
|
||||
// it will convert a to a1,
|
||||
// modifications (6/30/2025):
|
||||
// only the columns represented here, either mapped
|
||||
// or not, will show
|
||||
// examples: if a schema has cols a b c
|
||||
// project(parent_str, "a:aa b") -> aa b
|
||||
foreach (string o_p_tok in project_toks) {
|
||||
string p_tok = o_p_tok.Trim();
|
||||
if (p_tok.Contains(":")) {
|
||||
// explicit mapping
|
||||
// project(parent_str, "a:aa ") -> aa b c
|
||||
// project(parent_str, "a:aa !c") -> aa b
|
||||
// project(parent_str, "a:aa !") -> aa
|
||||
// project(parent_str, "a:aa b")) -> aa b
|
||||
bool hide_all = false;
|
||||
foreach (string p_tok in project_toks) {
|
||||
if (p_tok.StartsWith("!")) {
|
||||
if (p_tok.Length == 1) {
|
||||
// if it is a "blanket "!"=> hide all cols except the one that
|
||||
// are stated explicitly
|
||||
hide_all = true;
|
||||
} else {
|
||||
string removed_col = p_tok.Substring(1);
|
||||
removed_cols.Add(removed_col);
|
||||
}
|
||||
} else if (p_tok.Contains(":")) {
|
||||
string[] map_toks = p_tok.Split(":");
|
||||
string orig_col = map_toks[0];
|
||||
string mapped_col = map_toks[1];
|
||||
orig_to_mapped.Add(orig_col, mapped_col);
|
||||
mapped_to_orig_map.Add(mapped_col, orig_col);
|
||||
orig_to_mapped.Add(orig_col, mapped_col);
|
||||
} else {
|
||||
// this is a col_name explicitely stated
|
||||
if (input_schema.columnNames.Contains(p_tok)) {
|
||||
string orig_col = p_tok;
|
||||
string mapped_col = orig_col;
|
||||
@@ -170,19 +181,27 @@ namespace bts.BlueOrb {
|
||||
if (ci.colName == "id") {
|
||||
ColumnInfo nc = new ColumnInfo(ci.colName, new_cols.Count, ci.colType);
|
||||
new_cols.Add(nc);
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
if (removed_cols.Contains(ci.colName)) {
|
||||
continue;
|
||||
} else if (orig_to_mapped.ContainsKey(ci.colName)) {
|
||||
string mapped_name = orig_to_mapped[ci.colName];
|
||||
ColumnInfo nc = new ColumnInfo(mapped_name, new_cols.Count, ci.colType);
|
||||
new_cols.Add(nc);
|
||||
} else {
|
||||
if (hide_all)
|
||||
continue;
|
||||
//if (ci.colName == "id" || removed_cols.Count > 0) {
|
||||
// unless columns are explicitely hidden, all columns show up
|
||||
ColumnInfo nc = new ColumnInfo(ci.colName, new_cols.Count, ci.colType);
|
||||
new_cols.Add(nc);
|
||||
//}
|
||||
}
|
||||
}
|
||||
IBlueTableSchema new_schema = new BlueTableSchema(input_schema.tableName, new_cols.ToArray());
|
||||
var mapped_to_orig_map = orig_to_mapped.ToDictionary(kv => kv.Value, kv => kv.Key);
|
||||
return new ProjectData(input_schema, new_schema, mapped_to_orig_map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
|
||||
[DataStreamUserRespresentation("PythonDataframeStream")]
|
||||
public class PythonDataframeStream : ViewStream {
|
||||
private ViewStream _parent_str;
|
||||
private readonly string _in_csv_file_name;
|
||||
private readonly string _out_csv_filename;
|
||||
private readonly string _transform_function;
|
||||
public PythonDataframeStream(ViewStream parent_str, string transform_function) {
|
||||
var guid = System.Guid.NewGuid();
|
||||
_in_csv_file_name = $"pdfs_in_{guid}.csv";
|
||||
_out_csv_filename = $"pdfs_out_{guid}.csv";
|
||||
_parent_str = new CSVSaverStream(parent_str, _in_csv_file_name);
|
||||
_transform_function = transform_function;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_parent_str.onChange += _parent_str_onchange;
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
_parent_str.onChange -= _parent_str_onchange;
|
||||
}
|
||||
|
||||
private void _parent_str_onchange(object dp_obj) {
|
||||
Log.assert(dp_obj != null);
|
||||
// the file _in_csv_file_name is now populated.
|
||||
// call py_func_wrapper_main and pass this file name as well
|
||||
// as the output file name
|
||||
// py_func_wrapper_main reads _in_csv_file_name into the df and calls
|
||||
// transform function, which returns the tranformed df. py_func_wrapper_main then
|
||||
// writes it into the _out_csv_filename file.
|
||||
// now this function should read _out_csv_filename into a dp
|
||||
// and fire it
|
||||
_compute_and_write();
|
||||
//ViewStream rs = new SchemaGuesserStream(new CSVReaderStream(_out_csv_filename));
|
||||
ViewStream rs = new CSVReaderStream(_out_csv_filename);
|
||||
IBlueRowCollection nrows = null;
|
||||
rs.onChange += (dp_obj) => {
|
||||
nrows = (dp_obj as DataPacket).newRows;
|
||||
};
|
||||
var dp = BlueDataUtility.build_dp(nrows, myLastValue as DataPacket);
|
||||
myFireEvent(dp);
|
||||
}
|
||||
|
||||
private void _compute_and_write() {
|
||||
File.WriteAllText("user_code.py", _transform_function);
|
||||
// wrapper function
|
||||
string py_func_wrapper_main = @"
|
||||
import sys
|
||||
from user_code import transform
|
||||
import pandas as pd
|
||||
|
||||
if __name__ == '__main__':
|
||||
input_file_name = sys.argv[1]
|
||||
output_file_name = sys.argv[2]
|
||||
# 1. load input_file_name into df
|
||||
# 2. do some test calc
|
||||
# 3. write the output of 2 into output_file_name
|
||||
df = pd.read_csv(input_file_name)
|
||||
df_out = transform(df)
|
||||
df_out.to_csv(output_file_name, index=False)";
|
||||
|
||||
|
||||
File.WriteAllText("runner.py", py_func_wrapper_main);
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo {
|
||||
FileName = "python",
|
||||
Arguments = $"runner.py {_in_csv_file_name} {_out_csv_filename}",
|
||||
RedirectStandardOutput = false,
|
||||
UseShellExecute = false
|
||||
};
|
||||
var proc = Process.Start(psi);
|
||||
proc.WaitForExit();
|
||||
|
||||
}
|
||||
|
||||
#region Unused test code
|
||||
private void _simple_test() {
|
||||
|
||||
// actual function that needs to be called ////////////////////////
|
||||
string py_real_function = @"
|
||||
def test(x, out_path):
|
||||
rv = x * 10
|
||||
with open(out_path, 'w') as f:
|
||||
f.write(str(rv))
|
||||
return rv";
|
||||
// the function is in a string object.
|
||||
File.WriteAllText("user_code.py", py_real_function);
|
||||
|
||||
|
||||
// runner app (top level main function) //////////////////////////////
|
||||
string py_func_wrapper_main = @"
|
||||
import sys
|
||||
from user_code import test
|
||||
|
||||
if __name__ == '__main__':
|
||||
arg = int(sys.argv[1])
|
||||
out_path = sys.argv[2]
|
||||
rv = test(arg, out_path)
|
||||
rv = rv + 12
|
||||
with open(out_path, 'w') as f:to \
|
||||
f.write(str(rv))";
|
||||
|
||||
File.WriteAllText("runner.py", py_func_wrapper_main);
|
||||
|
||||
string outputPath = "py_out.txt";
|
||||
ProcessStartInfo psi = new ProcessStartInfo {
|
||||
FileName = "python",
|
||||
Arguments = $"runner.py 4 {outputPath}",
|
||||
RedirectStandardOutput = false,
|
||||
UseShellExecute = false
|
||||
};
|
||||
var proc = Process.Start(psi);
|
||||
proc.WaitForExit();
|
||||
|
||||
// Now read the output written by the function
|
||||
string result = File.ReadAllText(outputPath);
|
||||
Console.WriteLine(result); // Should print "6"
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[DataStreamUserRespresentation("SortStream")]
|
||||
public class SortStream: ViewStream {
|
||||
public SortStream (ViewStream parent_stream, string sort_expr) {
|
||||
ViewStream rs = new BCG.SortStream(parent_stream, sort_expr);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
[DataStreamUserRespresentation("TimeBasedRollingFilterStream")]
|
||||
public class TimeBasedRollingFilterStream : ViewStream {
|
||||
public TimeBasedRollingFilterStream(ViewStream parent_str, string time_col, double n_seconds) {
|
||||
ViewStream rs = new BCG.TimeBasedFilterStream(ViewStreamDatabase.instance, parent_str, time_col, TimeSpan.FromSeconds(n_seconds));
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
using BCG;
|
||||
|
||||
using bts.utils;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
using Spark.Core.Threading;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
// Keeps adding changing rows to the stream, hence preserving the history
|
||||
// and creating a time series, for example this can be used to make bbo updates
|
||||
// into a time series of prices/qty
|
||||
[DataStreamUserRespresentation("TimeSeriesStream")]
|
||||
public class TimeSeriesStream : ViewStream {
|
||||
readonly ViewStream _stream;
|
||||
readonly string timeColumn;
|
||||
readonly AtomicGate gate = new();
|
||||
CircularBufferTable? _table;
|
||||
private int _id = 0;
|
||||
private int _size = 0;
|
||||
|
||||
public TimeSeriesStream(ViewStream stream)
|
||||
: this(stream, Int32.MaxValue) { }
|
||||
|
||||
public TimeSeriesStream(ViewStream stream, int size, string timeColumn = "ts_event") {
|
||||
_stream = stream;
|
||||
_size = size;
|
||||
this.timeColumn = timeColumn;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_stream.onChange += new ChangeDelegate(_onstream_change);
|
||||
}
|
||||
protected override void myOnLastSubscriber() {
|
||||
_stream.onChange -= new ChangeDelegate(_onstream_change);
|
||||
}
|
||||
|
||||
|
||||
private void _onstream_change(object o) {
|
||||
var dp = ExceptionAssert.Argument.Is<IDataPacket>(o);
|
||||
DateTime now = DateTime.Now;
|
||||
using var _ = gate.BeginTransaction();
|
||||
if (_table == null) {
|
||||
var colInfos = dp.newRows.schema.columnInfo;
|
||||
if (colInfos.TryGetFirst(c => c.colName == timeColumn, out var currTimeCol, out var currTimeColIdx)) {
|
||||
colInfos = colInfos.ToArray();
|
||||
colInfos[currTimeColIdx] = new(timeColumn, currTimeCol.colNo, typeof(DateTime));
|
||||
} else {
|
||||
colInfos = ArrayHelper.add(colInfos, new(timeColumn, colInfos.Length, typeof(DateTime)));
|
||||
}
|
||||
_table = new CircularBufferTable(new BlueTableSchema(colInfos, dp.newRows.schema.tableName), _size);
|
||||
}
|
||||
var addedRowsBd = new BlueTableImmutable(_table.schema).ToDataPacketBuilder();
|
||||
var deletedRowsBd = new BlueTableImmutable(_table.schema).ToDataPacketBuilder();
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
MutableBlueRow ar = new MutableBlueRow(_table.schema, r);
|
||||
ar.setValue(timeColumn, now);
|
||||
int id = _id++;
|
||||
ar.setValue("id", id);
|
||||
_table = _table.Add(ar, out var oldRow);
|
||||
addedRowsBd.AddOrUpdate(ar);
|
||||
if (oldRow is not null) {
|
||||
deletedRowsBd.AddOrUpdate(oldRow);
|
||||
}
|
||||
}
|
||||
var addedRows = addedRowsBd.ToImmutable();
|
||||
var deletedRows = deletedRowsBd.ToImmutable();
|
||||
var dp_out = new DataPacket(_table, addedRows, deletedRows);
|
||||
myFireEvent(dp_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using bts;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
/// <summary>
|
||||
/// Maps a timeseries of keys to unique int32 ids.
|
||||
/// </summary>
|
||||
public class TimeseriesIndex<T> where T : notnull {
|
||||
static readonly IComparer<KeyValuePair<DateTime, int>> idTimeseriesComp =
|
||||
KeyValuePairComparer.KeyComparer<DateTime, int>();
|
||||
|
||||
readonly ImmutableDictionary<T, ImmutableList<KeyValuePair<DateTime, int>>> nameToId;
|
||||
readonly ImmutableDictionary<int, TimeseriesKey<T>> idToName;
|
||||
readonly int idCounter;
|
||||
|
||||
public TimeseriesIndex()
|
||||
: this(ImmutableDictionary<T, ImmutableList<KeyValuePair<DateTime, int>>>.Empty, ImmutableDictionary<int, TimeseriesKey<T>>.Empty, 0) { }
|
||||
|
||||
TimeseriesIndex(ImmutableDictionary<T, ImmutableList<KeyValuePair<DateTime, int>>> nameToId, ImmutableDictionary<int, TimeseriesKey<T>> idToName, int idCounter) {
|
||||
this.nameToId = nameToId;
|
||||
this.idToName = idToName;
|
||||
this.idCounter = idCounter;
|
||||
}
|
||||
|
||||
public int Count => idToName.Count;
|
||||
|
||||
public ImmutableDictionary<T, ImmutableList<KeyValuePair<DateTime, int>>> NameToId => nameToId;
|
||||
public ImmutableDictionary<int, TimeseriesKey<T>> IdToName => idToName;
|
||||
|
||||
public bool ContainsId(int id) =>
|
||||
idToName.ContainsKey(id);
|
||||
|
||||
public int GetNearest(TimeseriesKey<T> key) {
|
||||
if (!nameToId.TryGetValue(key.Name, out var ids) || ids.Count == 0) {
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
int idx = ids.BinarySearch(new(key.Timestamp, -1), idTimeseriesComp);
|
||||
if (idx < 0) {
|
||||
idx = ~idx;
|
||||
if (idx == 0) {
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
return ids[idx].Value;
|
||||
}
|
||||
|
||||
public bool TryGetNearest(TimeseriesKey<T> key, out int result) {
|
||||
if (!nameToId.TryGetValue(key.Name, out var ids) || ids.Count == 0) {
|
||||
result = -1;
|
||||
return false;
|
||||
}
|
||||
int idx = ids.BinarySearch(new(key.Timestamp, -1), idTimeseriesComp);
|
||||
if (idx < 0) {
|
||||
idx = ~idx;
|
||||
if (idx == 0) {
|
||||
result = -1;
|
||||
return false;
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
result = ids[idx].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public TimeseriesIndex<T> GetNearestOrAdd(TimeseriesKey<T> key, out int result) {
|
||||
int idx;
|
||||
if (!nameToId.TryGetValue(key.Name, out var ids) || ids.Count == 0) {
|
||||
ids = ImmutableList<KeyValuePair<DateTime, int>>.Empty;
|
||||
idx = 0;
|
||||
} else {
|
||||
idx = ids.BinarySearch(new(key.Timestamp, -1), idTimeseriesComp);
|
||||
if (idx < 0) {
|
||||
idx = ~idx;
|
||||
}
|
||||
}
|
||||
if (idx == 0) {
|
||||
result = idCounter + 1;
|
||||
ids = ids.Insert(0, new(key.Timestamp, result));
|
||||
return new(
|
||||
nameToId.SetItem(key.Name, ids),
|
||||
idToName.SetItem(result, key),
|
||||
result);
|
||||
}
|
||||
result = ids[idx].Value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TimeseriesIndex<T> GetOrAdd(TimeseriesKey<T> key, out int result) {
|
||||
int idx;
|
||||
if (!nameToId.TryGetValue(key.Name, out var ids) || ids.Count == 0) {
|
||||
ids = ImmutableList<KeyValuePair<DateTime, int>>.Empty;
|
||||
idx = 0;
|
||||
} else {
|
||||
idx = ids.BinarySearch(new(key.Timestamp, -1), idTimeseriesComp);
|
||||
if (idx < 0) {
|
||||
idx = ~idx;
|
||||
} else {
|
||||
result = ids[idx].Value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
result = idCounter + 1;
|
||||
ids = ids.Insert(idx, new(key.Timestamp, result));
|
||||
return new(
|
||||
nameToId.SetItem(key.Name, ids),
|
||||
idToName.SetItem(result, key),
|
||||
result);
|
||||
}
|
||||
|
||||
public IList<KeyValuePair<DateTime, int>> GetIds(T name) =>
|
||||
nameToId[name];
|
||||
|
||||
public Builder ToBuilder() =>
|
||||
new(this);
|
||||
|
||||
public class Builder {
|
||||
readonly ImmutableDictionary<T, ImmutableList<KeyValuePair<DateTime, int>>>.Builder nameToId;
|
||||
readonly ImmutableDictionary<int, TimeseriesKey<T>>.Builder idToName;
|
||||
int idCounter;
|
||||
|
||||
public Builder(TimeseriesIndex<T> source)
|
||||
: this(source.nameToId, source.idToName, source.idCounter) { }
|
||||
|
||||
public Builder(ImmutableDictionary<T, ImmutableList<KeyValuePair<DateTime, int>>> nameToId, ImmutableDictionary<int, TimeseriesKey<T>> idToName, int idCounter) {
|
||||
this.nameToId = nameToId.ToBuilder();
|
||||
this.idToName = idToName.ToBuilder();
|
||||
this.idCounter = idCounter;
|
||||
}
|
||||
|
||||
public int GetNearest(TimeseriesKey<T> key) =>
|
||||
getOrAdd(key, false, false);
|
||||
|
||||
public int GetNearestOrAdd(TimeseriesKey<T> key) =>
|
||||
getOrAdd(key, false, true);
|
||||
|
||||
public int GetOrAdd(TimeseriesKey<T> key) =>
|
||||
getOrAdd(key, true, true);
|
||||
|
||||
public int GetLatest(T key) =>
|
||||
nameToId.TryGetValue(key, out var ids)
|
||||
? ids[^1].Value
|
||||
: throw new KeyNotFoundException();
|
||||
|
||||
public bool TryGetLatest(T key, out int result) {
|
||||
if (nameToId.TryGetValue(key, out var ids)) {
|
||||
result = ids[^1].Value;
|
||||
return true;
|
||||
}
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public ImmutableList<KeyValuePair<DateTime, int>> GetIds(T name) =>
|
||||
nameToId.TryGetValue(name, out var ids)
|
||||
? ids
|
||||
: ImmutableList<KeyValuePair<DateTime, int>>.Empty;
|
||||
|
||||
public TimeseriesIndex<T> ToImmutable() =>
|
||||
new(nameToId.ToImmutable(), idToName.ToImmutable(), idCounter);
|
||||
|
||||
int getOrAdd(TimeseriesKey<T> key, bool requireExactTimestamp, bool canAdd) {
|
||||
var ids = nameToId.GetOrAdd(key.Name, _ => ImmutableList<KeyValuePair<DateTime, int>>.Empty);
|
||||
int idx = ids.BinarySearch(new(key.Timestamp, 0), idTimeseriesComp);
|
||||
int id;
|
||||
if (idx < 0) {
|
||||
Log.Gen.info($"Adding key to timeseries index ({key.Timestamp}, {key.Name})");
|
||||
// We didn't get an exact match. If requireExactTimestamp is false and a record with an
|
||||
// earlier Timestamp exists, use that. Otherwise, add a new record with this Timestamp.
|
||||
idx = ~idx;
|
||||
if (requireExactTimestamp || idx == 0) {
|
||||
if (!canAdd) {
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
id = ++idCounter;
|
||||
ids = ids.Insert(idx, new(key.Timestamp, id));
|
||||
nameToId[key.Name] = ids;
|
||||
idToName.Add(id, key);
|
||||
} else {
|
||||
if (idx == ids.Count) {
|
||||
--idx;
|
||||
}
|
||||
id = ids[idx].Value;
|
||||
}
|
||||
} else {
|
||||
id = ids[idx].Value;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public readonly record struct TimeseriesKey<T>(T Name, DateTime Timestamp) : IDualComparable<TimeseriesKey<T>> {
|
||||
public int CompareTo(TimeseriesKey<T> other) {
|
||||
var rv = Timestamp.CompareTo(other.Timestamp);
|
||||
if (rv == 0) {
|
||||
rv = Comparer<T>.Default.Compare(Name, other.Name);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static implicit operator (T Name, DateTime Timestamp)(TimeseriesKey<T> key) =>
|
||||
(key.Name, key.Timestamp);
|
||||
|
||||
public static implicit operator TimeseriesKey<T>((T Name, DateTime Timestamp) tup) =>
|
||||
new(tup.Name, tup.Timestamp);
|
||||
}
|
||||
@@ -1,16 +1,261 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using mbts;
|
||||
using BCG;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
internal class MutableAppendTable : IBlueRowCollection {
|
||||
private class MyRow : IBlueRow {
|
||||
private IBlueRow myRow;
|
||||
private int myID;
|
||||
|
||||
using mbts;
|
||||
using BCG;
|
||||
public MyRow(IBlueRow r, int id) {
|
||||
myRow = r;
|
||||
myID = id;
|
||||
}
|
||||
|
||||
#region IBlueRow Members
|
||||
|
||||
public IBlueTableSchema schema { get { return myRow.schema; } }
|
||||
|
||||
public object this[int index] {
|
||||
get {
|
||||
if (myRow.schema[index].colName == "id")
|
||||
return myID;
|
||||
else
|
||||
return myRow[index];
|
||||
}
|
||||
}
|
||||
|
||||
public object this[string colName] { get { return colName == "id" ? (object)myID : myRow[colName]; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDictionary Members
|
||||
|
||||
public void Add(object key, object value) { throw new Exception("Row is read only."); }
|
||||
|
||||
public void Clear() { throw new Exception("Row is read only."); }
|
||||
|
||||
public bool Contains(object key) { return myRow.Contains(key); }
|
||||
|
||||
public System.Collections.IDictionaryEnumerator GetEnumerator() { return new BlueRowDictionaryEnumerator(this); }
|
||||
|
||||
public bool IsFixedSize { get { return true; } }
|
||||
|
||||
public bool IsReadOnly { get { return true; } }
|
||||
|
||||
public System.Collections.ICollection Keys { get { return myRow.Keys; } }
|
||||
|
||||
public void Remove(object key) { throw new Exception("The method or operation is not implemented."); }
|
||||
|
||||
public System.Collections.ICollection Values {
|
||||
get {
|
||||
object[] vals = new object[myRow.Count];
|
||||
CopyTo(vals, 0);
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
|
||||
public object this[object key] {
|
||||
get { return key is string ? this[key as string] : this[(int)key]; }
|
||||
set { throw new Exception("The method or operation is not implemented."); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICollection Members
|
||||
|
||||
public void CopyTo(Array array, int index) {
|
||||
myRow.CopyTo(array, index);
|
||||
array.SetValue(myID, index + myRow.schema["id"].colNo);
|
||||
}
|
||||
|
||||
public int Count { get { return myRow.Count; } }
|
||||
|
||||
public bool IsSynchronized { get { return myRow.IsSynchronized; } }
|
||||
|
||||
public object SyncRoot { get { return myRow.SyncRoot; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable Members
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new BlueRowEnumerator(this); }
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
private BlueTable myRows;
|
||||
private int myID = 0;
|
||||
/// <summary>
|
||||
/// maps the table no to a dictionary containing the
|
||||
/// local IDs to a row in the final big table
|
||||
/// </summary>
|
||||
private Dictionary<int, Dictionary<int, IBlueRow>> myIDMap = new Dictionary<int, Dictionary<int, IBlueRow>>();
|
||||
|
||||
public MutableAppendTable(IBlueTableSchema schema) { myRows = new BlueTable(schema); }
|
||||
|
||||
public IBlueRow addRow(IBlueRow r, int tableNo) {
|
||||
if (!myIDMap.ContainsKey(tableNo))
|
||||
myIDMap.Add(tableNo, new Dictionary<int, IBlueRow>());
|
||||
IBlueRow nr = new MyRow(r, myID++); // BlueDataUtility.getNewReplacedRow(r, myID++, "id");
|
||||
myRows.addRow(nr);
|
||||
myIDMap[tableNo].Add((int)r["id"], nr);
|
||||
return nr;
|
||||
}
|
||||
|
||||
public IBlueRow removeRow(IBlueRow r, int tableNo) {
|
||||
IBlueRow dr = myIDMap[tableNo][(int)r["id"]];
|
||||
myRows.deleteRow(dr);
|
||||
myIDMap[tableNo].Remove((int)r["id"]);
|
||||
return dr;
|
||||
}
|
||||
|
||||
public IBlueRowCollection removeTable(int tableNo) {
|
||||
if (!myIDMap.ContainsKey(tableNo))
|
||||
return null;
|
||||
else {
|
||||
BlueTable rv = new BlueTable(myRows.schema);
|
||||
foreach (IBlueRow r in myIDMap[tableNo].Values)
|
||||
rv.addRow(r);
|
||||
myRows.deleteRows(rv);
|
||||
myIDMap.Remove(tableNo);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myRows.clear();
|
||||
myIDMap.Clear();
|
||||
}
|
||||
|
||||
#region IBlueRowCollection Members
|
||||
|
||||
public IBlueRow this[int id] { get { return myRows[id]; } }
|
||||
|
||||
public IBlueTableSchema schema { get { return myRows.schema; } }
|
||||
|
||||
public bool containsID(int id) { return myRows.containsID(id); }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICollection Members
|
||||
|
||||
public void CopyTo(Array array, int index) { myRows.CopyTo(array, index); }
|
||||
|
||||
public int Count { get { return myRows.Count; } }
|
||||
|
||||
public bool IsSynchronized { get { return myRows.IsSynchronized; } }
|
||||
|
||||
public object SyncRoot { get { return myRows.SyncRoot; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region IEnumerable Members
|
||||
|
||||
public System.Collections.IEnumerator GetEnumerator() { return myRows.GetEnumerator(); }
|
||||
|
||||
#endregion
|
||||
}
|
||||
/// <summary>
|
||||
/// MutableStream can append multiple streams
|
||||
/// as well as give the user the flexibility
|
||||
/// to append (or remove) more streams at
|
||||
/// runtime
|
||||
/// </summary>
|
||||
}
|
||||
namespace bts.BlueOrb {
|
||||
[DataStreamUserRespresentation("UnionStream")]
|
||||
public class UnionStream : ViewStream {
|
||||
public UnionStream(ViewStream left_stream, ViewStream right_stream) {
|
||||
ViewStream rs = new BCG.MutableAppendStream(left_stream, right_stream);
|
||||
mySetRealSource(rs);
|
||||
public class MutableAppendStream : ViewStream {
|
||||
private bool mySubscriptionActive = false;
|
||||
private MutableAppendTable myTable;
|
||||
private int myMovingIndex;
|
||||
private Dictionary<int, Pair<ViewStream, ViewStream>> myStreamIndex = new Dictionary<int, Pair<ViewStream, ViewStream>>();
|
||||
private bool _allign_col_orders = true;
|
||||
|
||||
public MutableAppendStream(params ViewStream[] streams)
|
||||
: this(new List<ViewStream>(streams)) { }
|
||||
|
||||
public MutableAppendStream(bool allign_col_order, params ViewStream[] streams)
|
||||
: this(allign_col_order, new List<ViewStream>(streams)) { }
|
||||
|
||||
public MutableAppendStream(ICollection<ViewStream> streams)
|
||||
: this(true, streams) { }
|
||||
|
||||
public MutableAppendStream(bool allign_col_orders, ICollection<ViewStream> streams) {
|
||||
_allign_col_orders = allign_col_orders;
|
||||
foreach (ViewStream vs in streams) {
|
||||
myMovingIndex++;
|
||||
ViewStream pj = new ChangeTableNameStream(vs, myMovingIndex.ToString());
|
||||
if (_allign_col_orders)
|
||||
pj = new ProjectStream(pj, "!");
|
||||
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
|
||||
}
|
||||
}
|
||||
|
||||
public void addStream(ViewStream vs) {
|
||||
myMovingIndex++;
|
||||
///the change name is done to identify the callbacks, and the project to
|
||||
///make all the schemas col orders the same
|
||||
ViewStream pj = new ChangeTableNameStream(vs, myMovingIndex.ToString());
|
||||
if (_allign_col_orders)
|
||||
pj = new ProjectStream(pj, "!");
|
||||
myStreamIndex.Add(myMovingIndex, new Pair<ViewStream, ViewStream>(vs, pj));
|
||||
if (mySubscriptionActive)
|
||||
pj.onChange += new ChangeDelegate(myHandleStreamChanges);
|
||||
}
|
||||
|
||||
public void removeStream(ViewStream vs) {
|
||||
int index = -1;
|
||||
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex) {
|
||||
if (p.Value.first == vs) {
|
||||
index = p.Key;
|
||||
if (mySubscriptionActive) {
|
||||
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
|
||||
if (myTable != null) {
|
||||
IBlueRowCollection delRows = myTable.removeTable(p.Key);
|
||||
if (delRows != null)
|
||||
myFireEvent(new DataPacket(myTable, new BlueTable(myTable.schema), delRows));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (index > 0)
|
||||
myStreamIndex.Remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
mySubscriptionActive = true;
|
||||
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
|
||||
p.Value.second.onChange += new ChangeDelegate(myHandleStreamChanges);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
mySubscriptionActive = false;
|
||||
foreach (KeyValuePair<int, Pair<ViewStream, ViewStream>> p in myStreamIndex)
|
||||
p.Value.second.onChange -= new ChangeDelegate(myHandleStreamChanges);
|
||||
if (myTable != null)
|
||||
myTable.clear();
|
||||
}
|
||||
|
||||
private void myHandleStreamChanges(object newValue) {
|
||||
DataPacket dp = newValue as DataPacket;
|
||||
myTable = myTable ?? new MutableAppendTable(new BlueTableSchema("MutableAppend", dp.schema.columnInfo));
|
||||
BlueTable adds = new BlueTable(myTable.schema),
|
||||
dels = new BlueTable(myTable.schema);
|
||||
int index = Int32.Parse(dp.schema.tableName);
|
||||
foreach (IBlueRow r in dp.deletedRows) {
|
||||
IBlueRow dr = myTable.removeRow(r, index);
|
||||
dels.addRow(dr);
|
||||
}
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
IBlueRow nr = myTable.addRow(r, index);
|
||||
adds.addRow(nr);
|
||||
}
|
||||
myFireEvent(new DataPacket(myTable, adds, dels));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,11 +17,12 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.57" />
|
||||
<PackageReference Include="IronPython" Version="3.4.2" />
|
||||
<PackageReference Include="Microsoft.Data.Analysis" Version="0.21.1" />
|
||||
<PackageReference Include="MongoDB.Bson" Version="2.23.1" />
|
||||
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
|
||||
<PackageReference Include="ParquetSharp" Version="20.0.0" />
|
||||
<PackageReference Include="Parquet.Net" Version="5.0.1" />
|
||||
<PackageReference Include="System.Data.SQLite" Version="1.0.118" />
|
||||
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -2,277 +2,25 @@ namespace Bts.DataStream;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
using bts.api.core;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.PubSub;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
using Spark.Core.Threading;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class DataStreamExtensions {
|
||||
public static ViewStream AsViewStream<T>(this IObservable<IDataPacket<T>> source, string? name = null, ILogger? logger = null) where T : IBlueRow =>
|
||||
source as ViewStream ?? new ObservableViewStream(source.Select(dp => new DataPacket(dp.newRows, dp.addedRows, dp.deletedRows)), name, logger);
|
||||
public static ViewStream AsViewStream(this IObservable<DataPacket> source) =>
|
||||
source as ViewStream ?? new ObservableViewStream(source);
|
||||
|
||||
// public static IObservable<IDataPacket<T>> SelectDataPacket<T>(this IObservable<IDataPacket> source, Func<IBlueRow, T> selector) where T : IBlueRow =>
|
||||
// source.Select(dp => {
|
||||
// dp.get_new_added_deleted(out var newRows, out var addedRows, out var deletedRows);
|
||||
// return new DataPacket<T>(CastRows(newRows), CastRows(addedRows), CastRows(deletedRows));
|
||||
public static IObservable<DataPacket> AsObservable(this ViewStream source) {
|
||||
return source as IObservable<DataPacket> ?? Observable.Create<DataPacket>(Subscribe);
|
||||
|
||||
// IBlueRowCollection<T> CastRows(ICollection rows) =>
|
||||
// new BlueTableSelectorWrapper<T>(
|
||||
// rows as IBlueRowCollection ?? new BlueRowCollection(rows, dp.Schema), selector);
|
||||
// });
|
||||
IDisposable Subscribe(IObserver<DataPacket> observer) {
|
||||
source.onChange += OnChange;
|
||||
return Disposable.Create(() => source.onChange -= OnChange);
|
||||
|
||||
public static IObservable<TableUpdate<IBlueRow, int>> AsTables(this IObservable<IDataPacket> source) =>
|
||||
source.AsTables<IBlueRow, int>(r => r, r => r.Id());
|
||||
|
||||
public static IObservable<TableUpdate<T, int>> AsTables<T>(this IObservable<IDataPacket> source, Func<IBlueRow, T> valueSelector) where T : IBlueRow =>
|
||||
source.AsTables<T, int>(valueSelector, r => r.Id());
|
||||
|
||||
public static IObservable<TableUpdate<T, int>> AsTables<T>(
|
||||
this IObservable<IDataPacket> source, Func<IBlueRow, T> valueSelector, Func<T, int> keySelector) =>
|
||||
source.AsTables<T, int>(valueSelector, keySelector);
|
||||
|
||||
public static IObservable<TableUpdate<T, TKey>> AsTables<T, TKey>(
|
||||
this IObservable<IDataPacket> source, Func<IBlueRow, T> valueSelector, Func<T, TKey> keySelector, Func<IBlueRow, TKey>? rowKeySelector = null) where TKey : IEquatable<TKey> {
|
||||
rowKeySelector ??= r => keySelector(valueSelector(r));
|
||||
return source.Scan(TableUpdate<T, TKey>.mk_empty(keySelector), (res, dp) => {
|
||||
var bd = res.to_builder();
|
||||
dp.get_new_added_deleted(out var newRows, out var addedRows, out var deletedRows);
|
||||
foreach (IBlueRow r in addedRows) {
|
||||
bd.add_or_update(valueSelector(r));
|
||||
}
|
||||
foreach (IBlueRow r in deletedRows) {
|
||||
bd.remove(rowKeySelector(r));
|
||||
}
|
||||
return bd.to_table();
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<IDataPacket> AsDataPackets(this IObservable<TableUpdate<IBlueRow, int>> source) =>
|
||||
source.Scan(
|
||||
(Table: (BlueTableImmutable?)null, Dp: (IDataPacket?)null),
|
||||
(res, table) => {
|
||||
var resTable = res.Table;
|
||||
if (resTable is null) {
|
||||
if (table.state.Count == 0) {
|
||||
return (null, null);
|
||||
}
|
||||
resTable = new(table.state.Values.First().schema);
|
||||
}
|
||||
var bd = resTable.ToDataPacketBuilder();
|
||||
foreach (var r in table.removed) {
|
||||
bd.Remove(r.Id());
|
||||
}
|
||||
foreach (var r in table.added) {
|
||||
bd.AddOrUpdate(r);
|
||||
}
|
||||
var resDp = bd.ToDataPacket(out var newRows);
|
||||
return (newRows, resDp);
|
||||
})
|
||||
.Where(t => t.Dp is not null && (t.Dp.addedRows.Count > 0 || t.Dp.deletedRows.Count > 0))
|
||||
.Select(t => t.Dp!);
|
||||
|
||||
public static IObservable<IDataPacket> AsDataPackets<T>(this IObservable<TableUpdate<T, int>> source, IBlueTableSchema schema) where T : IBlueRow =>
|
||||
source.Scan(
|
||||
(Table: new BlueTableImmutable(schema), Dp: (IDataPacket)new DataPacket(schema)),
|
||||
(res, table) => {
|
||||
var bd = res.Table.ToDataPacketBuilder();
|
||||
foreach (var r in table.removed) {
|
||||
bd.Remove(r.Id());
|
||||
}
|
||||
foreach (var r in table.added) {
|
||||
bd.AddOrUpdate(r);
|
||||
}
|
||||
var resDp = bd.ToDataPacket(out var newRows);
|
||||
return (newRows, resDp);
|
||||
})
|
||||
.Where(t => t.Dp.addedRows.Count > 0 || t.Dp.deletedRows.Count > 0)
|
||||
.Select(t => t.Dp);
|
||||
|
||||
public static IObservable<IDataPacket> AsDataPackets<T, TKey>(this IObservable<TableUpdate<T, TKey>> source, BlueTableSchemaAdapter<T> schema) where TKey : IEquatable<TKey> {
|
||||
return Observable.Create<IDataPacket>(Subscribe);
|
||||
|
||||
IDisposable Subscribe(IObserver<IDataPacket> o) {
|
||||
var adapter = new BlueTableImmutableAdapter<T>(schema);
|
||||
IDataPacket initDataPacket = new DataPacket(schema);
|
||||
return source.Scan((Adapter: adapter, DataPacket: initDataPacket), OnUpdate).Select(res => res.DataPacket).Subscribe(o);
|
||||
|
||||
(BlueTableImmutableAdapter<T> Adapter, IDataPacket DataPacket) OnUpdate(
|
||||
(BlueTableImmutableAdapter<T> Adapter, IDataPacket DataPacket) state, TableUpdate<T, TKey> tableUpdate) {
|
||||
var bd = state.Adapter.ToDataPacketBuilder();
|
||||
bd.Update(tableUpdate);
|
||||
var newRows = bd.ToImmutable(out var dp);
|
||||
return (newRows, dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ViewStream AsViewStream<T>(this IObservable<TableUpdate<T, int>> source, IBlueTableSchema schema) where T : IBlueRow =>
|
||||
source.AsDataPackets(schema).AsViewStream();
|
||||
|
||||
public static IObservable<IDataPacket> OnWorkScheduler(this IObservable<IDataPacket> source, IWorkScheduler scheduler) =>
|
||||
Observable.Create<IDataPacket>(o => {
|
||||
var inputGate = new AtomicGate();
|
||||
var outputGate = new AtomicGate();
|
||||
BlueTableImmutable? lastTable = null;
|
||||
BlueTableImmutable.DataPacketBuilder? bd = null;
|
||||
IDataPacket? pendingDpOut = null;
|
||||
return Disposable.Create(source.Subscribe(OnNext), scheduler.Subscribe(DoWork));
|
||||
|
||||
void OnNext(IDataPacket value) {
|
||||
using (inputGate.BeginTransaction()) {
|
||||
lastTable ??= new(value.newRows.schema);
|
||||
bd ??= lastTable.ToDataPacketBuilder();
|
||||
if (pendingDpOut is null) {
|
||||
// The last outgoing datapacket was just fired. Don't merge this update with the
|
||||
// previous one (otherwise its adds/removes would be fired twice).
|
||||
bd.Reset();
|
||||
}
|
||||
foreach (IBlueRow r in value.deletedRows) {
|
||||
bd.Remove(r.Id());
|
||||
}
|
||||
foreach (IBlueRow r in value.addedRows) {
|
||||
bd.AddOrUpdate(r);
|
||||
}
|
||||
pendingDpOut = bd.ToDataPacket(out lastTable, false);
|
||||
}
|
||||
}
|
||||
|
||||
void DoWork() {
|
||||
IDataPacket? dpOut = null;
|
||||
if (outputGate.TryEnter()) {
|
||||
using var exit = Disposable.Create(outputGate.Exit);
|
||||
(dpOut, pendingDpOut) = (pendingDpOut, dpOut);
|
||||
if (dpOut is not null) {
|
||||
o.OnNext(dpOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
public static IObservable<IDataPacket> NonIncrementalAsyncTransform(this IObservable<IDataPacket> source, Func<IBlueRowCollection, Task<IBlueRowCollection?>> transformAsync, IWorkScheduler workScheduler) {
|
||||
const int STATE_IDLE = 0;
|
||||
const int STATE_BUSY = 1;
|
||||
const int STATE_DISPOSED = 2;
|
||||
return Observable.Create<IDataPacket>(Subscribe);
|
||||
IDisposable Subscribe(IObserver<IDataPacket> o) {
|
||||
var syncRoot = new object();
|
||||
IBlueRowCollection? lastTableIn = null;
|
||||
BlueTableImmutable? lastTableOut = null;
|
||||
int nConcurrentDoWorks = 0;
|
||||
int state = STATE_IDLE;
|
||||
IDisposable? dispose = null;
|
||||
dispose = Disposable.Create(source.Subscribe(OnNext), workScheduler.Subscribe(DoWork));
|
||||
return Disposable.Create(Dispose);
|
||||
|
||||
void Dispose() {
|
||||
lock (syncRoot) {
|
||||
switch (state) {
|
||||
case STATE_DISPOSED:
|
||||
return;
|
||||
case STATE_BUSY:
|
||||
state = STATE_DISPOSED;
|
||||
return;
|
||||
}
|
||||
state = STATE_DISPOSED;
|
||||
}
|
||||
Disposable.dispose(ref dispose);
|
||||
}
|
||||
|
||||
void OnNext(IDataPacket value) =>
|
||||
Volatile.Write(ref lastTableIn, value.newRows);
|
||||
|
||||
async void DoWork() {
|
||||
lock (syncRoot) {
|
||||
nConcurrentDoWorks++;
|
||||
switch (state) {
|
||||
case STATE_DISPOSED:
|
||||
case STATE_BUSY:
|
||||
return;
|
||||
case STATE_IDLE:
|
||||
break;
|
||||
default:
|
||||
Log.assert(false, $"Unexpected state ({StateName(state)}) when DoWork called");
|
||||
return;
|
||||
}
|
||||
state = STATE_BUSY;
|
||||
}
|
||||
var dp = await PublishTable();
|
||||
bool isDisposed = false;
|
||||
lock (syncRoot) {
|
||||
switch (state) {
|
||||
case STATE_DISPOSED:
|
||||
isDisposed = true;
|
||||
break;
|
||||
case STATE_BUSY:
|
||||
break;
|
||||
default:
|
||||
Log.assert(false, $"Unexpected state ({StateName(state)}) after building output table (async)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isDisposed) {
|
||||
Disposable.dispose(ref dispose);
|
||||
return;
|
||||
}
|
||||
if (dp is not null) {
|
||||
o.OnNext(dp);
|
||||
}
|
||||
lock (syncRoot) {
|
||||
nConcurrentDoWorks = 0;
|
||||
switch (state) {
|
||||
case STATE_DISPOSED:
|
||||
isDisposed = true;
|
||||
break;
|
||||
case STATE_BUSY:
|
||||
state = STATE_IDLE;
|
||||
break;
|
||||
default:
|
||||
Log.assert(false, $"Unexpected state ({StateName(state)}) after firing output table");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (isDisposed) {
|
||||
Disposable.dispose(ref dispose);
|
||||
}
|
||||
|
||||
async Task<DataPacket?> PublishTable() {
|
||||
var tableIn = Interlocked.Exchange(ref lastTableIn, null);
|
||||
if (tableIn is null) {
|
||||
return null;
|
||||
}
|
||||
var tableOut = await transformAsync(tableIn);
|
||||
if (tableOut is null) {
|
||||
return null;
|
||||
}
|
||||
lastTableOut ??= new(tableOut.schema);
|
||||
var bd = lastTableOut.ToDataPacketBuilder();
|
||||
bd.Clear();
|
||||
foreach (IBlueRow r in tableOut) {
|
||||
bd.AddOrUpdate(r, BlueRowEqualityComparer.Instance);
|
||||
}
|
||||
return bd.ToDataPacket(out lastTableOut);
|
||||
}
|
||||
}
|
||||
|
||||
static string StateName(int state) =>
|
||||
state switch {
|
||||
STATE_IDLE => "IDLE",
|
||||
STATE_BUSY => "BUSY",
|
||||
STATE_DISPOSED => "DISPOSED",
|
||||
_ => $"STATE_{state}",
|
||||
};
|
||||
void OnChange(object? newValue) =>
|
||||
observer.OnNext(newValue as DataPacket ?? throw new ArgumentException(
|
||||
$"Expected DataPacket, got {newValue?.GetType()}", nameof(newValue)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
namespace bts.BlueOrb {
|
||||
namespace bts.SilverPine {
|
||||
using System;
|
||||
using BCG;
|
||||
using System.Collections.Generic;
|
||||
using Bts.DataStreamExpressions;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
// All this does is take in a dsl expression, parse it and fire the data that come out of running it.
|
||||
// So for example, if an expresison is passed
|
||||
[DataStreamUserRespresentation("dsl")]
|
||||
public class DSLStream : ViewStream {
|
||||
private readonly string _dsl;
|
||||
public DSLStream(string dsl, IDataStreamFactory streamFactory) {
|
||||
public DSLStream(string dsl) {
|
||||
Log.Gen.info($"DSLStream.cons dsl: {dsl}");
|
||||
_dsl = dsl;
|
||||
var rs = build_stream(streamFactory, dsl) ?? new LiteralStream("error", $"msg:invalid dsl");
|
||||
ViewStream rs = build_stream(dsl);
|
||||
rs = rs ?? new LiteralStream("error", $"msg:invalid dsl \"{dsl}\"");
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
static ViewStream? build_stream(IDataStreamFactory streamFactory, string stream_expression) {
|
||||
static ViewStream? build_stream(string stream_expression) {
|
||||
try {
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
|
||||
return rv;
|
||||
|
||||
} catch (Exception ex) {
|
||||
@@ -29,4 +29,4 @@ namespace bts.BlueOrb {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ namespace BCG {
|
||||
protected override void myOnFirstSubscriber() {
|
||||
MasterWorker.getInstance(false).addWorker(this, _send_period);
|
||||
var server_rci = new RemoteConnectionInfo(_ip, _port);
|
||||
bts.AsyncTCPConnector_AsyncWrapper.connect_to(server_rci, this);
|
||||
bts.AsyncTCPConnector_APM.connect_to(server_rci, this);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
@@ -76,4 +76,4 @@ namespace BCG {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
|
||||
using System;
|
||||
|
||||
public class ObservableViewStream : ViewStream, IObservable<DataPacket>, IDisposable {
|
||||
readonly IObservable<DataPacket> source;
|
||||
IDisposable? subscription;
|
||||
|
||||
public ObservableViewStream(IObservable<DataPacket> source) =>
|
||||
this.source = source;
|
||||
|
||||
public void Dispose() {
|
||||
GC.SuppressFinalize(this);
|
||||
if (subscription is not null) {
|
||||
subscription.Dispose();
|
||||
subscription = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Log.isnull(subscription);
|
||||
subscription = source.Subscribe(myFireEvent);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
Log.notnull(subscription);
|
||||
subscription.Dispose();
|
||||
subscription = null;
|
||||
}
|
||||
|
||||
IDisposable IObservable<DataPacket>.Subscribe(IObserver<DataPacket> observer) =>
|
||||
source.Subscribe(observer);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Bts.DataStreamExpressions;
|
||||
using BCG.Utilities.General;
|
||||
using bts;
|
||||
|
||||
namespace BCG {
|
||||
// listens to the requests posted on "cloud_streams" request table, and
|
||||
// if unfulfilled starts a ViewPubsliher
|
||||
public class RemoteQueryManager : IWorker {
|
||||
public class StreamPubUnit {
|
||||
public string name;
|
||||
public string stream_expression;
|
||||
public ViewStream stream;
|
||||
public bool persist;
|
||||
public ViewPublisher view_publisher;
|
||||
|
||||
public StreamPubUnit(string name_, string stream_expression_, ViewStream stream_, bool persist_, ViewPublisher view_publisher_) {
|
||||
name = name_;
|
||||
stream_expression = stream_expression_;
|
||||
stream = stream_;
|
||||
persist = persist_;
|
||||
view_publisher = view_publisher_;
|
||||
}
|
||||
}
|
||||
static ViewStream? build_stream(string stream_expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
|
||||
return rv;
|
||||
|
||||
} catch (Exception ex) {
|
||||
bts.Log.assert(false, $"Could not build stream: {stream_expression} ex: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private IDictionary<string, StreamPubUnit>
|
||||
_stream_pub_map = new Dictionary<string, StreamPubUnit>();
|
||||
private ViewStream _stream = new TableStream("cloud_streams");
|
||||
private PubTableBroker _broker = new PubTableBroker();
|
||||
private ManagedSubscriber _sub = ManagedSubscriber.instance;
|
||||
|
||||
|
||||
public RemoteQueryManager() {
|
||||
_stream.onChange += _on_str;
|
||||
_sub.subscribe("RemoteRequest", (string tag, byte[] data) => {
|
||||
RemoteRequest req = RemoteRequest.construct_from_bytes(data);
|
||||
_spawn_remote_stream(req.published_table_name, req.stream_expression, false);
|
||||
});
|
||||
}
|
||||
private void _on_str(object obj)
|
||||
{
|
||||
if (obj is not DataPacket dp) {
|
||||
return;
|
||||
}
|
||||
foreach (IBlueRow r in dp.newRows)
|
||||
{
|
||||
string name = r.get<string>("name");
|
||||
bool persist = r.get<bool>("persist");
|
||||
string stream_exp = r.get<string>("stream_exp");
|
||||
if (!_stream_pub_map.ContainsKey(name)) {
|
||||
_spawn_remote_stream(name, stream_exp, persist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _spawn_remote_stream(string name, string stream_expression, bool persist) {
|
||||
bts.Log.Gen.info($"CloudStreamManager.assign name: {name} stream_expression: {stream_expression}");
|
||||
ViewStream stream = build_stream(stream_expression);
|
||||
_expose_to_ws(name, stream);
|
||||
if (persist) {
|
||||
stream = new PersistorStream(stream, name, "C:\\Temp\\", 1000000); // 10MBs
|
||||
}
|
||||
ViewPublisher view_pub = new ViewPublisher(name, _broker, stream);
|
||||
StreamPubUnit u = new StreamPubUnit(name, stream_expression, stream, persist, view_pub);
|
||||
_stream_pub_map.Add(name, u);
|
||||
}
|
||||
|
||||
private void _expose_to_ws(string name, ViewStream stream) {
|
||||
// TODO: john
|
||||
}
|
||||
|
||||
public void doWork() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
using bts;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamExpressions;
|
||||
using Bts.PubSub;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BCG {
|
||||
// listens to the requests posted on "cloud_streams" request table, and
|
||||
// if unfulfilled starts a ViewPubsliher
|
||||
public class RemoteQueryManager : IHostedService {
|
||||
public class StreamPubUnit {
|
||||
public string name;
|
||||
public string stream_expression;
|
||||
public ViewStream stream;
|
||||
public bool persist;
|
||||
public ViewPublisher view_publisher;
|
||||
|
||||
public StreamPubUnit(string name_, string stream_expression_, ViewStream stream_, bool persist_, ViewPublisher view_publisher_) {
|
||||
name = name_;
|
||||
stream_expression = stream_expression_;
|
||||
stream = stream_;
|
||||
persist = persist_;
|
||||
view_publisher = view_publisher_;
|
||||
}
|
||||
}
|
||||
static ViewStream? build_stream(IDataStreamFactory streamFactory, string stream_expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0), streamFactory);
|
||||
return rv;
|
||||
|
||||
} catch (Exception ex) {
|
||||
bts.Log.assert(false, $"Could not build stream: {stream_expression} ex: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private IDictionary<string, StreamPubUnit>
|
||||
_stream_pub_map = new Dictionary<string, StreamPubUnit>();
|
||||
readonly IPubTableBroker _broker;
|
||||
readonly IManagedSubscriber _sub;
|
||||
readonly IDataStreamFactory streamFactory;
|
||||
readonly ITableStreamFactory tableStreamFactory;
|
||||
readonly object syncRoot = new();
|
||||
IDisposable? cloudStreamsSub;
|
||||
IDisposable? remoteRequestsSub;
|
||||
State state;
|
||||
|
||||
public RemoteQueryManager(IManagedSubscriber managedSubscriber, IPubTableBroker pubTableBroker, ITableStreamFactory tableStreamFactory, IEnumerable<IDataStreamFactory> streamFactories) {
|
||||
_sub = managedSubscriber;
|
||||
_broker = pubTableBroker;
|
||||
this.tableStreamFactory = tableStreamFactory;
|
||||
var streamFactoryList = streamFactories.ToList();
|
||||
streamFactory = streamFactoryList.Count == 1
|
||||
? streamFactoryList[0]
|
||||
: new CompositeDataStreamFactory(streamFactoryList);
|
||||
}
|
||||
|
||||
enum State {
|
||||
Idle = 0,
|
||||
Running = 1,
|
||||
Disposed = 2,
|
||||
WaitingToDispose = 3,
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken) {
|
||||
lock (syncRoot) {
|
||||
switch (state) {
|
||||
case State.Idle:
|
||||
break;
|
||||
case State.WaitingToDispose:
|
||||
case State.Disposed:
|
||||
throw new ObjectDisposedException(nameof(RemoteQueryManager));
|
||||
default:
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
state = State.Running;
|
||||
}
|
||||
if (cloudStreamsSub is not null) {
|
||||
throw new InvalidOperationException("cloudStreamsSub already created");
|
||||
}
|
||||
if (remoteRequestsSub is not null) {
|
||||
throw new InvalidOperationException("remoteRequestsSub already created");
|
||||
}
|
||||
var cloudStream = tableStreamFactory.Create("cloud_streams")
|
||||
?? throw new Exception("Failed to create TableStream 'cloud_stream'");
|
||||
cloudStreamsSub = cloudStream.AsObservable().Subscribe(_on_str);
|
||||
remoteRequestsSub = _sub.Observe("RemoteRequest").Subscribe(data => {
|
||||
RemoteRequest req = RemoteRequest.construct_from_bytes(data);
|
||||
_spawn_remote_stream(req.published_table_name, req.stream_expression, false);
|
||||
});
|
||||
lock (syncRoot) {
|
||||
if (state == State.WaitingToDispose) {
|
||||
state = State.Disposed;
|
||||
}
|
||||
}
|
||||
if (state == State.Disposed) {
|
||||
Disposable.dispose(ref cloudStreamsSub);
|
||||
Disposable.dispose(ref remoteRequestsSub);
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) {
|
||||
lock (syncRoot) {
|
||||
switch (state) {
|
||||
case State.Running:
|
||||
break;
|
||||
default:
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
state = State.Disposed;
|
||||
}
|
||||
Disposable.dispose(ref cloudStreamsSub);
|
||||
Disposable.dispose(ref remoteRequestsSub);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void _on_str(IDataPacket dp)
|
||||
{
|
||||
foreach (IBlueRow r in dp.newRows)
|
||||
{
|
||||
string name = r.get<string>("name");
|
||||
bool persist = r.get<bool>("persist");
|
||||
string stream_exp = r.get<string>("stream_exp");
|
||||
if (!_stream_pub_map.ContainsKey(name)) {
|
||||
_spawn_remote_stream(name, stream_exp, persist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _spawn_remote_stream(string name, string stream_expression, bool persist) {
|
||||
bts.Log.Gen.info($"CloudStreamManager.assign name: {name} stream_expression: {stream_expression}");
|
||||
var stream = build_stream(streamFactory, stream_expression);
|
||||
if (stream is null) {
|
||||
Log.DataFlow.error($"Failed to spawn remote stream. name: {name}; expression: {stream_expression}");
|
||||
return;
|
||||
}
|
||||
_expose_to_ws(name, stream);
|
||||
if (persist) {
|
||||
string tempDir = Path.GetTempPath();
|
||||
Directory.CreateDirectory(tempDir); // make sure it exists
|
||||
|
||||
stream = new PersistorStream(stream, name, tempDir, 10_000_000); // 10 MB
|
||||
}
|
||||
ViewPublisher view_pub = new ViewPublisher(name, _broker, stream);
|
||||
StreamPubUnit u = new StreamPubUnit(name, stream_expression, stream, persist, view_pub);
|
||||
_stream_pub_map.Add(name, u);
|
||||
}
|
||||
|
||||
private void _expose_to_ws(string name, ViewStream stream) {
|
||||
// TODO: john
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,30 +2,17 @@ using BCG;
|
||||
|
||||
using bts;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
|
||||
namespace BCG {
|
||||
/// <summary>
|
||||
/// This is a stream so we can run it from the DSQA (since dsqa can only load streams).
|
||||
/// <para>
|
||||
/// Note: It's hidden because this stream is now created by an IDataStreamFactory
|
||||
/// (see RemoteQueryStreamFactory.cs for details)
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[DataStreamUserRespresentation(false)]
|
||||
// this is a stream so we can run it from the DSQA (since dsqa can only load streams)
|
||||
[DataStreamUserRespresentation("remoteQuery")]
|
||||
public class RemoteQueryStream : ViewStream {
|
||||
private readonly string _name, _stream_exp;
|
||||
readonly ITableStreamFactory tableStreamFactory;
|
||||
readonly IPublisherCore _publisher_core;
|
||||
IDisposable? subscription;
|
||||
private PublisherCore _publisher_core = new PublisherCore();
|
||||
private ViewStream _source_str;
|
||||
|
||||
public RemoteQueryStream(ITableStreamFactory tableStreamFactory, IPublisherCore publisherCore, params string[] lines) {
|
||||
this.tableStreamFactory = tableStreamFactory;
|
||||
_publisher_core = publisherCore;
|
||||
public RemoteQueryStream(params string[] lines) {
|
||||
_stream_exp = get_expression(lines);
|
||||
_name = Guid.NewGuid().ToString();
|
||||
_name = $"remotereq_{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString()}";
|
||||
@@ -34,17 +21,17 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Log.isnull(subscription);
|
||||
RemoteRequest rem_req = new RemoteRequest(_stream_exp, _name);
|
||||
byte[] rem_req_bytes = rem_req.serialize();
|
||||
_publisher_core.publish("System", "RemoteRequest", rem_req_bytes);
|
||||
var sourceStream = tableStreamFactory.Create(_name);
|
||||
sourceStream.onChange += _handle_data;
|
||||
subscription = Disposable.Create(() => sourceStream.onChange -= _handle_data);
|
||||
_source_str = new TableStream(_name);
|
||||
_source_str.onChange += new ChangeDelegate(_handle_data);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() =>
|
||||
Disposable.dispose(ref subscription);
|
||||
protected override void myOnLastSubscriber() {
|
||||
//maybe there should be a way to turn remote requests off ?
|
||||
_source_str.onChange -= new ChangeDelegate(_handle_data);
|
||||
}
|
||||
|
||||
static string get_expression(params string[] lines) {
|
||||
for (int i = 0; i < lines.Length; i++) {
|
||||
|
||||
@@ -1,51 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BCG {
|
||||
namespace BCG {
|
||||
public class AddColumnsStream : ViewStream {
|
||||
public static Tuple<string, Type, object> parse_single_tok(string exp) {
|
||||
public static Tuple<string, Type, object> parse_exp(string exp) {
|
||||
string[] toks = exp.Split(':');
|
||||
string col_name = toks[0].Trim();
|
||||
string col_value = toks[1].Trim();
|
||||
string col_name = toks[0];
|
||||
string col_value = toks[1];
|
||||
Tuple<Type, object> tup = BlueDataUtility.guess_type(col_value);
|
||||
return Tuple.Create(col_name, tup.Item1, tup.Item2);
|
||||
}
|
||||
|
||||
public static List<Tuple<string, Type, object>> parse_exp(string exp) {
|
||||
string[] toks = exp.Split(",");
|
||||
List<Tuple<string, Type, object>> rv = new List<Tuple<string, Type, object>>();
|
||||
foreach (string s in toks) {
|
||||
var tup = parse_single_tok(s.Trim());
|
||||
rv.Add(tup);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private Tuple<string, Type, object> _new_col;
|
||||
private List<Tuple<string, Type, object>> _new_col_map;
|
||||
private IBlueTableSchema _out_schema;
|
||||
|
||||
public AddColumnsStream(ViewStream vs, string col_def) {
|
||||
_new_col_map = parse_exp(col_def);
|
||||
_new_col = parse_exp(col_def);
|
||||
ViewStream rs = new MapStream(vs, (IBlueTableSchema s) => _get_schema(s), (IBlueRow r) => _map(r));
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
private IBlueTableSchema _get_schema(IBlueTableSchema input_schema) {
|
||||
if (_out_schema == null) {
|
||||
_out_schema = input_schema;
|
||||
foreach (var m in _new_col_map) {
|
||||
_out_schema = BlueDataUtility.add_column(_out_schema, m.Item1, m.Item2);
|
||||
}
|
||||
}
|
||||
if (_out_schema == null)
|
||||
_out_schema = BlueDataUtility.add_column(input_schema, _new_col.Item1, _new_col.Item2);
|
||||
return _out_schema;
|
||||
}
|
||||
|
||||
private IBlueRow _map(IBlueRow r) {
|
||||
MutableBlueRow rv = new MutableBlueRow(_get_schema(r.schema), r);
|
||||
foreach (var m in _new_col_map) {
|
||||
rv.setValue(m.Item1, m.Item3);
|
||||
}
|
||||
rv.setValue(_new_col.Item1, _new_col.Item3);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
|
||||
namespace bts.BlueOrb {
|
||||
using BCG;
|
||||
[DataStreamUserRespresentation("oldCount")]
|
||||
[DataStreamUserRespresentation("CountStream")]
|
||||
public class CountStream : ViewStream {
|
||||
private DataPacket myLastFiredDataPacket;
|
||||
private IBlueTableSchema mySchema = new BlueTableSchema("count",
|
||||
@@ -15,6 +15,9 @@ namespace bts.BlueOrb {
|
||||
myVS = vs;
|
||||
}
|
||||
|
||||
public CountStream(string tableName)
|
||||
: this(new TableStream(tableName)) { }
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
myVS.onChange += new ChangeDelegate(myHandleChanges);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using bts;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStream.Primitives.Filter;
|
||||
|
||||
using mbts.config;
|
||||
|
||||
@@ -24,7 +21,6 @@ namespace BCG.StreamWorld.Addition {
|
||||
public FilterStream(ViewStream vs, IStreamFilter filter) {
|
||||
myBaseStream = vs;
|
||||
myFilter = filter;
|
||||
vs.ErrorChanged += OnError;
|
||||
if (filter is IDynamicStreamFilter)
|
||||
(filter as IDynamicStreamFilter).onFilterChange += new FilterChangeDelegate(myHandleFilterChange);
|
||||
}
|
||||
@@ -40,45 +36,31 @@ namespace BCG.StreamWorld.Addition {
|
||||
myStateTable.clear();
|
||||
}
|
||||
|
||||
bool filterRow(IBlueRow r) {
|
||||
try {
|
||||
return myFilter.filter(r);
|
||||
} catch (Exception ex) {
|
||||
Log.Gen.error($"FilterStream delegate threw exception: {ex}");
|
||||
OnError(new StreamFilterException(StreamId, StreamName, null, ex, r));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void myHandleChanges(object newValue) {
|
||||
try {
|
||||
DataPacket dp = newValue as DataPacket;
|
||||
if (myStateTable == null) {
|
||||
bts.Log.assert(myBaseTable == null);
|
||||
myStateTable = new BlueTable(dp.schema);
|
||||
myBaseTable = new BlueTable(dp.schema);
|
||||
}
|
||||
BlueTable dels = new BlueTable(dp.schema),
|
||||
adds = new BlueTable(dp.schema);
|
||||
foreach (IBlueRow r in dp.deletedRows) {
|
||||
myBaseTable.deleteRow(r);
|
||||
if (myStateTable.containsID((int)r["id"])) {
|
||||
dels.addRow(r);
|
||||
myStateTable.deleteRow(r);
|
||||
}
|
||||
}
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
myBaseTable.addRow(r);
|
||||
if (filterRow(r)) {
|
||||
adds.addRow(r);
|
||||
myStateTable.addRow(r);
|
||||
}
|
||||
}
|
||||
if ((dels.Count > 0 || adds.Count > 0) || (myLastValue == null))
|
||||
myFireEvent(new DataPacket(myStateTable, adds, dels));
|
||||
} catch (Exception ex) {
|
||||
OnError(ex);
|
||||
DataPacket dp = newValue as DataPacket;
|
||||
if (myStateTable == null) {
|
||||
bts.Log.assert(myBaseTable == null);
|
||||
myStateTable = new BlueTable(dp.schema);
|
||||
myBaseTable = new BlueTable(dp.schema);
|
||||
}
|
||||
BlueTable dels = new BlueTable(dp.schema),
|
||||
adds = new BlueTable(dp.schema);
|
||||
foreach (IBlueRow r in dp.deletedRows) {
|
||||
myBaseTable.deleteRow(r);
|
||||
if (myStateTable.containsID((int)r["id"])) {
|
||||
dels.addRow(r);
|
||||
myStateTable.deleteRow(r);
|
||||
}
|
||||
}
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
myBaseTable.addRow(r);
|
||||
if (myFilter.filter(r)) {
|
||||
adds.addRow(r);
|
||||
myStateTable.addRow(r);
|
||||
}
|
||||
}
|
||||
if ((dels.Count > 0 || adds.Count > 0) || (myLastValue == null))
|
||||
myFireEvent(new DataPacket(myStateTable, adds, dels));
|
||||
}
|
||||
|
||||
public IStreamFilter filter {
|
||||
@@ -87,20 +69,9 @@ namespace BCG.StreamWorld.Addition {
|
||||
if (myBaseTable != null) {
|
||||
IBlueRowCollection oldState = new BlueTable(myStateTable);
|
||||
myStateTable.clear();
|
||||
// If the filter throws an exception, we can rethrow it as a StreamFilterException
|
||||
// and include the 'currentRow' (for which the filter failed) to provide context.
|
||||
IBlueRow? currentRow = null;
|
||||
foreach (IBlueRow r in myBaseTable) {
|
||||
try {
|
||||
currentRow = r;
|
||||
if (filterRow(r)) {
|
||||
myStateTable.addRow(r);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.Gen.error($"FilterStream delegate threw exception: {ex}");
|
||||
OnError(new StreamFilterException(StreamId, StreamName, null, ex, currentRow));
|
||||
}
|
||||
}
|
||||
foreach (IBlueRow r in myBaseTable)
|
||||
if (myFilter.filter(r))
|
||||
myStateTable.addRow(r);
|
||||
IBlueRowCollection dels, adds;
|
||||
BlueDataUtility.computeDifferences(myStateTable, oldState, out dels, out adds);
|
||||
myFireEvent(new DataPacket(myStateTable, adds, dels));
|
||||
@@ -235,36 +206,32 @@ namespace BCG
|
||||
DataPacket retVal;
|
||||
DataPacket arrivedPacket = newValue as DataPacket;
|
||||
myLastReceivedRows = arrivedPacket.newRows;
|
||||
try {
|
||||
if (myLastFiredRows != null)
|
||||
{
|
||||
retVal = new DataPacket(myLastFiredRows, new BlueTable(myLastFiredRows.schema),
|
||||
new BlueTable(myLastFiredRows.schema));
|
||||
foreach (IBlueRow r in arrivedPacket.deletedRows)
|
||||
if (myLastFiredRows.containsID((int)r["id"]))
|
||||
{
|
||||
myLastFiredRows.deleteRow(r);
|
||||
(retVal.deletedRows as BlueTable).addRow(r);
|
||||
}
|
||||
foreach (IBlueRow r in arrivedPacket.addedRows)
|
||||
if (filterRow(r))
|
||||
{
|
||||
myLastFiredRows.addRow(r);
|
||||
(retVal.addedRows as BlueTable).addRow(r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myLastFiredRows = new BlueTable(arrivedPacket.schema);
|
||||
retVal = new DataPacket(myLastFiredRows, myLastFiredRows, new BlueTable(myLastFiredRows.schema));
|
||||
foreach (IBlueRow r in arrivedPacket.newRows)
|
||||
if (filterRow(r))
|
||||
myLastFiredRows.addRow(r);
|
||||
}
|
||||
myFireEvent(retVal);
|
||||
} catch (Exception ex) {
|
||||
OnError(ex);
|
||||
if (myLastFiredRows != null)
|
||||
{
|
||||
retVal = new DataPacket(myLastFiredRows, new BlueTable(myLastFiredRows.schema),
|
||||
new BlueTable(myLastFiredRows.schema));
|
||||
foreach (IBlueRow r in arrivedPacket.deletedRows)
|
||||
if (myLastFiredRows.containsID((int)r["id"]))
|
||||
{
|
||||
myLastFiredRows.deleteRow(r);
|
||||
(retVal.deletedRows as BlueTable).addRow(r);
|
||||
}
|
||||
foreach (IBlueRow r in arrivedPacket.addedRows)
|
||||
if (myFilter.filter(r))
|
||||
{
|
||||
myLastFiredRows.addRow(r);
|
||||
(retVal.addedRows as BlueTable).addRow(r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myLastFiredRows = new BlueTable(arrivedPacket.schema);
|
||||
retVal = new DataPacket(myLastFiredRows, myLastFiredRows, new BlueTable(myLastFiredRows.schema));
|
||||
foreach (IBlueRow r in arrivedPacket.newRows)
|
||||
if (myFilter.filter(r))
|
||||
myLastFiredRows.addRow(r);
|
||||
}
|
||||
myFireEvent(retVal);
|
||||
}
|
||||
|
||||
public IStreamFilter filter
|
||||
@@ -282,20 +249,16 @@ namespace BCG
|
||||
{
|
||||
if (myLastReceivedRows != null)
|
||||
{
|
||||
try {
|
||||
BlueTable nRows = new BlueTable(myLastReceivedRows.schema);
|
||||
foreach (IBlueRow r in myLastReceivedRows)
|
||||
if (filterRow(r))
|
||||
if (myFilter.filter(r))
|
||||
nRows.addRow(r);
|
||||
IBlueRowCollection dRows = new BlueTable(nRows.schema),
|
||||
aRows = new BlueTable(nRows.schema);
|
||||
BlueDataUtility.computeDifferences(nRows, myLastFiredRows, out dRows, out aRows);
|
||||
myLastFiredRows = nRows;
|
||||
myFireEvent(new DataPacket(nRows, aRows, dRows));
|
||||
} catch (Exception ex) {
|
||||
OnError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -319,15 +282,5 @@ namespace BCG
|
||||
{
|
||||
filter = myFilter;
|
||||
}
|
||||
|
||||
bool filterRow(IBlueRow r) {
|
||||
try {
|
||||
return myFilter.filter(r);
|
||||
} catch (Exception ex) {
|
||||
Log.Gen.error($"FilterStream delegate threw exception: {ex}");
|
||||
OnError(new StreamFilterException(StreamId, StreamName, null, ex, r));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#nullable enable
|
||||
namespace Bts.DataStream.Primitives.Filter;
|
||||
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
|
||||
public class StreamFilterException : Exception {
|
||||
public StreamFilterException(Guid streamId, string streamName, string? message, Exception? innerException, IBlueRow? badRow = null)
|
||||
: base(message, innerException) {
|
||||
StreamId = streamId;
|
||||
StreamName = streamName;
|
||||
BadRow = badRow;
|
||||
}
|
||||
|
||||
public Guid StreamId { get; }
|
||||
public string StreamName { get; }
|
||||
public IBlueRow? BadRow { get; }
|
||||
}
|
||||
@@ -52,14 +52,14 @@ namespace BCG {
|
||||
}
|
||||
|
||||
public TimeBasedFilter(ViewStreamDatabase vsd, string rowTimeColumnName, TimeSpan rowTimeToLive)
|
||||
: this(vsd, rowTimeColumnName, rowTimeToLive, rowTimeToLive) {
|
||||
: this(vsd, rowTimeColumnName, rowTimeToLive, new TimeSpan(0, 1, 0) /* 1 minute */) {
|
||||
}
|
||||
|
||||
public TimeBasedFilter(ViewStreamDatabase vsd, string rowTimeColumnName, TimeSpan rowTimeToLive, TimeSpan filter_period) {
|
||||
public TimeBasedFilter(ViewStreamDatabase vsd, string rowTimeColumnName, TimeSpan rowTimeToLive, TimeSpan filterFrequency) {
|
||||
myVsd = vsd;
|
||||
_time_col = rowTimeColumnName;
|
||||
_ttl = rowTimeToLive;
|
||||
_filter_period = filter_period;
|
||||
myFilterFrequency = filterFrequency;
|
||||
myNextFilter = DateTime.MinValue;
|
||||
|
||||
// add worker
|
||||
@@ -71,10 +71,11 @@ namespace BCG {
|
||||
|
||||
#region IStreamFilter
|
||||
public bool filter(IBlueRow row) {
|
||||
DateTime now_utc = DateTime.UtcNow;
|
||||
DateTime row_time_utc = row.get_datetime(_time_col, DateTime.Now).ToUniversalTime();
|
||||
if (now_utc > row_time_utc) {
|
||||
TimeSpan span = now_utc - row_time_utc;
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
DateTime row_time = row.get_datetime(_time_col, DateTime.Now);
|
||||
if (now > row_time) {
|
||||
TimeSpan span = now - row_time;
|
||||
if (span >= _ttl) {
|
||||
return (false);
|
||||
}
|
||||
@@ -89,9 +90,9 @@ namespace BCG {
|
||||
|
||||
if (now > myNextFilter) {
|
||||
// fire event
|
||||
onFilterChange?.Invoke();
|
||||
onFilterChange();
|
||||
|
||||
myNextFilter = now.Add(_filter_period);
|
||||
myNextFilter = now.Add(myFilterFrequency);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -107,7 +108,7 @@ namespace BCG {
|
||||
private ViewStreamDatabase myVsd;
|
||||
private string _time_col;
|
||||
private TimeSpan _ttl;
|
||||
private TimeSpan _filter_period;
|
||||
private TimeSpan myFilterFrequency;
|
||||
private DateTime myNextFilter;
|
||||
#endregion
|
||||
}
|
||||
|
||||
+1
-5
@@ -8,7 +8,7 @@ using bts;
|
||||
using bts.SilverPine;
|
||||
|
||||
namespace BCG {
|
||||
//[DataStreamUserRespresentation("AggregateStream")]
|
||||
[DataStreamUserRespresentation("AggregateStream")]
|
||||
public class NonIncGroupByStream : ViewStream {
|
||||
private class DelNonIncGroupByEvaluator : INonIncGroupByEvaluator {
|
||||
Func<string[]> _groupby_cols_func;
|
||||
@@ -96,10 +96,6 @@ namespace BCG {
|
||||
_timer.Restart();
|
||||
IBlueRowCollection total_state = _groupby_func.evaluate(grouped_rows);
|
||||
_timer.Stop();
|
||||
if (total_state is null) {
|
||||
Log.Gen.warn("NonIncGroupByStream _groupby_func.evaluate returned null (ignoring last update).");
|
||||
return;
|
||||
}
|
||||
var applyElapsedMs = _timer.ElapsedMilliseconds;
|
||||
_n_total_fires++;
|
||||
if (applyElapsedMs >= 50) {
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
//namespace BCG
|
||||
//{
|
||||
// public class FullJoinStream : ViewStream
|
||||
// {
|
||||
// private ViewStream myMainStream;
|
||||
// public FullJoinStream(ViewStream v1, string joinCol1, string cmExp1,
|
||||
// ViewStream v2, string joinCol2, string cmExp2, string empty_col)
|
||||
// {
|
||||
// myMainStream = new LeftJoinStream(v1, joinCol1, cmExp1, v2, joinCol2, cmExp2);
|
||||
// ViewStream filtered = new LeftJoinStream(v2, joinCol2, cmExp2, v1, joinCol1, cmExp1);
|
||||
// filtered = new FilterStream(filtered, String.Format("{0}=null", empty_col));
|
||||
// myMainStream = new AppendStream(myMainStream, filtered);
|
||||
// }
|
||||
namespace BCG
|
||||
{
|
||||
public class FullJoinStream : ViewStream
|
||||
{
|
||||
private ViewStream myMainStream;
|
||||
public FullJoinStream(ViewStream v1, string joinCol1, string cmExp1,
|
||||
ViewStream v2, string joinCol2, string cmExp2, string empty_col)
|
||||
{
|
||||
myMainStream = new LeftJoinStream(v1, joinCol1, cmExp1, v2, joinCol2, cmExp2);
|
||||
ViewStream filtered = new LeftJoinStream(v2, joinCol2, cmExp2, v1, joinCol1, cmExp1);
|
||||
filtered = new FilterStream(filtered, String.Format("{0}=null", empty_col));
|
||||
myMainStream = new AppendStream(myMainStream, filtered);
|
||||
}
|
||||
|
||||
// protected override void myOnFirstSubscriber()
|
||||
// {
|
||||
// myMainStream.onChange += myHandleMainStreamChange;
|
||||
// }
|
||||
protected override void myOnFirstSubscriber()
|
||||
{
|
||||
myMainStream.onChange += myHandleMainStreamChange;
|
||||
}
|
||||
|
||||
// private void myHandleMainStreamChange(object newData)
|
||||
// {
|
||||
// IBlueRowCollection result = (newData as DataPacket).newRows;
|
||||
// myFireEvent(new DataPacket(result, result, myLastValue == null ? new BlueTable(result.schema) : (myLastValue as DataPacket).newRows));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
private void myHandleMainStreamChange(object newData)
|
||||
{
|
||||
IBlueRowCollection result = (newData as DataPacket).newRows;
|
||||
myFireEvent(new DataPacket(result, result, myLastValue == null ? new BlueTable(result.schema) : (myLastValue as DataPacket).newRows));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
#nullable disable
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using BCG.Utilities.General;
|
||||
using BCG.Utilities;
|
||||
|
||||
namespace BCG
|
||||
{
|
||||
|
||||
@@ -10,8 +10,6 @@ using BCG.Utilities;
|
||||
using bts;
|
||||
|
||||
namespace BCG {
|
||||
// Prefixing with "old" to avoid name conflict with the BlueOrb LiteralStream
|
||||
[DataStreamUserRespresentation("oldLiteral")]
|
||||
public class LiteralStream : ViewStream {
|
||||
|
||||
public static List<Tuple<ColumnInfo, object>> parse_columns(string key_value_pairs) {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using bts;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using mbts.config;
|
||||
using mbts.utils;
|
||||
|
||||
using System;
|
||||
|
||||
@@ -19,8 +15,8 @@ namespace BCG {
|
||||
/// </summary>
|
||||
[DataStreamUserRespresentation(false)]
|
||||
public class MapStream : MethodDrivenStream {
|
||||
protected IStreamMapper? myMapper;
|
||||
protected IChangeableStreamMapper? myChangeableMapper;
|
||||
protected IStreamMapper myMapper;
|
||||
protected IChangeableStreamMapper myChangeableMapper = null;
|
||||
private bool myUseNewMap = Configuration.get<DataStreamConfig>().UseNewMap;
|
||||
|
||||
public class FuncWrapper : IStreamMapper {
|
||||
@@ -75,7 +71,7 @@ namespace BCG {
|
||||
|
||||
|
||||
protected override void myHandleFirstCall() {
|
||||
ArgumentNullException.ThrowIfNull(myMapper);
|
||||
|
||||
IBlueTableSchema outputSchema = myMapper.getOutputSchema(myLastArrivedPacket.newRows.schema);
|
||||
myLastFiredPacket = new DataPacket();
|
||||
myLastFiredPacket.newRows = new BlueTable(outputSchema);
|
||||
@@ -86,34 +82,28 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myHandleIncrementalAdd() {
|
||||
if (myLastArrivedPacket.addedRows.Count == 0) {
|
||||
Log.Gen.warn("MapStream.myHandleIncrementalAdd called with 0 addedRows");
|
||||
return;
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(myMapper);
|
||||
var addedRows = new BlueTable(myLastFiredPacket.newRows.schema);
|
||||
var newRows = ExceptionAssert.Cast(myLastFiredPacket.newRows).To<BlueTable>();
|
||||
//t.start ();
|
||||
myLastFiredPacket.addedRows = new BlueTable(myLastFiredPacket.newRows.schema);
|
||||
foreach (IBlueRow row in myLastArrivedPacket.addedRows) {
|
||||
var newRow = myMapper.map(row);
|
||||
newRows.addRow(newRow);
|
||||
addedRows.addRow(newRow);
|
||||
IBlueRow newRow = myMapper.map(row);
|
||||
(myLastFiredPacket.newRows as BlueTable).addRow(newRow);
|
||||
(myLastFiredPacket.addedRows as BlueTable).addRow(newRow);
|
||||
}
|
||||
myLastFiredPacket.addedRows = addedRows;
|
||||
//t.stop ();
|
||||
//System.Diagnostics.Trace.WriteLine ("adding " + myLastFiredPacket.addedRows.Count.ToString () + " : " + t.lastIntervalTime);
|
||||
//System.Diagnostics.Trace.WriteLine (" ");
|
||||
}
|
||||
|
||||
protected override void myHandleIncrementalDelete() {
|
||||
if (myLastArrivedPacket.deletedRows.Count == 0) {
|
||||
Log.Gen.warn("MapStream.myHandleIncrementalDelete called with 0 deletedRows");
|
||||
return;
|
||||
}
|
||||
var deletedRows = new BlueTable(myLastFiredPacket.newRows.schema);
|
||||
var newRows = ExceptionAssert.Cast(myLastFiredPacket.newRows).To<BlueTable>();
|
||||
//t.start ();
|
||||
myLastFiredPacket.deletedRows = new BlueTable(myLastFiredPacket.newRows.schema);
|
||||
foreach (IBlueRow row in myLastArrivedPacket.deletedRows) {
|
||||
var delRow = newRows[row.Id()];
|
||||
deletedRows.addRow(delRow);
|
||||
newRows.deleteRow(row);
|
||||
IBlueRow delRow = (myLastFiredPacket.newRows as BlueTable)[(int)row["id"]];
|
||||
(myLastFiredPacket.deletedRows as BlueTable).addRow(delRow);
|
||||
(myLastFiredPacket.newRows as BlueTable).deleteRow(row);
|
||||
}
|
||||
myLastFiredPacket.deletedRows = deletedRows;
|
||||
//t.stop ();
|
||||
//System.Diagnostics.Trace.WriteLine ("deleting " + myLastFiredPacket.deletedRows.Count.ToString () + " : " + t.lastIntervalTime);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using mbts.utils;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using BCG.Utilities;
|
||||
using BCG.Utilities.General;
|
||||
|
||||
using mbts;
|
||||
|
||||
namespace BCG {
|
||||
/// <summary>
|
||||
@@ -54,15 +56,15 @@ namespace BCG {
|
||||
return rows == null ? new IBlueRow[] { } : new List<IBlueRow>(rows).ToArray();
|
||||
}
|
||||
|
||||
public event MapperChangeDelegate? onMapperChange;
|
||||
public event MapperChangeDelegate onMapperChange;
|
||||
private void _fake() { onMapperChange(); }
|
||||
}
|
||||
|
||||
//maps the id of the underlying stream to the
|
||||
//rows of the resulting stream
|
||||
private Dictionary<int, List<IBlueRow>> myMap = new Dictionary<int, List<IBlueRow>>();
|
||||
private int myID = 0;
|
||||
private BlueTable? myRows;
|
||||
private BlueTable? myBaseRows;
|
||||
private BlueTable myRows, myBaseRows;
|
||||
private ViewStream myStream;
|
||||
private ISuperStreamMapper myMapper;
|
||||
public bool generate_ids = true;
|
||||
@@ -90,40 +92,49 @@ namespace BCG {
|
||||
myRows = null;
|
||||
myBaseRows = null;
|
||||
myMap.Clear();
|
||||
//myMapper.onMapperChange -= new MapperChangeDelegate(myHandleMapChange);
|
||||
}
|
||||
|
||||
private void myHandleData(object newValue) {
|
||||
var dp = ExceptionAssert.Cast(newValue).To<DataPacket>();
|
||||
myRows ??= new BlueTable(myMapper.getOutputSchema(dp.schema));
|
||||
myBaseRows ??= new BlueTable(dp.schema);
|
||||
DataPacket idp = newValue as DataPacket;
|
||||
//HighPerformanceTimer timer = new HighPerformanceTimer();
|
||||
//timer.start();
|
||||
DataPacket dp = newValue as DataPacket;
|
||||
myRows = myRows ?? new BlueTable(myMapper.getOutputSchema(dp.schema));
|
||||
myBaseRows = myBaseRows ?? new BlueTable(dp.schema);
|
||||
BlueDataUtility.absorbChanges(myBaseRows, dp.deletedRows, dp.addedRows);
|
||||
var dels = new BlueTable(myRows.schema);
|
||||
var adds = new BlueTable(myRows.schema);
|
||||
BlueTable dels = new BlueTable(myRows.schema),
|
||||
adds = new BlueTable(myRows.schema);
|
||||
|
||||
foreach (IBlueRow r in dp.deletedRows) {
|
||||
var mappedRows = myMap[r.Id()];
|
||||
List<IBlueRow> mappedRows = myMap[(int)r["id"]];
|
||||
foreach (IBlueRow mr in mappedRows) {
|
||||
dels.addRow(mr);
|
||||
myRows.deleteRow(mr);
|
||||
}
|
||||
myMap.Remove(r.Id());
|
||||
myMap.Remove((int)r["id"]);
|
||||
}
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
IBlueRow[] mappedRows = myMapper.map(r);
|
||||
foreach (IBlueRow mr in mappedRows) {
|
||||
IBlueRow idChangedMapRow = generate_ids ? BlueDataUtility.getNewReplacedRow(mr, myID++, "id") : mr;
|
||||
myMap.GetOrAdd(r.Id(), _ => new()).Add(idChangedMapRow);
|
||||
if (!myMap.ContainsKey((int)r["id"])) {
|
||||
myMap.Add((int)r["id"], new List<IBlueRow>());
|
||||
}
|
||||
myMap[(int)r["id"]].Add(idChangedMapRow);
|
||||
myRows.addRow(idChangedMapRow);
|
||||
adds.addRow(idChangedMapRow);
|
||||
}
|
||||
}
|
||||
//timer.stop();
|
||||
// if (timer.lastIntervalTime > 20)
|
||||
// {}//mbts.Logger.log(bts.log.Level.Info, bts.log.Subsystem.gen, String.Format("SuperMapper:myHandlerData for mapper {0} took {1} msecs", myMapper.GetType().ToString(), timer.lastIntervalTime));
|
||||
myFireEvent(new DataPacket(myRows, adds, dels));
|
||||
}
|
||||
|
||||
private void myHandleMapChange() {
|
||||
if (myBaseRows is not null) {
|
||||
if (myBaseRows != null)
|
||||
myHandleData(new DataPacket(myBaseRows, new BlueTable(myBaseRows), new BlueTable(myBaseRows)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,8 +70,7 @@ namespace bts
|
||||
private readonly int _msg_size;
|
||||
private readonly TimeSpan _publish_period;
|
||||
private DateTime _last_publish_time = DateTime.MinValue;
|
||||
private IPublisherCore _pub_core;
|
||||
readonly ISubscriberCore subscriberCore;
|
||||
private PublisherCore _pub_core = new PublisherCore();
|
||||
private BlueTable _table;
|
||||
private int _n_pubs = 0;
|
||||
private readonly int _max_pubs;
|
||||
@@ -83,10 +82,8 @@ namespace bts
|
||||
private readonly int _payload_sz;
|
||||
private const byte _payload_byte = (byte)'A';
|
||||
private readonly string _tag_name;
|
||||
public PubSubTestingStream(int publish_period_msecs, int max_pubs, int payload_size, string tag_name, IPublisherCore publisherCore, ISubscriberCore subscriberCore, ViewStreamDatabase vsd)
|
||||
public PubSubTestingStream(int publish_period_msecs, int max_pubs, int payload_size, string tag_name, ViewStreamDatabase vsd)
|
||||
{
|
||||
_pub_core = publisherCore;
|
||||
this.subscriberCore = subscriberCore;
|
||||
_vsd = vsd;
|
||||
_payload_sz = payload_size;
|
||||
var schema = BlueDataUtility.form_schema("PubSubTest",
|
||||
@@ -106,6 +103,9 @@ namespace bts
|
||||
_tag_name = tag_name;
|
||||
}
|
||||
|
||||
public PubSubTestingStream(int publish_period_seconds, int max_pubs, int msg_size, string tag_name)
|
||||
: this(publish_period_seconds, max_pubs, msg_size, tag_name, ViewStreamDatabase.instance) { }
|
||||
|
||||
protected override void myOnFirstSubscriber()
|
||||
{
|
||||
_vsd.addWorker(this);
|
||||
@@ -132,31 +132,33 @@ namespace bts
|
||||
|
||||
private void _subscribe_thread_func()
|
||||
{
|
||||
var sub = subscriberCore.Updates().Subscribe(onUpdate);
|
||||
// subscription is done in another thread
|
||||
subscriberCore.subscribe(_tag_name);
|
||||
SubscriberCore sub_core = new SubscriberCore();
|
||||
sub_core.subscribe(_tag_name);
|
||||
while (_continue_sub_thread)
|
||||
{
|
||||
// TODO recv_id
|
||||
subscriberCore.get_updates(TimeSpan.FromMilliseconds(250));
|
||||
var updates = sub_core.get_updates(TimeSpan.FromMilliseconds(250));
|
||||
if (updates == null || updates.Count() == 0)
|
||||
continue;
|
||||
_log_updates(updates);
|
||||
_n_updates += updates.Count();
|
||||
if (updates.Count() > 0)
|
||||
{
|
||||
var server_msg = updates.Last();
|
||||
if (server_msg.data != null && server_msg.data.Length > 0)
|
||||
{
|
||||
_last_recvd_msg = PayloadMessage.deserialize(server_msg.data);
|
||||
_last_recvd_msg.travel_epoch_ms = epoch_now();
|
||||
}
|
||||
else
|
||||
{
|
||||
// why are we getting empty or null data ? (server is sending data regardless?)
|
||||
}
|
||||
_fire_dirty = true;
|
||||
}
|
||||
}
|
||||
sub.Dispose();
|
||||
|
||||
void onUpdate(IEnumerable<PubSubServerMessage> updates) {
|
||||
_log_updates(updates);
|
||||
_n_updates += updates.Count();
|
||||
if (updates.Count() > 0) {
|
||||
var server_msg = updates.Last();
|
||||
if (server_msg.data != null && server_msg.data.Length > 0) {
|
||||
_last_recvd_msg = PayloadMessage.deserialize(server_msg.data);
|
||||
_last_recvd_msg.travel_epoch_ms = epoch_now();
|
||||
} else {
|
||||
// why are we getting empty or null data ? (server is sending data regardless?)
|
||||
}
|
||||
_fire_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _publish_next_packet()
|
||||
{
|
||||
@@ -222,4 +224,4 @@ namespace bts
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,10 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using bts.api;
|
||||
using Bts.PubSub.Routing;
|
||||
|
||||
namespace bts
|
||||
{
|
||||
[DataStreamUserRespresentation(false)]
|
||||
[DataStreamUserRespresentation("pss_echo")]
|
||||
public class PubsubEchoTestStream : ViewStream, IWorker
|
||||
{
|
||||
public class PayloadMessage
|
||||
@@ -77,7 +76,7 @@ namespace bts
|
||||
private readonly int _msg_size;
|
||||
private readonly TimeSpan _publish_period;
|
||||
private DateTime _last_publish_time = DateTime.MinValue;
|
||||
private IPublisherCore _pub_core;
|
||||
private PublisherCore _pub_core;
|
||||
private ISubscriberCore _sub_core;
|
||||
private BlueTable _table;
|
||||
private int _n_pubs = 0;
|
||||
@@ -96,21 +95,10 @@ namespace bts
|
||||
};
|
||||
IOState _state = IOState.SEND;
|
||||
|
||||
public PubsubEchoTestStream(
|
||||
string server_url,
|
||||
TimeSpan publish_period,
|
||||
int payload_size,
|
||||
string tag_name,
|
||||
IPublisherCore publisherCore,
|
||||
ISubscriberCore subscriberCore,
|
||||
ViewStreamDatabase vsd
|
||||
) {
|
||||
_router = new PubSubRouter(new PubSubRouterConfig() {
|
||||
PublisherRoutes = new() { new(server_url, ".*") },
|
||||
SubscriberRoutes = new() { new(server_url, ".*") },
|
||||
});
|
||||
_pub_core = publisherCore;
|
||||
_sub_core = subscriberCore;
|
||||
public PubsubEchoTestStream(string server_url, TimeSpan publish_period, int payload_size, string tag_name, ViewStreamDatabase vsd)
|
||||
{
|
||||
var route = new PubSubRoute(server_url, ".*");
|
||||
_router = new PubSubRouter(route);
|
||||
_vsd = vsd;
|
||||
_payload_sz = payload_size;
|
||||
var schema = BlueDataUtility.form_schema("PubSubTest",
|
||||
@@ -126,8 +114,13 @@ namespace bts
|
||||
_tag_name = tag_name;
|
||||
}
|
||||
|
||||
public PubsubEchoTestStream(string server_url, int publish_period_msecs, int payload_size, string tag_name)
|
||||
: this(server_url, TimeSpan.FromMilliseconds(publish_period_msecs), payload_size, tag_name, ViewStreamDatabase.instance) { }
|
||||
|
||||
protected override void myOnFirstSubscriber()
|
||||
{
|
||||
_pub_core = new PublisherCore(_router);
|
||||
_sub_core = new SubscriberCore(_router);
|
||||
_sub_core.subscribe(_tag_name);
|
||||
_vsd.addWorker(this);
|
||||
|
||||
@@ -227,4 +220,4 @@ namespace bts
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace bts {
|
||||
if (_in_rows.Count > 0) {
|
||||
// fire row
|
||||
IBlueRow curr_row = _in_rows.ElementAt(_in_row_ptr++);
|
||||
_out_table = _out_table.Add(curr_row);
|
||||
_out_table.add_row(curr_row);
|
||||
DataPacket dp = BlueDataUtility.build_dp_inc(_out_table,
|
||||
myLastValue == null ? null : myLastValue as DataPacket, false);
|
||||
myFireEvent(dp);
|
||||
@@ -74,4 +74,4 @@ namespace bts {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ namespace BCG {
|
||||
sub_msg.serialize_into_str(str);
|
||||
str.Position = 0;
|
||||
bts.SubscribeMsg sub_msg_ = new bts.SubscribeMsg();
|
||||
sub_msg_.construct_deserialize(str);
|
||||
sub_msg_.consruct_deserialize(str);
|
||||
bool res = sub_msg.Equals(sub_msg_);
|
||||
return new TestResult {
|
||||
test_name = "SubscribeMsg",
|
||||
@@ -117,7 +117,7 @@ namespace BCG {
|
||||
pub_msg.serialize_into_str(str);
|
||||
str.Position = 0;
|
||||
var pub_msg_ = new bts.PublishMsg();
|
||||
pub_msg_.construct_deserialize(str);
|
||||
pub_msg_.consruct_deserialize(str);
|
||||
bool res = pub_msg.Equals(pub_msg_);
|
||||
return new TestResult {
|
||||
test_name = "PublishMsg",
|
||||
@@ -135,7 +135,7 @@ namespace BCG {
|
||||
msg.serialize_into_str(str);
|
||||
str.Position = 0;
|
||||
var msg_ = new bts.PubSubServerMessage();
|
||||
msg_.construct_deserialize(str);
|
||||
msg_.consruct_deserialize(str);
|
||||
bool res = msg.Equals(msg_);
|
||||
return new TestResult {
|
||||
test_name = "PubSubServerMessage",
|
||||
@@ -156,7 +156,7 @@ namespace BCG {
|
||||
msg.serialize_into_str(str);
|
||||
str.Position = 0;
|
||||
var msg_ = new PubSubClientMessage();
|
||||
msg_.construct_deserialize(str);
|
||||
msg_.consruct_deserialize(str);
|
||||
var res = msg.Equals(msg_);
|
||||
return new TestResult {
|
||||
test_name = "PubSubClientMessage",
|
||||
@@ -617,15 +617,14 @@ namespace BCG {
|
||||
|
||||
|
||||
private static TestResult _run_single_tag_data_test_clean() {
|
||||
// var tagHandlerFactory
|
||||
// create message
|
||||
var test_name = MethodBase.GetCurrentMethod()?.Name;
|
||||
var test_name = MethodBase.GetCurrentMethod().Name;
|
||||
var schema = create_schema_with_all_types();
|
||||
var tag = "DS_" + schema.tableName;
|
||||
BlueTable table = new BlueTable(schema);
|
||||
IStreamIOMsgSerializer serializer = new StreamIOSerializationController();
|
||||
IStreamMsgDeserilizer deser = new StreamIODeserializationController();
|
||||
bts.SingleTagData st_data = new bts.SingleTagData(tag, DSTagManager.DataStreamTagType, new PubsubServerStreamTagHandler());
|
||||
bts.SingleTagData st_data = new bts.SingleTagData(tag, DSTagManager.DataStreamTagType);
|
||||
// create with 100 rows
|
||||
int n_rows = 100;
|
||||
bool is_succ = true;
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
using BCG;
|
||||
|
||||
namespace bts.SilverPine {
|
||||
// Keeps adding changing rows to the stream, hence preserving the history
|
||||
// and creating a time series, for example this can be used to make bbo updates
|
||||
// into a time series of prices/qty
|
||||
public class TimeSeriesStream : ViewStream {
|
||||
private BlueTable _table;
|
||||
private ViewStream _stream;
|
||||
private int _id = 0;
|
||||
|
||||
public TimeSeriesStream(ViewStream stream) {
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_stream.onChange += new ChangeDelegate(_onstream_change);
|
||||
}
|
||||
protected override void myOnLastSubscriber() {
|
||||
_stream.onChange -= new ChangeDelegate(_onstream_change);
|
||||
}
|
||||
|
||||
|
||||
private void _onstream_change(object o) {
|
||||
DataPacket dp = o as DataPacket;
|
||||
DateTime now = DateTime.Now;
|
||||
if (_table == null) {
|
||||
IBlueTableSchema schema = new BlueTableSchema(dp.newRows.schema.columnInfo, dp.newRows.schema.tableName);
|
||||
schema = schema.add_columns(Tuple.Create(typeof(DateTime), "timestamp"));
|
||||
_table = new BlueTable(schema);
|
||||
}
|
||||
BlueTable added_rows = new BlueTable(_table.schema);
|
||||
foreach (IBlueRow r in dp.addedRows) {
|
||||
MutableBlueRow ar = new MutableBlueRow(_table.schema, r);
|
||||
ar.setValue("timestamp", now);
|
||||
ar.setValue("id", _id++);
|
||||
added_rows.addRow(ar);
|
||||
}
|
||||
_table.addRows(added_rows);
|
||||
myFireEvent(new DataPacket(_table, added_rows, new BlueTable(_table.schema)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,121 +1,121 @@
|
||||
// using System;
|
||||
// using System.Collections.Generic;
|
||||
// using System.IO;
|
||||
// using System.Security.Cryptography.X509Certificates;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
// using BCG;
|
||||
// using BCG.Utilities.General;
|
||||
using BCG;
|
||||
using BCG.Utilities.General;
|
||||
|
||||
// using HtmlAgilityPack;
|
||||
using HtmlAgilityPack;
|
||||
|
||||
// namespace BCG {
|
||||
// class Program {
|
||||
// // static void Main() {
|
||||
// // string url = "http://quotes.toscrape.com";
|
||||
// // List<string> quotes = ScrapeQuotes(url);
|
||||
namespace BCG {
|
||||
class Program {
|
||||
static void Main() {
|
||||
string url = "http://quotes.toscrape.com";
|
||||
List<string> quotes = ScrapeQuotes(url);
|
||||
|
||||
// // Console.WriteLine("Quotes from http://quotes.toscrape.com:");
|
||||
// // foreach (var quote in quotes) {
|
||||
// // Console.WriteLine(quote);
|
||||
// // }
|
||||
// // }
|
||||
Console.WriteLine("Quotes from http://quotes.toscrape.com:");
|
||||
foreach (var quote in quotes) {
|
||||
Console.WriteLine(quote);
|
||||
}
|
||||
}
|
||||
|
||||
// static List<string> ScrapeQuotes(string url) {
|
||||
// List<string> quotes = new List<string>();
|
||||
static List<string> ScrapeQuotes(string url) {
|
||||
List<string> quotes = new List<string>();
|
||||
|
||||
// // Create a new HtmlWeb instance
|
||||
// HtmlWeb web = new HtmlWeb();
|
||||
// Create a new HtmlWeb instance
|
||||
HtmlWeb web = new HtmlWeb();
|
||||
|
||||
// try {
|
||||
// // Load the HTML document from the specified URL
|
||||
// HtmlDocument document = web.Load(url);
|
||||
try {
|
||||
// Load the HTML document from the specified URL
|
||||
HtmlDocument document = web.Load(url);
|
||||
|
||||
// // Extract quotes from the HTML document
|
||||
// var quoteNodes = document.DocumentNode.SelectNodes("//span[@class='text']");
|
||||
// if (quoteNodes != null) {
|
||||
// foreach (var quoteNode in quoteNodes) {
|
||||
// string quote = quoteNode.InnerText.Trim();
|
||||
// quotes.Add(quote);
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception ex) {
|
||||
// Console.WriteLine($"Error: {ex.Message}");
|
||||
// }
|
||||
// Extract quotes from the HTML document
|
||||
var quoteNodes = document.DocumentNode.SelectNodes("//span[@class='text']");
|
||||
if (quoteNodes != null) {
|
||||
foreach (var quoteNode in quoteNodes) {
|
||||
string quote = quoteNode.InnerText.Trim();
|
||||
quotes.Add(quote);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
|
||||
// return quotes;
|
||||
// }
|
||||
// }
|
||||
return quotes;
|
||||
}
|
||||
}
|
||||
|
||||
// public class WebScapperStream : ViewStream, IWorker {
|
||||
// private readonly string _url;
|
||||
// private readonly string _xpath;
|
||||
// private readonly ViewStreamDatabase _vsd;
|
||||
// private IDictionary<string, int> _line_id_map = new Dictionary<string, int>();
|
||||
// private readonly IBlueTableSchema _schema;
|
||||
public class WebScapperStream : ViewStream, IWorker {
|
||||
private readonly string _url;
|
||||
private readonly string _xpath;
|
||||
private readonly ViewStreamDatabase _vsd;
|
||||
private IDictionary<string, int> _line_id_map = new Dictionary<string, int>();
|
||||
private readonly IBlueTableSchema _schema;
|
||||
|
||||
// public WebScapperStream()
|
||||
// :
|
||||
// this("http://quotes.toscrape.com", "//span[@class='text']", ViewStreamDatabase.instance) { }
|
||||
// public WebScapperStream(string url, string xpath)
|
||||
// : this(url, xpath, ViewStreamDatabase.instance) { }
|
||||
// public WebScapperStream(string url, string xpath, ViewStreamDatabase vsd) {
|
||||
// bts.Log.Gen.info($"WebScapperStream cons url: {url} xpath: {xpath}");
|
||||
// _schema = BlueDataUtility.form_schema($"{url}_{xpath}",
|
||||
// Tuple.Create("id", TypeCode.Int32),
|
||||
// Tuple.Create("url", TypeCode.UInt32),
|
||||
// Tuple.Create("line", TypeCode.String));
|
||||
// _url = url;
|
||||
// _xpath = xpath;
|
||||
// _vsd = vsd;
|
||||
// }
|
||||
public WebScapperStream()
|
||||
:
|
||||
this("http://quotes.toscrape.com", "//span[@class='text']", ViewStreamDatabase.instance) { }
|
||||
public WebScapperStream(string url, string xpath)
|
||||
: this(url, xpath, ViewStreamDatabase.instance) { }
|
||||
public WebScapperStream(string url, string xpath, ViewStreamDatabase vsd) {
|
||||
bts.Log.Gen.info($"WebScapperStream cons url: {url} xpath: {xpath}");
|
||||
_schema = BlueDataUtility.form_schema($"{url}_{xpath}",
|
||||
Tuple.Create("id", TypeCode.Int32),
|
||||
Tuple.Create("url", TypeCode.UInt32),
|
||||
Tuple.Create("line", TypeCode.String));
|
||||
_url = url;
|
||||
_xpath = xpath;
|
||||
_vsd = vsd;
|
||||
}
|
||||
|
||||
// protected override void myOnFirstSubscriber() {
|
||||
// MasterWorker.getInstance(false).addWorker(this, TimeSpan.FromSeconds(1));
|
||||
// }
|
||||
protected override void myOnFirstSubscriber() {
|
||||
MasterWorker.getInstance(false).addWorker(this, TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
// protected override void myOnLastSubscriber() {
|
||||
// MasterWorker.getInstance(false).removeWorker(this);
|
||||
// }
|
||||
protected override void myOnLastSubscriber() {
|
||||
MasterWorker.getInstance(false).removeWorker(this);
|
||||
}
|
||||
|
||||
// public void doWork() {
|
||||
// var lines = scrape_lines(_url, _xpath);
|
||||
// Func<string, int> get_id = (line) => {
|
||||
// int rv = 0;
|
||||
// if (!_line_id_map.TryGetValue(line, out rv))
|
||||
// _line_id_map.Add(line, _line_id_map.Count);
|
||||
// return rv;
|
||||
// };
|
||||
// BlueTable nrows = new BlueTable(_schema);
|
||||
// foreach (var l in lines) {
|
||||
// bts.Log.Gen.info($"line: {l}");
|
||||
// var id = get_id(l);
|
||||
// BlueRow nr = new BlueRow(_schema, get_id(l), _url, l);
|
||||
// nrows.addRow(nr);
|
||||
// }
|
||||
// var dp = BlueDataUtility.build_dp_inc(nrows, myLastValue as DataPacket, true);
|
||||
// myFireEvent(dp);
|
||||
// }
|
||||
public void doWork() {
|
||||
var lines = scrape_lines(_url, _xpath);
|
||||
Func<string, int> get_id = (line) => {
|
||||
int rv = 0;
|
||||
if (!_line_id_map.TryGetValue(line, out rv))
|
||||
_line_id_map.Add(line, _line_id_map.Count);
|
||||
return rv;
|
||||
};
|
||||
BlueTable nrows = new BlueTable(_schema);
|
||||
foreach (var l in lines) {
|
||||
bts.Log.Gen.info($"line: {l}");
|
||||
var id = get_id(l);
|
||||
BlueRow nr = new BlueRow(_schema, get_id(l), _url, l);
|
||||
nrows.addRow(nr);
|
||||
}
|
||||
var dp = BlueDataUtility.build_dp_inc(nrows, myLastValue as DataPacket, true);
|
||||
myFireEvent(dp);
|
||||
}
|
||||
|
||||
// static List<string> scrape_lines(string url, string xpath) {
|
||||
// List<string> quotes = new List<string>();
|
||||
// // Create a new HtmlWeb instance
|
||||
// HtmlWeb web = new HtmlWeb();
|
||||
// try {
|
||||
// // Load the HTML document from the specified URL
|
||||
// HtmlDocument document = web.Load(url);
|
||||
// // Extract quotes from the HTML document
|
||||
// var quote_nodes = document.DocumentNode.SelectNodes(xpath);
|
||||
// if (quote_nodes != null) {
|
||||
// foreach (var qn in quote_nodes) {
|
||||
// string quote = qn.InnerText.Trim();
|
||||
// quotes.Add(quote);
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception ex) {
|
||||
// Console.WriteLine($"Error: {ex.Message}");
|
||||
// }
|
||||
static List<string> scrape_lines(string url, string xpath) {
|
||||
List<string> quotes = new List<string>();
|
||||
// Create a new HtmlWeb instance
|
||||
HtmlWeb web = new HtmlWeb();
|
||||
try {
|
||||
// Load the HTML document from the specified URL
|
||||
HtmlDocument document = web.Load(url);
|
||||
// Extract quotes from the HTML document
|
||||
var quote_nodes = document.DocumentNode.SelectNodes(xpath);
|
||||
if (quote_nodes != null) {
|
||||
foreach (var qn in quote_nodes) {
|
||||
string quote = qn.InnerText.Trim();
|
||||
quotes.Add(quote);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
|
||||
// return quotes;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
return quotes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,14 @@ namespace Bts.DataStream;
|
||||
|
||||
using bts;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using MongoDB.Bson;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public static class MongoSchemaAdaptor {
|
||||
public static BlueTableSchemaAdapter<BsonDocument> InferSchema(IEnumerable<BsonDocument> docs) {
|
||||
var schemaAdaptor = new BlueTableSchemaAdapter<BsonDocument>("MongoCollectionStream");
|
||||
public static BlueTableSchemaAdaptor<BsonDocument> InferSchema(IEnumerable<BsonDocument> docs) {
|
||||
var schemaAdaptor = new BlueTableSchemaAdaptor<BsonDocument>("MongoCollectionStream");
|
||||
foreach (var doc in docs) {
|
||||
foreach (var el in doc) {
|
||||
if (schemaAdaptor.Contains(el.Name)) {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
namespace Bts.DataStream;
|
||||
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
public class SQLiteEnumerable : IAsyncEnumerable<IBlueRowCollection> {
|
||||
readonly string location;
|
||||
readonly string statement;
|
||||
readonly int pageSize;
|
||||
|
||||
public SQLiteEnumerable(string location, string statement, int pageSize = 65536) {
|
||||
this.location = location;
|
||||
this.statement = statement;
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public async IAsyncEnumerator<IBlueRowCollection> GetAsyncEnumerator(CancellationToken cancellationToken = default) {
|
||||
var dataTable = new DataTable();
|
||||
await using var conn = new SQLiteConnection($"Data Source={location};Version=3");
|
||||
await conn.OpenAsync(cancellationToken);
|
||||
await using var cmd = new SQLiteCommand(statement, conn);
|
||||
await using var reader = cmd.ExecuteReader();
|
||||
var schema = await reader.GetColumnSchemaAsync(cancellationToken);
|
||||
var columns = schema.OrderBy(c => c.ColumnOrdinal ?? int.MaxValue)
|
||||
.Select((c, i) => new ColumnInfo(c.ColumnName, c.ColumnOrdinal ?? i, c.DataType))
|
||||
.Append(new ColumnInfo("id", schema.Count, typeof(int)))
|
||||
.ToArray();
|
||||
var blueSchema = new BlueTableSchema("anon", columns);
|
||||
BlueTable? table = null;
|
||||
int rowId = 1;
|
||||
while (await reader.ReadAsync(cancellationToken)) {
|
||||
table ??= new BlueTable(blueSchema);
|
||||
var rowVals = new object[blueSchema.columnInfo.Length];
|
||||
if (reader.GetValues(rowVals) != rowVals.Length - 1) {
|
||||
throw new InvalidOperationException("Sqlite reader value count for single row not equal to column count");
|
||||
}
|
||||
rowVals[^1] = rowId++;
|
||||
table.addRow(new BlueRow(blueSchema, rowVals));
|
||||
if (table.Count == pageSize) {
|
||||
yield return table;
|
||||
table = null;
|
||||
}
|
||||
}
|
||||
if (table is not null) {
|
||||
yield return table;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@ using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
|
||||
using BCG;
|
||||
@@ -12,14 +10,12 @@ using System.Linq;
|
||||
using System.Data.Entity;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
|
||||
namespace bts.BlueOrb{
|
||||
namespace bts.SilverPine {
|
||||
|
||||
public static class SQLiteHelper {
|
||||
public static string location = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "C:\\BlueOrb_Data\\" : Path.Combine(Environment.GetEnvironmentVariable("HOME"), "BlueOrb_Data");
|
||||
public static string location = "C:\\Users\\m_tah\\development\\data\\";
|
||||
public static string db_name = "stream_data.db";
|
||||
|
||||
public static DataTable execute_select_query(string connection_string, string query) {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
namespace bts.BlueOrb {
|
||||
namespace bts.SilverPine {
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
|
||||
|
||||
using BCG;
|
||||
|
||||
[DataStreamUserRespresentation("SQLiteStream")]
|
||||
[DataStreamUserRespresentation("SQLite")]
|
||||
public class SQLiteStream : ViewStream {
|
||||
private readonly string _connection_string, _query;
|
||||
private Stopwatch _stopwatch = new Stopwatch();
|
||||
@@ -18,7 +20,7 @@ namespace bts.BlueOrb {
|
||||
|
||||
public SQLiteStream(string db_name, string query)
|
||||
:
|
||||
this($"Data Source={System.IO.Path.Combine(SQLiteHelper.location,db_name)};Version=3", query, true) { }
|
||||
this($"Data Source={SQLiteHelper.location}{db_name};Version=3", query, true) { }
|
||||
|
||||
public SQLiteStream(string query)
|
||||
:
|
||||
@@ -30,7 +32,7 @@ namespace bts.BlueOrb {
|
||||
_stopwatch.Start();
|
||||
DataTable dt = SQLiteHelper.execute_select_query(_connection_string, _query);
|
||||
_stopwatch.Stop();
|
||||
Log.Gen.info($"SQLiteStream.ExecuteSelectQuery time to read db: {_stopwatch.ElapsedMilliseconds} msecs, query: {_query}, connection:{_connection_string}");
|
||||
Log.Gen.info($"SQLiteStream.ExecuteSelectQuery time to read db: {_stopwatch.ElapsedMilliseconds} msecs");
|
||||
_stopwatch.Restart();
|
||||
#region perf measures
|
||||
// SQLiteHelper.get_table(_connection_string, _query);
|
||||
@@ -68,5 +70,4 @@ namespace bts.BlueOrb {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@ using System.IO;
|
||||
using BCG.Utilities;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Data.Analysis;
|
||||
using Parquet;
|
||||
using Parquet.Data;
|
||||
|
||||
|
||||
namespace BCG {
|
||||
@@ -110,12 +112,11 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
//_stopwatch.Start();
|
||||
//DataFrame df = DataFrame.LoadCsv(_file_address);
|
||||
//_stopwatch.Stop();
|
||||
//bts.Log.Gen.info($"CSVReaderStream.myOnFirstSubscriber stream csv load col_count: {df.Columns.Count} rows, time: {_stopwatch.ElapsedMilliseconds} msecs");
|
||||
_stopwatch.Start();
|
||||
bts.Log.Gen.info($"CSVReaderStream.myOnFirstSubscriber opening address{_file_address}");
|
||||
DataFrame df = DataFrame.LoadCsv(_file_address);
|
||||
_stopwatch.Stop();
|
||||
bts.Log.Gen.info($"CSVReaderStream.myOnFirstSubscriber stream csv load col_count: {df.Columns.Count} rows, time: {_stopwatch.ElapsedMilliseconds} msecs");
|
||||
_stopwatch.Start();
|
||||
IBlueRowCollection rows = BlueDataUtility.createRowsFromCSVFileWithoutTypes(_file_address);
|
||||
_stopwatch.Stop();
|
||||
bts.Log.Gen.info($"CSVReaderStream.myOnFirstSubscriber stream csv load count: {rows.Count} rows, time: {_stopwatch.ElapsedMilliseconds} msecs");
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using BCG;
|
||||
|
||||
namespace bts {
|
||||
[DataStreamUserRespresentation("oldSchemaGuesser")]
|
||||
public class SchemaGuesserStream : ViewStream {
|
||||
|
||||
private IBlueRowCollection _rows = null;
|
||||
@@ -31,4 +30,4 @@ namespace bts {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -4,9 +4,9 @@ namespace bts.SilverPine {
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
[DataStreamUserRespresentation("DateTimeExpansionStream")]
|
||||
public class DateTimeExpansionStream : ViewStream {
|
||||
public DateTimeExpansionStream(ViewStream parent_stream, string inp_col) {
|
||||
[DataStreamUserRespresentation("DateTimeExpanderStream")]
|
||||
public class DateTimeExpanstionStream : ViewStream {
|
||||
public DateTimeExpanstionStream(ViewStream parent_stream, string inp_col) {
|
||||
Func<IBlueTableSchema, IBlueTableSchema> get_schema = (s) => {
|
||||
IBlueTableSchema rv = s.add_column(System.TypeCode.DateTime, $"{inp_col}_date");
|
||||
rv = rv.add_column(System.TypeCode.String, $"{inp_col}_day");
|
||||
@@ -35,4 +35,4 @@ namespace bts.SilverPine {
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
|
||||
using BCG;
|
||||
using BCG.Utilities.General;
|
||||
|
||||
using bts;
|
||||
@@ -44,7 +43,7 @@ namespace BCG {
|
||||
_last_fire_time = DateTime.Now;
|
||||
IBlueRow nr = new BlueRow(_schema, _id++, _last_fire_time,
|
||||
_last_fire_time.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
_table = _table.Add(nr);
|
||||
_table.add_row(nr);
|
||||
var dp = BlueDataUtility.build_dp_inc(_table, myLastValue as DataPacket);
|
||||
myFireEvent(dp);
|
||||
}
|
||||
@@ -88,17 +87,3 @@ namespace BCG {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//namespace bts.BlueOrb {
|
||||
// [DataStreamUserRespresentation("MillisecondStream")]
|
||||
// public class MillisecondStream : ViewStream {
|
||||
// public MillisecondStream(ViewStreamDatabase vsd, int interval_msecs, int size) {
|
||||
// ViewStream rs = new BCG.MillisecondStream(vsd, interval_msecs, size);
|
||||
// mySetRealSource(rs);
|
||||
// }
|
||||
|
||||
// public MillisecondStream(int interval_msecs, int size)
|
||||
// : this(interval_msecs, size) {
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,124 +1,124 @@
|
||||
//namespace bts.SilverPine {
|
||||
// using BCG;
|
||||
namespace bts.SilverPine {
|
||||
using BCG;
|
||||
|
||||
// using bts;
|
||||
// //using bts.collections;
|
||||
using bts;
|
||||
using bts.collections;
|
||||
|
||||
// using System;
|
||||
// using System.CodeDom;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Linq;
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
// // Given 2 filters, and 2 columns, finds the different in the value of the 2 columns from the 2 rows
|
||||
// // so:
|
||||
// // f1(base_stream.rows)[col1] - f1(base_stream.rows)[col2]
|
||||
// [DataStreamUserRespresentation("ColDiff")]
|
||||
// public class ColumnDifferenceStream : ViewStream {
|
||||
// private readonly ViewStream _base_stream;
|
||||
// private readonly FilterStream.OnFilter _f1, _f2;
|
||||
// private readonly string _c1, _c2;
|
||||
// Given 2 filters, and 2 columns, finds the different in the value of the 2 columns from the 2 rows
|
||||
// so:
|
||||
// f1(base_stream.rows)[col1] - f1(base_stream.rows)[col2]
|
||||
[DataStreamUserRespresentation("ColDiff")]
|
||||
public class ColumnDifferenceStream : ViewStream {
|
||||
private readonly ViewStream _base_stream;
|
||||
private readonly FilterStream.OnFilter _f1, _f2;
|
||||
private readonly string _c1, _c2;
|
||||
|
||||
// public ColumnDifferenceStream(ViewStream base_stream, FilterStream.OnFilter f1, FilterStream.OnFilter f2, string col1, string col2) {
|
||||
// _base_stream = base_stream;
|
||||
// _f1 = f1;
|
||||
// _f2 = f2;
|
||||
// _c1 = col1;
|
||||
// _c2 = col2;
|
||||
// }
|
||||
public ColumnDifferenceStream(ViewStream base_stream, FilterStream.OnFilter f1, FilterStream.OnFilter f2, string col1, string col2) {
|
||||
_base_stream = base_stream;
|
||||
_f1 = f1;
|
||||
_f2 = f2;
|
||||
_c1 = col1;
|
||||
_c2 = col2;
|
||||
}
|
||||
|
||||
// public ColumnDifferenceStream(ViewStream base_stream, string f1, string f2, string col1, string col2) {
|
||||
// FilterStream.OnFilter f1_del = r => {
|
||||
// BooleanExpressionFilter rv = new BooleanExpressionFilter(f1);
|
||||
// return rv.filter(r);
|
||||
// };
|
||||
// FilterStream.OnFilter f2_del = r => {
|
||||
// BooleanExpressionFilter rv = new BooleanExpressionFilter(f2);
|
||||
// return rv.filter(r);
|
||||
// };
|
||||
// ViewStream rs = new ColumnDifferenceStream(base_stream, f1_del, f2_del, col1, col2);
|
||||
// mySetRealSource(rs);
|
||||
// }
|
||||
public ColumnDifferenceStream(ViewStream base_stream, string f1, string f2, string col1, string col2) {
|
||||
FilterStream.OnFilter f1_del = r => {
|
||||
BooleanExpressionFilter rv = new BooleanExpressionFilter(f1);
|
||||
return rv.filter(r);
|
||||
};
|
||||
FilterStream.OnFilter f2_del = r => {
|
||||
BooleanExpressionFilter rv = new BooleanExpressionFilter(f2);
|
||||
return rv.filter(r);
|
||||
};
|
||||
ViewStream rs = new ColumnDifferenceStream(base_stream, f1_del, f2_del, col1, col2);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
// // for each row, does a row[new_col_name] = row[col1] - rows[row_ffset][col2]
|
||||
// // we should generlize this for any math operation
|
||||
// public ColumnDifferenceStream(ViewStream parent_stream, string sort_col_name, int row_offset, string col1, string col2, string diff_col_name, double optional_perc_diff_filter = 0.0) {
|
||||
// // use GlobalMapStream
|
||||
// string diff_col_perc_name = $"{diff_col_name}_percentage";
|
||||
// System.Func<System.Collections.Generic.List<BCG.IBlueRow>, uint, BCG.IBlueRow> g_map_func = (rows, idx) => {
|
||||
// int minuend_idx = Convert.ToInt32(idx);
|
||||
// var inp_schema = rows[0].schema;
|
||||
// var out_schema = inp_schema.add_column(TypeCode.Double, diff_col_name);
|
||||
// out_schema = out_schema.add_column(TypeCode.Double, diff_col_perc_name);
|
||||
// // minuend - subtrahend
|
||||
// IBlueRow minuend_row = rows.ElementAt(minuend_idx);
|
||||
// MutableBlueRow rv = new MutableBlueRow(out_schema, minuend_row);
|
||||
// int subtrahend_index = minuend_idx + row_offset;
|
||||
// double diff_val = Double.NaN, diff_val_perc = Double.NaN;
|
||||
// if (subtrahend_index >= 0) {
|
||||
// try {
|
||||
// IBlueRow subtrahend_row = rows.ElementAt(subtrahend_index);
|
||||
// diff_val = minuend_row.get<double>(col1) - subtrahend_row.get<double>(col2);
|
||||
// diff_val_perc = 100.0 * diff_val / subtrahend_row.get<double>(col1);
|
||||
// } catch (Exception ex) {
|
||||
// Log.assert(false, ex.Message);
|
||||
// }
|
||||
// }
|
||||
// rv.setValue(diff_col_name, diff_val);
|
||||
// rv.setValue(diff_col_perc_name, diff_val_perc);
|
||||
// return rv;
|
||||
// };
|
||||
// ViewStream rs = new GlobalMapStream(parent_stream, sort_col_name, g_map_func);
|
||||
// if (optional_perc_diff_filter != 0) {
|
||||
// rs = new FilterStream(rs, r => {
|
||||
// double diff_val_perc = r.get<double>(diff_col_perc_name);
|
||||
// double abs_diff_val_perc = Math.Abs(diff_val_perc);
|
||||
// return abs_diff_val_perc >= optional_perc_diff_filter;
|
||||
// });
|
||||
// }
|
||||
// mySetRealSource(rs);
|
||||
// }
|
||||
// for each row, does a row[new_col_name] = row[col1] - rows[row_ffset][col2]
|
||||
// we should generlize this for any math operation
|
||||
public ColumnDifferenceStream(ViewStream parent_stream, string sort_col_name, int row_offset, string col1, string col2, string diff_col_name, double optional_perc_diff_filter = 0.0) {
|
||||
// use GlobalMapStream
|
||||
string diff_col_perc_name = $"{diff_col_name}_percentage";
|
||||
System.Func<System.Collections.Generic.List<BCG.IBlueRow>, uint, BCG.IBlueRow> g_map_func = (rows, idx) => {
|
||||
int minuend_idx = Convert.ToInt32(idx);
|
||||
var inp_schema = rows[0].schema;
|
||||
var out_schema = inp_schema.add_column(TypeCode.Double, diff_col_name);
|
||||
out_schema = out_schema.add_column(TypeCode.Double, diff_col_perc_name);
|
||||
// minuend - subtrahend
|
||||
IBlueRow minuend_row = rows.ElementAt(minuend_idx);
|
||||
MutableBlueRow rv = new MutableBlueRow(out_schema, minuend_row);
|
||||
int subtrahend_index = minuend_idx + row_offset;
|
||||
double diff_val = Double.NaN, diff_val_perc = Double.NaN;
|
||||
if (subtrahend_index >= 0) {
|
||||
try {
|
||||
IBlueRow subtrahend_row = rows.ElementAt(subtrahend_index);
|
||||
diff_val = minuend_row.get<double>(col1) - subtrahend_row.get<double>(col2);
|
||||
diff_val_perc = 100.0 * diff_val / subtrahend_row.get<double>(col1);
|
||||
} catch (Exception ex) {
|
||||
Log.assert(false, ex.Message);
|
||||
}
|
||||
}
|
||||
rv.setValue(diff_col_name, diff_val);
|
||||
rv.setValue(diff_col_perc_name, diff_val_perc);
|
||||
return rv;
|
||||
};
|
||||
ViewStream rs = new GlobalMapStream(parent_stream, sort_col_name, g_map_func);
|
||||
if (optional_perc_diff_filter != 0) {
|
||||
rs = new FilterStream(rs, r => {
|
||||
double diff_val_perc = r.get<double>(diff_col_perc_name);
|
||||
double abs_diff_val_perc = Math.Abs(diff_val_perc);
|
||||
return abs_diff_val_perc >= optional_perc_diff_filter;
|
||||
});
|
||||
}
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
// protected override void myOnFirstSubscriber() {
|
||||
// _base_stream.onChange += _handle_base_stream_update;
|
||||
// }
|
||||
protected override void myOnFirstSubscriber() {
|
||||
_base_stream.onChange += _handle_base_stream_update;
|
||||
}
|
||||
|
||||
// protected override void myOnLastSubscriber() {
|
||||
// _base_stream.onChange -= _handle_base_stream_update;
|
||||
// }
|
||||
protected override void myOnLastSubscriber() {
|
||||
_base_stream.onChange -= _handle_base_stream_update;
|
||||
}
|
||||
|
||||
// private void _handle_base_stream_update(object dp_obj) {
|
||||
// // could have been done with filter and cartesian prod, and then math
|
||||
// DataPacket dp = dp_obj as DataPacket;
|
||||
// List<IBlueRow> rows = dp.newRows.to_list();
|
||||
// var f1_rows = rows.Where(r => _f1(r));
|
||||
// //Log.assert(f1_rows.Count() == 1);
|
||||
// var f2_rows = rows.Where(r => _f2(r));
|
||||
// //Log.assert(f2_rows.Count() == 1);
|
||||
// if (f1_rows != null && f1_rows.Count() > 0 && f2_rows != null && f2_rows.Count() > 0) {
|
||||
// IBlueRow f1_r = f1_rows.ElementAt(0);
|
||||
// IBlueRow f2_r = f2_rows.ElementAt(0);
|
||||
// double diff = f1_r.get<double>(_c1) - f2_r.get<double>(_c2);
|
||||
// IBlueTableSchema out_schema = f1_r.schema.add_columns(Tuple.Create(typeof(double), "diff"));
|
||||
// BlueTable out_table = new BlueTable(out_schema);
|
||||
// MutableBlueRow out_row = new MutableBlueRow(out_schema, f1_r);
|
||||
// out_row.setValue("diff", diff);
|
||||
// out_table.addRow(out_row);
|
||||
// DataPacket dp_out = BlueDataUtility.build_dp(out_table, myLastValue as DataPacket);
|
||||
// myFireEvent(dp_out);
|
||||
// } else {
|
||||
// IBlueRow f1_r = rows.ElementAt(0);
|
||||
// IBlueRow f2_r = rows.ElementAt(0);
|
||||
// double diff = Double.NaN;
|
||||
// IBlueTableSchema out_schema = f1_r.schema.add_columns(Tuple.Create(typeof(double), "diff"));
|
||||
// BlueTable out_table = new BlueTable(out_schema);
|
||||
// MutableBlueRow out_row = new MutableBlueRow(out_schema, f1_r);
|
||||
// out_row.setValue("diff", diff);
|
||||
// out_table.addRow(out_row);
|
||||
// DataPacket dp_out = BlueDataUtility.build_dp(out_table, myLastValue as DataPacket);
|
||||
// myFireEvent(dp_out);
|
||||
// }
|
||||
private void _handle_base_stream_update(object dp_obj) {
|
||||
// could have been done with filter and cartesian prod, and then math
|
||||
DataPacket dp = dp_obj as DataPacket;
|
||||
List<IBlueRow> rows = dp.newRows.to_list();
|
||||
var f1_rows = rows.Where(r => _f1(r));
|
||||
//Log.assert(f1_rows.Count() == 1);
|
||||
var f2_rows = rows.Where(r => _f2(r));
|
||||
//Log.assert(f2_rows.Count() == 1);
|
||||
if (f1_rows != null && f1_rows.Count() > 0 && f2_rows != null && f2_rows.Count() > 0) {
|
||||
IBlueRow f1_r = f1_rows.ElementAt(0);
|
||||
IBlueRow f2_r = f2_rows.ElementAt(0);
|
||||
double diff = f1_r.get<double>(_c1) - f2_r.get<double>(_c2);
|
||||
IBlueTableSchema out_schema = f1_r.schema.add_columns(Tuple.Create(typeof(double), "diff"));
|
||||
BlueTable out_table = new BlueTable(out_schema);
|
||||
MutableBlueRow out_row = new MutableBlueRow(out_schema, f1_r);
|
||||
out_row.setValue("diff", diff);
|
||||
out_table.addRow(out_row);
|
||||
DataPacket dp_out = BlueDataUtility.build_dp(out_table, myLastValue as DataPacket);
|
||||
myFireEvent(dp_out);
|
||||
} else {
|
||||
IBlueRow f1_r = rows.ElementAt(0);
|
||||
IBlueRow f2_r = rows.ElementAt(0);
|
||||
double diff = Double.NaN;
|
||||
IBlueTableSchema out_schema = f1_r.schema.add_columns(Tuple.Create(typeof(double), "diff"));
|
||||
BlueTable out_table = new BlueTable(out_schema);
|
||||
MutableBlueRow out_row = new MutableBlueRow(out_schema, f1_r);
|
||||
out_row.setValue("diff", diff);
|
||||
out_table.addRow(out_row);
|
||||
DataPacket dp_out = BlueDataUtility.build_dp(out_table, myLastValue as DataPacket);
|
||||
myFireEvent(dp_out);
|
||||
}
|
||||
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
||||
}
|
||||
Loaded 100 of 1027 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user