Skip to content

Commit b604010

Browse files
authored
Add HTTP APIs (#1996)
### What problem does this PR solve? 1. SHOW BUFFER; 2. SHOW PROFILES; 4. SHOW MEMINDEX; # no document 5. SHOW QUERIES; # no document ### Type of change - [x] New Feature (non-breaking change which adds functionality) Signed-off-by: Jin Hai <[email protected]>
1 parent 3f2a0f5 commit b604010

File tree

3 files changed

+365
-1
lines changed

3 files changed

+365
-1
lines changed

docs/references/http_api_reference.mdx

+165-1
Original file line numberDiff line numberDiff line change
@@ -2370,4 +2370,168 @@ A `500` HTTP status code indicates an error condition. The response includes a J
23702370
</TabItem>
23712371
</Tabs>
23722372
2373-
---
2373+
---
2374+
2375+
## Show buffer
2376+
2377+
**GET** `/instance/buffer`
2378+
2379+
List the cached buffer objects in database.
2380+
2381+
### Request
2382+
2383+
- Method: GET
2384+
- URL: `/instance/buffer`
2385+
- Headers: `accept: application/json`
2386+
2387+
#### Request example
2388+
2389+
```shell
2390+
curl --request GET \
2391+
--url http://localhost:23820/instance/buffer \
2392+
--header 'accept: application/json'
2393+
```
2394+
2395+
### Response
2396+
2397+
<Tabs
2398+
defaultValue="s200"
2399+
values={[
2400+
{label: 'Status code 200', value: 's200'},
2401+
{label: 'Status code 500', value: 's500'},
2402+
]}>
2403+
<TabItem value="s200">
2404+
2405+
The response includes a JSON object like the following:
2406+
2407+
```shell
2408+
{
2409+
"buffer": [
2410+
{
2411+
"buffered_type": "Persistent",
2412+
"path": "/var/infinity/data/nlAn5spku9_db_default_db/sNzUhKy3er_table_table1/seg_0/blk_0/0.col",
2413+
"size": "32768",
2414+
"status": "Freed",
2415+
"type": "data"
2416+
},
2417+
{
2418+
"buffered_type": "Persistent",
2419+
"path": "/var/infinity/data/nlAn5spku9_db_default_db/sNzUhKy3er_table_table1/seg_0/blk_0/2.col",
2420+
"size": "131072",
2421+
"status": "Freed",
2422+
"type": "data"
2423+
},
2424+
{
2425+
"buffered_type": "Persistent",
2426+
"path": "/var/infinity/data/nlAn5spku9_db_default_db/sNzUhKy3er_table_table1/seg_0/blk_0/version",
2427+
"size": "65536",
2428+
"status": "Freed",
2429+
"type": "version data"
2430+
}
2431+
],
2432+
"error_code": 0
2433+
}
2434+
```
2435+
2436+
- `"error_code"`: `integer`
2437+
`0`: The operation succeeds.
2438+
2439+
</TabItem>
2440+
<TabItem value="s500">
2441+
2442+
A `500` HTTP status code indicates an error condition. The response includes a JSON object like the following:
2443+
2444+
```shell
2445+
{
2446+
"error_code": 2005,
2447+
"error_message": "Not support in maintenance mode"
2448+
}
2449+
```
2450+
2451+
- `"error_code"`: `integer`
2452+
A non-zero value indicates a specific error condition.
2453+
- `"error_message"`: `string`
2454+
When `error_code` is non-zero, `"error_message"` provides additional details about the error.
2455+
2456+
</TabItem>
2457+
</Tabs>
2458+
2459+
---
2460+
2461+
## Show profiles
2462+
2463+
**GET** `/instance/profiles`
2464+
2465+
When set session variable 'enable_profiling', Infinity will record query profile information. This command is to list recorded queries profile.
2466+
2467+
### Request
2468+
2469+
- Method: GET
2470+
- URL: `/instance/profiles`
2471+
- Headers: `accept: application/json`
2472+
2473+
#### Request example
2474+
2475+
```shell
2476+
curl --request GET \
2477+
--url http://localhost:23820/instance/profiles \
2478+
--header 'accept: application/json'
2479+
```
2480+
2481+
### Response
2482+
2483+
<Tabs
2484+
defaultValue="s200"
2485+
values={[
2486+
{label: 'Status code 200', value: 's200'},
2487+
{label: 'Status code 500', value: 's500'},
2488+
]}>
2489+
<TabItem value="s200">
2490+
2491+
The response includes a JSON object like the following:
2492+
2493+
```shell
2494+
{
2495+
"error_code": 0,
2496+
"profiles": [
2497+
{
2498+
"command parsing": "250us",
2499+
"commit": "0ns",
2500+
"execution": "380us",
2501+
"logical plan building": "133us",
2502+
"physical plan building": "44us",
2503+
"pipeline building": "38us",
2504+
"plan optimizing": "1000ns",
2505+
"record_no": "0",
2506+
"rollback": "35us",
2507+
"task building": "70us",
2508+
"total_cost": "951us"
2509+
}
2510+
]
2511+
}
2512+
```
2513+
2514+
- `"error_code"`: `integer`
2515+
`0`: The operation succeeds.
2516+
2517+
</TabItem>
2518+
<TabItem value="s500">
2519+
2520+
A `500` HTTP status code indicates an error condition. The response includes a JSON object like the following:
2521+
2522+
```shell
2523+
{
2524+
"error_code": 2005,
2525+
"error_message": "Not support in maintenance mode"
2526+
}
2527+
```
2528+
2529+
- `"error_code"`: `integer`
2530+
A non-zero value indicates a specific error condition.
2531+
- `"error_message"`: `string`
2532+
When `error_code` is non-zero, `"error_message"` provides additional details about the error.
2533+
2534+
</TabItem>
2535+
</Tabs>
2536+
2537+
---

example/http/show_metrics.sh

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright(C) 2024 InfiniFlow, Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# show buffer
16+
echo -e '\n-- show buffer'
17+
curl --request GET \
18+
--url http://localhost:23820/instance/buffer \
19+
--header 'accept: application/json'
20+
21+
# show profiles
22+
echo -e '\n\n-- show profiles'
23+
curl --request GET \
24+
--url http://localhost:23820/instance/profiles \
25+
--header 'accept: application/json'
26+
27+
# show memindex
28+
echo -e '\n\n-- show memindex'
29+
curl --request GET \
30+
--url http://localhost:23820/instance/memindex \
31+
--header 'accept: application/json'
32+
33+
# show queries
34+
echo -e '\n\n-- show queries'
35+
curl --request GET \
36+
--url http://localhost:23820/instance/queries \
37+
--header 'accept: application/json'
38+

src/network/http_server.cpp

+162
Original file line numberDiff line numberDiff line change
@@ -3313,6 +3313,162 @@ class SetConfigHandler final : public HttpRequestHandler {
33133313
}
33143314
};
33153315

