Skip to content

Commit 56de213

Browse files
Add SAP HANA schema collection and diagnostics (DataDog#23934)
* Add SAP HANA schema collection and diagnostics Collect SAP HANA catalog metadata (schemas, tables, columns) for Database Monitoring's Schema Explorer, mirroring the postgres implementation on the shared SchemaCollector base class. Add startup diagnostics for connection, version, and catalog-view access. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add changelog entry Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix license header year on new files Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * sap_hana: handle missing DESCRIPTION column in SYS.M_DATABASE HANA Express does not include the DESCRIPTION column in SYS.M_DATABASE. Fetch DATABASE_NAME and DESCRIPTION in separate queries so that the absence of DESCRIPTION (silently ignored) does not prevent the database name from being resolved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: align kind and dbms with dbm-metadata-processor expectations Use 'saphana_databases' as the schema payload kind and 'saphana' as the dbms identifier, matching KindSapHanaDatabases and the SapHana DBMS constant defined in the dd-go dbm-metadata-processor PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: update tests to expect saphana kind and dbms values Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: fix schema collector privilege filter and column query efficiency Remove HAS_PRIVILEGES filter from schema discovery so catalog-view grants control visibility, consistent with the Postgres schema collector. Apply max_tables trimming before fetching columns to avoid loading column data for tables that will be discarded. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: push column filter to SQL WHERE clause instead of client-side Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: address PR review wording suggestions in README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: replace "Database Monitoring's Schema Explorer" with "Data Quality features in Data Observability" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: enforce schema collection limits in SQL and stream tables Replace the three fetchall() catalog queries and in-memory filtering with a single streamed JOIN. The limited_tables CTE pushes the schema filters and the max_tables LIMIT into the database, so the agent never pulls more than max_tables tables' rows into memory regardless of total schema size. Columns are joined and ordered so each table is assembled one at a time as the cursor streams, instead of materializing every table and column up front. Verified against a live HANA Express instance that the CTE LIMIT caps tables (not joined rows) and the LIKE ... ESCAPE system-schema filter parses correctly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * sap_hana: add HanaSchemaCollector unit tests for column mapping and _get_databases Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: add schema collection memory benchmark Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: fix benchmark setup and add 50x50 baseline results - Use host port 39019 to avoid collision with test container on 39017 - Grant SELECT on SYS.M_DATABASE, SYS.TABLES, SYS.SCHEMAS, SYS.TABLE_COLUMNS (CATALOG READ alone is insufficient for these views) - Fix global declaration order bug in setup_database.py - Add benchmark_results_50x50.txt as baseline (trivial data, both modes identical) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: add 1000x1000 benchmark results (18.4x RSS reduction with limits) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: set hdbcli cursor fetch size to 10k to reduce C-layer buffering Without a fetch size, hdbcli buffers the entire query result set in its C layer before Python iterates it, contributing ~500 MiB to RSS on a 1000x1000 schema. setfetchsize(10_000) limits the client-side buffer to 10k rows per round-trip. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Revert "sap_hana: set hdbcli cursor fetch size to 10k to reduce C-layer buffering" This reverts commit 6fe80a4. * sap_hana: push max_columns limit into SQL via ROW_NUMBER() CTE Previously the query returned all columns for every table and Python discarded those beyond max_columns. On a 1000-table schema with max_columns=50 this sent 285k unnecessary rows from the server (300 tables x 950 discarded columns). A new limited_columns CTE ranks columns per table with ROW_NUMBER() OVER (PARTITION BY schema, table ORDER BY position) and the LEFT JOIN filters on rn <= max_columns, so the server only sends the first max_columns columns per table. The client-side check in _get_next() stays as a safety net. Benchmark result on 1000x1000 schema: limited mode duration 8.1s -> 1.6s (5x). Peak RSS is unchanged — memory is bounded by the Python-side column dict accumulation, not the cursor row count. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: add license headers to benchmark scripts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: flush after 50k columns instead of 10k tables The base class payload_chunk_size counts tables, which is a poor memory proxy for wide tables. HanaSchemaCollector now overrides maybe_flush to trigger after PAYLOAD_COLUMN_CHUNK_SIZE (50,000) columns instead, keeping _queued_rows bounded regardless of how wide the tables are. On the 1000x1000 benchmark schema, unlimited peak RSS drops from 1,038 MiB to 93.7 MiB (11x reduction). The limited mode (300 tables x 50 cols = 15k columns) is unaffected since it never reaches the threshold. The column count is tracked in _map_row rather than _get_next because the base class loop calls _get_next after appending the current table; counting there would cause the freshly-fetched table's columns to be lost on flush. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: raise default max_tables to 2000 and max_columns to 500 Previous defaults (300 tables, 50 columns) were conservative placeholders. With the column-based flush threshold in place, peak memory is now bounded by columns processed at once (50k) rather than total tables queued, so higher defaults are safe without a proportional memory cost increase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: hide collect_schemas config block from user-facing docs The feature is not yet backed by production quality monitors. Mark the entire collect_schemas section as hidden: true so it is omitted from conf.yaml.example until the backend is ready. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: switch schema collector to SYS.M_TABLES, SYS.VIEWS, and SYS.VIEW_COLUMNS Replace SYS.TABLES with SYS.M_TABLES to gain live RECORD_COUNT (row_count in the payload). Add SYS.VIEWS so view objects are collected alongside tables, with columns sourced from SYS.VIEW_COLUMNS (TABLE_COLUMNS does not cover views in HANA). Conditionally LEFT JOIN SYS.M_TABLE_STATISTICS at runtime for last_updated_on: the collector probes for access on first run and omits the join when the monitoring user lacks the privilege. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: update spec.yaml descriptions to reference new catalog views Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: update benchmark results with SYS.M_TABLES + SYS.VIEWS query Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: update benchmark README with current query results Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: tidy README grant order and bump example limits to defaults Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: address schema collector review feedback - Add max_views config option (SQL LIMIT on the views CTE) so view collection is bounded like tables/columns. - Update _maybe_collect_schemas to advance the schedule only on success so transient failures are retried promptly instead of being suppressed for a full interval. - Classify version-query failures: privilege/access errors reading SYS.M_DATABASE now report the privilege/access diagnostic instead of a misleading "version unsupported" result. - Drop the hostname fallback in _get_databases; skip collection and warn when the current database can't be determined to avoid mislabeled data. - Extract HanaSchemaQueryBuilder to separate SQL/query-policy concerns from the collector's streaming and flush logic. - Document why payloads flush by accumulated column count, referencing the schema-collection memory benchmark. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * sap_hana: handle single-tenant HANA Express in monitoring queries SYS views on single-tenant HANA Express lack the DATABASE_NAME column, so inject a constant SYSTEMDB value and drop the GROUP BY for SYS-schema queries, and use FILE_SIZE instead of TOTAL_SIZE for global disk usage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * sap_hana: add maintainer docstring mapping schema collector flow Document the end-to-end control flow, the query-builder/collector responsibility split, and the collection-policy decisions (SQL vs client-side caps, system-schema exclusion, optional stats join) in a module docstring, with a pointer to the memory benchmark. Addresses the reviewer's request to reduce cross-method context jumping. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Revert "sap_hana: handle single-tenant HANA Express in monitoring queries" This reverts commit fd86284. * sap_hana: address janine-c doc review feedback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * sap_hana: fix subject-verb agreement in include_schemas description Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent a034114 commit 56de213

16 files changed

Lines changed: 1736 additions & 0 deletions

File tree

sap_hana/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ To learn how to set the port number for HANA tenant, single-tenant, and system d
8181
GRANT SELECT ON SYS_DATABASES.M_VOLUME_IO_TOTAL_STATISTICS TO DD_MONITOR;
8282
```
8383

84+
To collect schema metadata for Data Quality features in Data Observability, grant select on the catalog and monitoring views that store schema, table, and column definitions. These are already covered by the `GRANT CATALOG READ` in step 2, so this is only needed if you skipped that grant:
85+
86+
```shell
87+
GRANT SELECT ON SYS.SCHEMAS TO DD_MONITOR;
88+
GRANT SELECT ON SYS.M_TABLES TO DD_MONITOR;
89+
GRANT SELECT ON SYS.TABLE_COLUMNS TO DD_MONITOR;
90+
GRANT SELECT ON SYS.VIEWS TO DD_MONITOR;
91+
GRANT SELECT ON SYS.VIEW_COLUMNS TO DD_MONITOR;
92+
GRANT SELECT ON SYS.M_TABLE_STATISTICS TO DD_MONITOR;
93+
```
94+
8495
4. Finally, run the following command to assign the monitoring role to the desired user:
8596

8697
```shell
@@ -121,6 +132,21 @@ To learn how to set the port number for HANA tenant, single-tenant, and system d
121132

122133
3. [Restart the Agent][5].
123134

135+
#### Schema collection
136+
137+
The Agent can collect SAP HANA catalog metadata (schemas, tables, views, and columns) for Data Quality features in Data Observability. When the monitoring user has access to `SYS.M_TABLE_STATISTICS`, the Agent also collects row counts and last modification times for tables. Collection is disabled by default. To enable schema collection, ensure that the monitoring user can read the required views (see [Granting privileges](#granting-privileges)) and add the following block to your `sap_hana.d/conf.yaml` file:
138+
139+
```yaml
140+
collect_schemas:
141+
enabled: true
142+
collection_interval: 600
143+
max_tables: 2000
144+
max_views: 2000
145+
max_columns: 500
146+
```
147+
148+
See the [sample sap_hana.d/conf.yaml][4] for all available schema collection options, including `include_schemas` and `exclude_schemas`.
149+
124150
### Validation
125151

126152
Run the [Agent's status subcommand][6] and look for `sap_hana` under the Checks section.

sap_hana/assets/configuration/spec.yaml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,67 @@ files:
9494
example: false
9595
type: boolean
9696
- template: instances/tls
97+
- name: collect_schemas
98+
hidden: true
99+
description: |
100+
Configure collection of SAP HANA catalog metadata (schemas, tables,
101+
views, and columns) for Data Quality features in Data Observability.
102+
options:
103+
- name: enabled
104+
description: |
105+
Enable collection of catalog metadata. When enabled, the Agent
106+
queries `SYS.M_TABLES`, `SYS.VIEWS`, `SYS.TABLE_COLUMNS`, and
107+
`SYS.VIEW_COLUMNS` and emits schema metadata payloads.
108+
value:
109+
type: boolean
110+
example: false
111+
- name: collection_interval
112+
description: |
113+
Set the schema collection interval (in seconds). Catalog data
114+
changes slowly; 600s (10 min) is a reasonable default.
115+
value:
116+
type: number
117+
example: 600
118+
- name: max_tables
119+
description: |
120+
Maximum number of tables to collect per cycle across all schemas.
121+
value:
122+
type: integer
123+
example: 2000
124+
- name: max_columns
125+
description: |
126+
Maximum number of columns to collect per table.
127+
value:
128+
type: integer
129+
example: 500
130+
- name: max_views
131+
description: |
132+
Maximum number of views to collect per cycle across all schemas.
133+
value:
134+
type: integer
135+
example: 2000
136+
- name: include_schemas
137+
description: |
138+
A list of schema names to include. Any schema whose name is in
139+
this list is included. If empty, all schemas (other than
140+
those excluded) are included.
141+
value:
142+
type: array
143+
items:
144+
type: string
145+
example:
146+
- "MY_SCHEMA"
147+
- name: exclude_schemas
148+
description: |
149+
A list of schema names to exclude. Any schema whose name is in
150+
this list is excluded. SAP HANA system schemas are always
151+
excluded regardless of this setting.
152+
value:
153+
type: array
154+
items:
155+
type: string
156+
example:
157+
- "TMP_SCHEMA"
97158
- template: instances/default
98159
- template: logs
99160
example:
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Schema Collection Memory Benchmark
2+
3+
Demonstrates the memory impact of the `max_tables` and `max_columns` limits added to
4+
`HanaSchemaCollector`. It stands up a SAP HANA Express container, fills it with a 1000×1000
5+
schema (1000 tables, 1000 columns each), then runs the real `collect_schemas()` code path
6+
twice — once with limits enabled and once effectively unlimited — in isolated subprocesses
7+
and compares peak RSS.
8+
9+
## Prerequisites
10+
11+
- Docker with sufficient memory (≥8 GB recommended for HANA Express).
12+
- A Python environment with the following installed:
13+
```
14+
pip install -e ../../.. # datadog_checks_base (repo root)
15+
pip install -e ../.. # sap_hana integration
16+
pip install hdbcli==2.21.28
17+
```
18+
The integration's hatch test environment already satisfies this.
19+
20+
## Run
21+
22+
```bash
23+
cd sap_hana/benchmarks/schema_collection_memory
24+
25+
# 1. Start SAP HANA Express (startup takes 5–10 minutes).
26+
PASSWORD=Admin1337 docker compose up -d
27+
docker logs -f saphanabenchmark # wait for "Startup finished!"
28+
29+
# 2. Populate the database and run both modes.
30+
python benchmark.py
31+
32+
# Re-run measurements without recreating the schema.
33+
python benchmark.py --skip-setup
34+
35+
# 3. Tear down.
36+
docker compose down --volumes
37+
```
38+
39+
Results are written to `results/benchmark_results.txt`.
40+
41+
## Tuning
42+
43+
| Constant | File | Default | Notes |
44+
|---|---|---|---|
45+
| `SAP_HANA_VERSION` | `docker-compose.yaml` env var | `2.00.076.00.20231004.2` | Pin to a known-good image tag. |
46+
| `NUM_TABLES` | `setup_database.py` | 1000 | Lower if setup is too slow. |
47+
| `NUM_COLUMNS` | `setup_database.py` | 1000 | Lower if HANA Express rejects wide tables. |
48+
49+
HANA Express has resource constraints. If `CREATE TABLE` fails with a column-count or
50+
memory error, set `NUM_COLUMNS` to 500 or lower.
51+
52+
## Notes on memory investigation
53+
54+
### `setfetchsize` (no effect on memory)
55+
`cursor.setfetchsize(10_000)` was tried on the hdbcli cursor before `execute()` to reduce
56+
the C-layer result buffer. It had no measurable effect on peak RSS (1042 MiB → 1043 MiB).
57+
The reason: the dominant memory consumer is the Python-side `_queued_rows` list
58+
accumulating all table dicts before the single `json.dumps` flush — not the hdbcli C
59+
layer. The base `SchemaCollector` flushes when `len(_queued_rows) >= payload_chunk_size`
60+
(default 10,000) or on the last database. Since HANA always reports one database and a
61+
1000-table schema is below the 10,000 threshold, everything flushes at once. The
62+
`max_tables` / `max_columns` limits are the effective memory control.
63+
64+
### Column-based flush threshold (1.5x RSS reduction with limits)
65+
The base class `payload_chunk_size` counts tables, which is a poor proxy for memory when
66+
tables are wide. `HanaSchemaCollector` overrides `maybe_flush` to flush after every
67+
`PAYLOAD_COLUMN_CHUNK_SIZE` (50,000) columns instead. For 1000-column tables, this flushes
68+
every 50 tables, keeping `_queued_rows` from growing unboundedly. Result on the 1000×1000
69+
schema (RSS before = without column-flush override; RSS after = with override):
70+
71+
| Mode | RSS before | RSS after | Payloads |
72+
|------|-----------|-----------|---------|
73+
| unlimited (no limits) | 1,038 MiB | 93.7 MiB | 21 |
74+
| limited (300 tables × 50 cols) | 56.4 MiB | 61.5 MiB | 1 |
75+
76+
The limited case is unaffected: 300 × 50 = 15,000 columns never reaches the 50,000
77+
threshold so it still flushes once at the end.
78+
79+
### SQL column limit via `ROW_NUMBER()`
80+
The original query joined `SYS.TABLE_COLUMNS` without a column count cap, so the server
81+
returned all 1000 columns per table regardless of `max_columns`; Python discarded the
82+
excess. Pushing the limit into SQL with a `limited_columns` CTE using `ROW_NUMBER() OVER
83+
(PARTITION BY schema, table ORDER BY position)` means the server only sends the first
84+
`max_columns` columns per table. Result on the 1000×1000 schema (duration before = without
85+
ROW_NUMBER cap; duration after = with cap):
86+
87+
| Mode | Duration before | Duration after |
88+
|---------|-----------------|----------------|
89+
| limited (max_tables=300, max_columns=50) | 8.1s | 2.2s |
90+
| unlimited (max_tables=10M, max_columns=10M) | 48.8s | 50.7s |
91+
92+
Peak RSS was unchanged in both modes — the Python-side column dicts are bounded by
93+
`max_columns` either way, so peak Python heap stays the same. The gain is query
94+
efficiency: 285,000 fewer rows sent from the server (300 tables × 950 discarded
95+
columns) in the limited case.
96+
97+
## Expected outcome
98+
99+
The limited run (max\_tables=300, max\_columns=50) processes 300 tables × 50 columns =
100+
15,000 column dicts. The unlimited run processes 1000 tables × 1000 columns = 1,000,000
101+
column dicts, all held in memory at once before the single `json.dumps` flush. The
102+
unlimited peak RSS is expected to be ~1.5x larger than the limited run.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# (C) Datadog, Inc. 2026-present
2+
# All rights reserved
3+
# Licensed under a 3-clause BSD style license (see LICENSE)
4+
#!/usr/bin/env python3
5+
"""Orchestrate limited vs unlimited schema collection runs and compare peak memory."""
6+
7+
from __future__ import annotations
8+
9+
import argparse
10+
import json
11+
import os
12+
import subprocess
13+
import sys
14+
import time
15+
16+
RESULTS_DIR = os.path.join(os.path.dirname(__file__), 'results')
17+
RESULTS_FILE = os.path.join(RESULTS_DIR, 'benchmark_results.txt')
18+
RUN_COLLECTOR = os.path.join(os.path.dirname(__file__), 'run_collector.py')
19+
SETUP_DATABASE = os.path.join(os.path.dirname(__file__), 'setup_database.py')
20+
21+
HOST = 'localhost'
22+
PORT = 39019
23+
24+
25+
def wait_for_hana(host: str, port: int, timeout: int = 600) -> None:
26+
print(f'Waiting for SAP HANA at {host}:{port} (up to {timeout}s)...', flush=True)
27+
deadline = time.time() + timeout
28+
while time.time() < deadline:
29+
try:
30+
from hdbcli.dbapi import Connection as HanaConnection
31+
32+
conn = HanaConnection(address=host, port=port, user='system', password='Admin1337')
33+
conn.close()
34+
print('HANA is ready.', flush=True)
35+
return
36+
except Exception:
37+
time.sleep(5)
38+
print('ERROR: HANA did not become ready in time.', file=sys.stderr)
39+
sys.exit(1)
40+
41+
42+
def run_mode(python: str, mode: str, host: str, port: int) -> dict:
43+
print(f'Running mode={mode}...', flush=True)
44+
result = subprocess.run(
45+
[python, RUN_COLLECTOR, '--mode', mode, '--host', host, '--port', str(port)],
46+
capture_output=True,
47+
text=True,
48+
)
49+
if result.returncode != 0:
50+
print(f'ERROR running mode={mode}:\n{result.stderr}', file=sys.stderr)
51+
sys.exit(1)
52+
return json.loads(result.stdout.strip())
53+
54+
55+
def mib(value_bytes: int) -> str:
56+
return f'{value_bytes / 1024 / 1024:.1f} MiB'
57+
58+
59+
def build_report(limited: dict, unlimited: dict) -> str:
60+
rss_ratio = unlimited['peak_rss_kb'] / max(limited['peak_rss_kb'], 1)
61+
lines = [
62+
'SAP HANA Schema Collection Memory Benchmark',
63+
'=' * 60,
64+
'',
65+
f"{'Mode':<12} {'Peak RSS':>12} {'Tracemalloc':>14} {'Payloads':>10} {'Payload bytes':>15} {'Duration':>10}",
66+
'-' * 75,
67+
]
68+
for r in (limited, unlimited):
69+
lines.append(
70+
f"{r['mode']:<12}"
71+
f" {mib(r['peak_rss_kb'] * 1024):>12}"
72+
f" {mib(r['tracemalloc_peak_bytes']):>14}"
73+
f" {r['payloads']:>10}"
74+
f" {r['total_payload_bytes']:>15,}"
75+
f" {r['duration_s']:>9.1f}s"
76+
)
77+
lines += [
78+
'',
79+
f"Memory reduction: {rss_ratio:.1f}x less peak RSS with limits enabled",
80+
" limited : max_tables=300, max_columns=50",
81+
" unlimited: max_tables=10_000_000, max_columns=10_000_000",
82+
'',
83+
]
84+
return '\n'.join(lines)
85+
86+
87+
def main() -> None:
88+
parser = argparse.ArgumentParser(description='Run the schema collection memory benchmark.')
89+
parser.add_argument('--skip-setup', action='store_true', help='Skip database setup (schema already populated).')
90+
parser.add_argument('--python', default=sys.executable, help='Python interpreter for child runs.')
91+
parser.add_argument('--host', default=HOST)
92+
parser.add_argument('--port', type=int, default=PORT)
93+
args = parser.parse_args()
94+
95+
wait_for_hana(args.host, args.port)
96+
97+
if not args.skip_setup:
98+
print('Running database setup...', flush=True)
99+
result = subprocess.run(
100+
[args.python, SETUP_DATABASE, '--host', args.host, '--port', str(args.port)],
101+
check=True,
102+
)
103+
_ = result
104+
105+
limited = run_mode(args.python, 'limited', args.host, args.port)
106+
unlimited = run_mode(args.python, 'unlimited', args.host, args.port)
107+
108+
report = build_report(limited, unlimited)
109+
print(report)
110+
111+
os.makedirs(RESULTS_DIR, exist_ok=True)
112+
with open(RESULTS_FILE, 'w') as f:
113+
f.write(report)
114+
print(f'Results written to {RESULTS_FILE}')
115+
116+
117+
if __name__ == '__main__':
118+
sys.exit(main())
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
services:
2+
saphanabenchmark:
3+
container_name: saphanabenchmark
4+
image: saplabs/hanaexpress:${SAP_HANA_VERSION:-latest}
5+
ulimits:
6+
nofile:
7+
soft: 1048576
8+
hard: 1048576
9+
sysctls:
10+
kernel.shmmax: 1073741824
11+
net.ipv4.ip_local_port_range: "40000 60999"
12+
ports:
13+
- "39019:39017"
14+
environment:
15+
- PASSWORD=${PASSWORD}
16+
entrypoint:
17+
- sh
18+
- -c
19+
- echo "{\"master_password\":\"$$PASSWORD\"}" > /tmp/hana_password.json;cat /tmp/hana_password.json;/run_hana --agree-to-sap-license --passwords-url file:///tmp/hana_password.json

sap_hana/benchmarks/schema_collection_memory/results/.gitkeep

Whitespace-only changes.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SAP HANA Schema Collection Memory Benchmark
2+
============================================================
3+
4+
Mode Peak RSS Tracemalloc Payloads Payload bytes Duration
5+
---------------------------------------------------------------------------
6+
limited 61.5 MiB 8.6 MiB 1 1,772,208 2.2s
7+
unlimited 93.7 MiB 24.2 MiB 21 95,425,468 50.7s
8+
9+
Memory reduction: 1.5x less peak RSS with limits enabled
10+
limited : max_tables=300, max_columns=50
11+
unlimited: max_tables=10_000_000, max_columns=10_000_000
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SAP HANA Schema Collection Memory Benchmark
2+
============================================================
3+
4+
Mode Peak RSS Tracemalloc Payloads Payload bytes Duration
5+
---------------------------------------------------------------------------
6+
limited 45.0 MiB 1.2 MiB 1 243,885 0.3s
7+
unlimited 45.0 MiB 1.2 MiB 1 243,885 0.3s
8+
9+
Memory reduction: 1.0x less peak RSS with limits enabled
10+
limited : max_tables=300, max_columns=50
11+
unlimited: max_tables=10_000_000, max_columns=10_000_000

0 commit comments

Comments
 (0)