Skip to main content

frontend/instance/
log_handler.rs

1// Copyright 2023 Greptime Team
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//     http://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
15use std::sync::Arc;
16
17use api::v1::RowInsertRequests;
18use async_trait::async_trait;
19use auth::{
20    LOG_WRITE, PIPELINE_DELETE, PIPELINE_INSERT, PIPELINE_QUERY, PermissionChecker,
21    PermissionCheckerRef, PermissionReq,
22};
23use client::Output;
24use common_error::ext::BoxedError;
25use datatypes::timestamp::TimestampNanosecond;
26use pipeline::{Pipeline, PipelineInfo, PipelineVersion};
27use servers::error::{
28    AuthSnafu, Error as ServerError, ExecuteGrpcRequestSnafu, PipelineSnafu, Result as ServerResult,
29};
30use servers::interceptor::{LogIngestInterceptor, LogIngestInterceptorRef};
31use servers::query_handler::PipelineHandler;
32use session::context::{QueryContext, QueryContextRef};
33use snafu::ResultExt;
34use table::Table;
35
36use crate::instance::Instance;
37
38impl Instance {
39    async fn prepare_log_insert(
40        &self,
41        log: RowInsertRequests,
42        ctx: QueryContextRef,
43    ) -> ServerResult<RowInsertRequests> {
44        self.plugins
45            .get::<PermissionCheckerRef>()
46            .as_ref()
47            .check_permission(ctx.current_user(), PermissionReq::Action(LOG_WRITE))
48            .context(AuthSnafu)?;
49
50        let log = self
51            .plugins
52            .get::<LogIngestInterceptorRef<ServerError>>()
53            .as_ref()
54            .pre_ingest(log, ctx.clone())?;
55
56        self.check_row_insert_permission(&log, &ctx, PermissionReq::Action(LOG_WRITE))
57            .context(AuthSnafu)?;
58
59        Ok(log)
60    }
61}
62
63#[async_trait]
64impl PipelineHandler for Instance {
65    async fn insert(&self, log: RowInsertRequests, ctx: QueryContextRef) -> ServerResult<Output> {
66        let log = self.prepare_log_insert(log, ctx.clone()).await?;
67        self.handle_log_inserts(log, Arc::new(ctx.fork())).await
68    }
69
70    async fn insert_all(
71        &self,
72        inputs: Vec<(QueryContextRef, RowInsertRequests)>,
73    ) -> ServerResult<Vec<ServerResult<Output>>> {
74        let mut prepared = Vec::with_capacity(inputs.len());
75        for (ctx, log) in inputs {
76            let log = self.prepare_log_insert(log, ctx.clone()).await?;
77            // Detach from context clones retained by pre-ingest hooks so the
78            // checked schema cannot change before this batch is written.
79            prepared.push((Arc::new(ctx.fork()), log));
80        }
81
82        operator::insert::admit_row_insert_batches(&mut prepared)
83            .await
84            .map_err(BoxedError::new)
85            .context(servers::error::ExecuteGrpcQuerySnafu)?;
86
87        let mut outputs = Vec::with_capacity(prepared.len());
88        for (ctx, log) in prepared {
89            outputs.push(self.handle_log_inserts(log, ctx).await);
90        }
91        Ok(outputs)
92    }
93
94    fn check_pipeline_query_permission(&self, query_ctx: &QueryContextRef) -> ServerResult<()> {
95        self.check_permission(query_ctx, PermissionReq::Action(PIPELINE_QUERY))
96    }
97
98    async fn get_pipeline(
99        &self,
100        name: &str,
101        version: PipelineVersion,
102        query_ctx: QueryContextRef,
103    ) -> ServerResult<Arc<Pipeline>> {
104        self.pipeline_operator
105            .get_pipeline(query_ctx, name, version)
106            .await
107            .context(PipelineSnafu)
108    }
109
110    async fn insert_pipeline(
111        &self,
112        name: &str,
113        content_type: &str,
114        pipeline: &str,
115        query_ctx: QueryContextRef,
116    ) -> ServerResult<PipelineInfo> {
117        self.check_permission(&query_ctx, PermissionReq::Action(PIPELINE_INSERT))?;
118        self.pipeline_operator
119            .insert_pipeline(name, content_type, pipeline, query_ctx)
120            .await
121            .context(PipelineSnafu)
122    }
123
124    async fn delete_pipeline(
125        &self,
126        name: &str,
127        version: PipelineVersion,
128        ctx: QueryContextRef,
129    ) -> ServerResult<Option<()>> {
130        self.check_permission(&ctx, PermissionReq::Action(PIPELINE_DELETE))?;
131        self.pipeline_operator
132            .delete_pipeline(name, version, ctx)
133            .await
134            .context(PipelineSnafu)
135    }
136
137    async fn get_table(
138        &self,
139        table: &str,
140        query_ctx: &QueryContext,
141    ) -> std::result::Result<Option<Arc<Table>>, catalog::error::Error> {
142        let catalog = query_ctx.current_catalog();
143        let schema = query_ctx.current_schema();
144        self.catalog_manager
145            .table(catalog, &schema, table, None)
146            .await
147    }
148
149    fn build_pipeline(&self, pipeline: &str) -> ServerResult<Pipeline> {
150        self.pipeline_operator
151            .build_pipeline(pipeline)
152            .context(PipelineSnafu)
153    }
154
155    async fn get_pipeline_str(
156        &self,
157        name: &str,
158        version: PipelineVersion,
159        query_ctx: QueryContextRef,
160    ) -> ServerResult<(String, TimestampNanosecond)> {
161        self.check_permission(&query_ctx, PermissionReq::Action(PIPELINE_QUERY))?;
162        self.pipeline_operator
163            .get_pipeline_str(name, version, query_ctx)
164            .await
165            .context(PipelineSnafu)
166    }
167}
168
169impl Instance {
170    pub async fn handle_log_inserts(
171        &self,
172        log: RowInsertRequests,
173        ctx: QueryContextRef,
174    ) -> ServerResult<Output> {
175        self.inserter
176            .handle_log_inserts(log, ctx, self.statement_executor.as_ref())
177            .await
178            .map_err(BoxedError::new)
179            .context(ExecuteGrpcRequestSnafu)
180    }
181
182    pub async fn handle_trace_inserts(
183        &self,
184        rows: RowInsertRequests,
185        ctx: QueryContextRef,
186    ) -> ServerResult<Output> {
187        self.inserter
188            .handle_trace_inserts(rows, ctx, self.statement_executor.as_ref())
189            .await
190            .map_err(BoxedError::new)
191            .context(ExecuteGrpcRequestSnafu)
192    }
193}