3316+
class ShowBufferHandler final : public HttpRequestHandler {
3317+
public:
3318+
SharedPtr<OutgoingResponse> handle(const SharedPtr<IncomingRequest> &request) final {
3319+
auto infinity = Infinity::RemoteConnect();
3320+
DeferFn defer_fn([&]() { infinity->RemoteDisconnect(); });
3321+
3322+
nlohmann::json json_response;
3323+
HTTPStatus http_status;
3324+
QueryResult result = infinity->Query("show buffer");
3325+
3326+
if (result.IsOk()) {
3327+
SizeT block_rows = result.result_table_->DataBlockCount();
3328+
for (SizeT block_id = 0; block_id < block_rows; ++block_id) {
3329+
DataBlock *data_block = result.result_table_->GetDataBlockById(block_id).get();
3330+
auto row_count = data_block->row_count();
3331+
auto column_cnt = result.result_table_->ColumnCount();
3332+
for (int row = 0; row < row_count; ++row) {
3333+
nlohmann::json json_table;
3334+
for (SizeT col = 0; col < column_cnt; ++col) {
3335+
const String &column_name = result.result_table_->GetColumnNameById(col);
3336+
Value value = data_block->GetValue(col, row);
3337+
const String &column_value = value.ToString();
3338+
json_table[column_name] = column_value;
3339+
}
3340+
json_response["buffer"].push_back(json_table);
3341+
}
3342+
}
3343+
json_response["error_code"] = 0;
3344+
http_status = HTTPStatus::CODE_200;
3345+
} else {
3346+
json_response["error_code"] = result.ErrorCode();
3347+
json_response["error_message"] = result.ErrorMsg();
3348+
http_status = HTTPStatus::CODE_500;
3349+
}
3350+
3351+
return ResponseFactory::createResponse(http_status, json_response.dump());
3352+
}
3353+
};
3354+
3355+
class ShowProfilesHandler final : public HttpRequestHandler {
3356+
public:
3357+
SharedPtr<OutgoingResponse> handle(const SharedPtr<IncomingRequest> &request) final {
3358+
auto infinity = Infinity::RemoteConnect();
3359+
DeferFn defer_fn([&]() { infinity->RemoteDisconnect(); });
3360+
3361+
nlohmann::json json_response;
3362+
HTTPStatus http_status;
3363+
QueryResult result = infinity->Query("show profiles");
3364+
3365+
if (result.IsOk()) {
3366+
SizeT block_rows = result.result_table_->DataBlockCount();
3367+
for (SizeT block_id = 0; block_id < block_rows; ++block_id) {
3368+
DataBlock *data_block = result.result_table_->GetDataBlockById(block_id).get();
3369+
auto row_count = data_block->row_count();
3370+
auto column_cnt = result.result_table_->ColumnCount();
3371+
for (int row = 0; row < row_count; ++row) {
3372+
nlohmann::json json_table;
3373+
for (SizeT col = 0; col < column_cnt; ++col) {
3374+
const String &column_name = result.result_table_->GetColumnNameById(col);
3375+
Value value = data_block->GetValue(col, row);
3376+
const String &column_value = value.ToString();
3377+
json_table[column_name] = column_value;
3378+
}
3379+
json_response["profiles"].push_back(json_table);
3380+
}
3381+
}
3382+
json_response["error_code"] = 0;
3383+
http_status = HTTPStatus::CODE_200;
3384+
} else {
3385+
json_response["error_code"] = result.ErrorCode();
3386+
json_response["error_message"] = result.ErrorMsg();
3387+
http_status = HTTPStatus::CODE_500;
3388+
}
3389+
3390+
return ResponseFactory::createResponse(http_status, json_response.dump());
3391+
}
3392+
};
3393+
3394+
class ShowMemIndexHandler final : public HttpRequestHandler {
3395+
public:
3396+
SharedPtr<OutgoingResponse> handle(const SharedPtr<IncomingRequest> &request) final {
3397+
auto infinity = Infinity::RemoteConnect();
3398+
DeferFn defer_fn([&]() { infinity->RemoteDisconnect(); });
3399+
3400+
nlohmann::json json_response;
3401+
HTTPStatus http_status;
3402+
QueryResult result = infinity->Query("show memindex");
3403+
3404+
if (result.IsOk()) {
3405+
SizeT block_rows = result.result_table_->DataBlockCount();
3406+
for (SizeT block_id = 0; block_id < block_rows; ++block_id) {
3407+
DataBlock *data_block = result.result_table_->GetDataBlockById(block_id).get();
3408+
auto row_count = data_block->row_count();
3409+
auto column_cnt = result.result_table_->ColumnCount();
3410+
for (int row = 0; row < row_count; ++row) {
3411+
nlohmann::json json_table;
3412+
for (SizeT col = 0; col < column_cnt; ++col) {
3413+
const String &column_name = result.result_table_->GetColumnNameById(col);
3414+
Value value = data_block->GetValue(col, row);
3415+
const String &column_value = value.ToString();
3416+
json_table[column_name] = column_value;
3417+
}
3418+
json_response["index"].push_back(json_table);
3419+
}
3420+
}
3421+
json_response["error_code"] = 0;
3422+
http_status = HTTPStatus::CODE_200;
3423+
} else {
3424+
json_response["error_code"] = result.ErrorCode();
3425+
json_response["error_message"] = result.ErrorMsg();
3426+
http_status = HTTPStatus::CODE_500;
3427+
}
3428+
3429+
return ResponseFactory::createResponse(http_status, json_response.dump());
3430+
}
3431+
};
3432+
3433+
class ShowQueriesHandler final : public HttpRequestHandler {
3434+
public:
3435+
SharedPtr<OutgoingResponse> handle(const SharedPtr<IncomingRequest> &request) final {
3436+
auto infinity = Infinity::RemoteConnect();
3437+
DeferFn defer_fn([&]() { infinity->RemoteDisconnect(); });
3438+
3439+
nlohmann::json json_response;
3440+
HTTPStatus http_status;
3441+
QueryResult result = infinity->Query("show queries");
3442+
3443+
if (result.IsOk()) {
3444+
SizeT block_rows = result.result_table_->DataBlockCount();
3445+
for (SizeT block_id = 0; block_id < block_rows; ++block_id) {
3446+
DataBlock *data_block = result.result_table_->GetDataBlockById(block_id).get();
3447+
auto row_count = data_block->row_count();
3448+
auto column_cnt = result.result_table_->ColumnCount();
3449+
for (int row = 0; row < row_count; ++row) {
3450+
nlohmann::json json_table;
3451+
for (SizeT col = 0; col < column_cnt; ++col) {
3452+
const String &column_name = result.result_table_->GetColumnNameById(col);
3453+
Value value = data_block->GetValue(col, row);
3454+
const String &column_value = value.ToString();
3455+
json_table[column_name] = column_value;
3456+
}
3457+
json_response["queries"].push_back(json_table);
3458+
}
3459+
}
3460+
json_response["error_code"] = 0;
3461+
http_status = HTTPStatus::CODE_200;
3462+
} else {
3463+
json_response["error_code"] = result.ErrorCode();
3464+
json_response["error_message"] = result.ErrorMsg();
3465+
http_status = HTTPStatus::CODE_500;
3466+
}
3467+
3468+
return ResponseFactory::createResponse(http_status, json_response.dump());
3469+
}
3470+
};
3471+
33163472
class ShowCurrentNodeHandler final : public HttpRequestHandler {
33173473
public:
33183474
SharedPtr<OutgoingResponse> handle(const SharedPtr<IncomingRequest> &request) final {
@@ -3449,6 +3605,12 @@ void HTTPServer::Start(const String& ip_address, u16 port) {
34493605

34503606
router->route("POST", "/configs", MakeShared<SetConfigHandler>());
34513607

3608+
// metrics
3609+
router->route("GET", "/instance/buffer", MakeShared<ShowBufferHandler>());
3610+
router->route("GET", "/instance/profiles", MakeShared<ShowProfilesHandler>());
3611+
router->route("GET", "/instance/memindex", MakeShared<ShowMemIndexHandler>());
3612+
router->route("GET", "/instance/queries", MakeShared<ShowQueriesHandler>());
3613+
34523614
// variable
34533615
router->route("GET", "/variables/global", MakeShared<ShowGlobalVariablesHandler>());
34543616
router->route("GET", "/variables/global/{variable_name}", MakeShared<ShowGlobalVariableHandler>());

0 commit comments

Comments
 (0)