Skip to content

Commit 703052c

Browse files
committed
Merge remote-tracking branch 'origin/main' into bump-toolchain-2023-10-21
2 parents 1f371d7 + 210ae71 commit 703052c

File tree

85 files changed

+2521
-2173
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2521
-2173
lines changed

Cargo.lock

+1-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -244,4 +244,4 @@ etcd-client = { git = "https://github.com/risingwavelabs/etcd-client.git", rev =
244244
# Patch for coverage_attribute.
245245
# https://github.com/sgodwincs/dlv-list-rs/pull/19#issuecomment-1774786289
246246
dlv-list = { git = "https://github.com/sgodwincs/dlv-list-rs.git", rev = "5bbc5d0" }
247-
ordered-multimap = { git = "https://github.com/risingwavelabs/ordered-multimap-rs.git", dev = "c315112" }
247+
ordered-multimap = { git = "https://github.com/risingwavelabs/ordered-multimap-rs.git", rev = "19c743f" }

ci/scripts/deterministic-recovery-test.sh

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ chmod +x ./risingwave_simulation
1111

1212
export RUST_LOG="info,\
1313
risingwave_meta::barrier::recovery=debug,\
14+
risingwave_meta::manager::catalog=debug,\
1415
risingwave_meta::rpc::ddl_controller=debug,\
1516
risingwave_meta::barrier::mod=debug,\
1617
risingwave_simulation=debug"

docker/docker-compose.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
version: "3"
33
services:
44
compactor-0:
5-
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.2.0}"
5+
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.3.0}"
66
command:
77
- compactor-node
88
- "--listen-addr"
@@ -37,7 +37,7 @@ services:
3737
timeout: 5s
3838
retries: 5
3939
compute-node-0:
40-
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.2.0}"
40+
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.3.0}"
4141
command:
4242
- compute-node
4343
- "--listen-addr"
@@ -122,7 +122,7 @@ services:
122122
timeout: 5s
123123
retries: 5
124124
frontend-node-0:
125-
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.2.0}"
125+
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.3.0}"
126126
command:
127127
- frontend-node
128128
- "--listen-addr"
@@ -179,7 +179,7 @@ services:
179179
timeout: 5s
180180
retries: 5
181181
meta-node-0:
182-
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.2.0}"
182+
image: "ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.3.0}"
183183
command:
184184
- meta-node
185185
- "--listen-addr"
@@ -295,7 +295,7 @@ services:
295295
timeout: 5s
296296
retries: 5
297297
connector-node:
298-
image: ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.2.0}
298+
image: ghcr.io/risingwavelabs/risingwave:${RW_IMAGE_VERSION:-v1.3.0}
299299
entrypoint: "/risingwave/bin/connector-node/start-service.sh"
300300
ports:
301301
- 50051

integration_tests/redis-sink/create_sink.sql

+2-8
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,13 @@ FROM
33
bhv_mv WITH (
44
primary_key = 'user_id',
55
connector = 'redis',
6-
type = 'append-only',
7-
force_append_only='true',
86
redis.url= 'redis://127.0.0.1:6379/',
9-
);
7+
)FORMAT PLAIN ENCODE JSON(force_append_only='true');
108

119
CREATE SINK bhv_redis_sink_2
1210
FROM
1311
bhv_mv WITH (
1412
primary_key = 'user_id',
1513
connector = 'redis',
16-
type = 'append-only',
17-
force_append_only='true',
1814
redis.url= 'redis://127.0.0.1:6379/',
19-
redis.keyformat='user_id:{user_id}',
20-
redis.valueformat='username:{username},event_timestamp{event_timestamp}'
21-
);
15+
)FORMAT PLAIN ENCODE TEMPLATE(force_append_only='true', key_format = 'UserID:{user_id}', value_format = 'TargetID:{target_id},EventTimestamp{event_timestamp}');

proto/expr.proto

+1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ message AggCall {
348348
MODE = 24;
349349
LAST_VALUE = 25;
350350
GROUPING = 26;
351+
INTERNAL_LAST_SEEN_VALUE = 27;
351352
}
352353
Type type = 1;
353354
repeated InputRef args = 2;

proto/plan_common.proto

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ enum EncodeType {
106106
ENCODE_TYPE_PROTOBUF = 4;
107107
ENCODE_TYPE_JSON = 5;
108108
ENCODE_TYPE_BYTES = 6;
109+
ENCODE_TYPE_TEMPLATE = 7;
109110
}
110111

111112
enum RowFormatType {

src/batch/src/executor/aggregation/filter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl AggregateFunction for Filter {
7575
mod tests {
7676
use risingwave_common::test_prelude::StreamChunkTestExt;
7777
use risingwave_expr::aggregate::{build_append_only, AggCall};
78-
use risingwave_expr::expr::{build_from_pretty, Expression, LiteralExpression};
78+
use risingwave_expr::expr::{build_from_pretty, ExpressionBoxExt, LiteralExpression};
7979

8080
use super::*;
8181

src/batch/src/executor/project_set.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ mod tests {
171171
use risingwave_common::catalog::{Field, Schema};
172172
use risingwave_common::test_prelude::*;
173173
use risingwave_common::types::DataType;
174-
use risingwave_expr::expr::{Expression, InputRefExpression, LiteralExpression};
174+
use risingwave_expr::expr::{ExpressionBoxExt, InputRefExpression, LiteralExpression};
175175
use risingwave_expr::table_function::repeat;
176176

177177
use super::*;

src/connector/src/sink/catalog/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ pub enum SinkEncode {
132132
Json,
133133
Protobuf,
134134
Avro,
135+
Template,
135136
}
136137

137138
impl SinkFormatDesc {
@@ -177,6 +178,7 @@ impl SinkFormatDesc {
177178
SinkEncode::Json => E::Json,
178179
SinkEncode::Protobuf => E::Protobuf,
179180
SinkEncode::Avro => E::Avro,
181+
SinkEncode::Template => E::Template,
180182
};
181183
let options = self
182184
.options
@@ -212,6 +214,7 @@ impl TryFrom<PbSinkFormatDesc> for SinkFormatDesc {
212214
let encode = match value.encode() {
213215
E::Json => SinkEncode::Json,
214216
E::Protobuf => SinkEncode::Protobuf,
217+
E::Template => SinkEncode::Template,
215218
E::Avro => SinkEncode::Avro,
216219
e @ (E::Unspecified | E::Native | E::Csv | E::Bytes) => {
217220
return Err(SinkError::Config(anyhow!(

src/connector/src/sink/encoder/template.rs

+22
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
use std::collections::HashSet;
16+
17+
use regex::Regex;
1518
use risingwave_common::catalog::Schema;
1619
use risingwave_common::row::Row;
1720
use risingwave_common::types::ToText;
1821

1922
use super::{Result, RowEncoder};
23+
use crate::sink::SinkError;
2024

2125
/// Encode a row according to a specified string template `user_id:{user_id}`
2226
pub struct TemplateEncoder {
@@ -34,6 +38,24 @@ impl TemplateEncoder {
3438
template,
3539
}
3640
}
41+
42+
pub fn check_string_format(format: &str, set: &HashSet<String>) -> Result<()> {
43+
// We will check if the string inside {} corresponds to a column name in rw.
44+
// In other words, the content within {} should exclusively consist of column names from rw,
45+
// which means '{{column_name}}' or '{{column_name1},{column_name2}}' would be incorrect.
46+
let re = Regex::new(r"\{([^}]*)\}").unwrap();
47+
if !re.is_match(format) {
48+
return Err(SinkError::Redis(
49+
"Can't find {} in key_format or value_format".to_string(),
50+
));
51+
}
52+
for capture in re.captures_iter(format) {
53+
if let Some(inner_content) = capture.get(1) && !set.contains(inner_content.as_str()){
54+
return Err(SinkError::Redis(format!("Can't find field({:?}) in key_format or value_format",inner_content.as_str())))
55+
}
56+
}
57+
Ok(())
58+
}
3759
}
3860

3961
impl RowEncoder for TemplateEncoder {

src/connector/src/sink/formatter/mod.rs

+80-76
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub use upsert::UpsertFormatter;
2929
use super::catalog::{SinkEncode, SinkFormat, SinkFormatDesc};
3030
use super::encoder::template::TemplateEncoder;
3131
use super::encoder::KafkaConnectParams;
32+
use super::redis::{KEY_FORMAT, VALUE_FORMAT};
3233
use crate::sink::encoder::{JsonEncoder, ProtoEncoder, TimestampHandlingMode};
3334

3435
/// Transforms a `StreamChunk` into a sequence of key-value pairs according a specific format,
@@ -92,7 +93,7 @@ impl SinkFormatterImpl {
9293
let key_encoder = (!pk_indices.is_empty()).then(|| {
9394
JsonEncoder::new(
9495
schema.clone(),
95-
Some(pk_indices),
96+
Some(pk_indices.clone()),
9697
TimestampHandlingMode::Milli,
9798
)
9899
});
@@ -115,6 +116,28 @@ impl SinkFormatterImpl {
115116
Ok(SinkFormatterImpl::AppendOnlyProto(formatter))
116117
}
117118
SinkEncode::Avro => err_unsupported(),
119+
SinkEncode::Template => {
120+
let key_format = format_desc.options.get(KEY_FORMAT).ok_or_else(|| {
121+
SinkError::Config(anyhow!(
122+
"Cannot find 'key_format',please set it or use JSON"
123+
))
124+
})?;
125+
let value_format =
126+
format_desc.options.get(VALUE_FORMAT).ok_or_else(|| {
127+
SinkError::Config(anyhow!(
128+
"Cannot find 'redis_value_format',please set it or use JSON"
129+
))
130+
})?;
131+
let key_encoder = TemplateEncoder::new(
132+
schema.clone(),
133+
Some(pk_indices),
134+
key_format.clone(),
135+
);
136+
let val_encoder = TemplateEncoder::new(schema, None, value_format.clone());
137+
Ok(SinkFormatterImpl::AppendOnlyTemplate(
138+
AppendOnlyFormatter::new(Some(key_encoder), val_encoder),
139+
))
140+
}
118141
}
119142
}
120143
SinkFormat::Debezium => {
@@ -131,85 +154,66 @@ impl SinkFormatterImpl {
131154
)))
132155
}
133156
SinkFormat::Upsert => {
134-
if format_desc.encode != SinkEncode::Json {
135-
return err_unsupported();
136-
}
157+
match format_desc.encode {
158+
SinkEncode::Json => {
159+
let mut key_encoder = JsonEncoder::new(
160+
schema.clone(),
161+
Some(pk_indices),
162+
TimestampHandlingMode::Milli,
163+
);
164+
let mut val_encoder =
165+
JsonEncoder::new(schema, None, TimestampHandlingMode::Milli);
137166

138-
let mut key_encoder = JsonEncoder::new(
139-
schema.clone(),
140-
Some(pk_indices),
141-
TimestampHandlingMode::Milli,
142-
);
143-
let mut val_encoder = JsonEncoder::new(schema, None, TimestampHandlingMode::Milli);
144-
145-
if let Some(s) = format_desc.options.get("schemas.enable") {
146-
match s.to_lowercase().parse::<bool>() {
147-
Ok(true) => {
148-
let kafka_connect = KafkaConnectParams {
149-
schema_name: format!("{}.{}", db_name, sink_from_name),
150-
};
151-
key_encoder = key_encoder.with_kafka_connect(kafka_connect.clone());
152-
val_encoder = val_encoder.with_kafka_connect(kafka_connect);
153-
}
154-
Ok(false) => {}
155-
_ => {
156-
return Err(SinkError::Config(anyhow!(
157-
"schemas.enable is expected to be `true` or `false`, got {}",
158-
s
159-
)));
160-
}
167+
if let Some(s) = format_desc.options.get("schemas.enable") {
168+
match s.to_lowercase().parse::<bool>() {
169+
Ok(true) => {
170+
let kafka_connect = KafkaConnectParams {
171+
schema_name: format!("{}.{}", db_name, sink_from_name),
172+
};
173+
key_encoder =
174+
key_encoder.with_kafka_connect(kafka_connect.clone());
175+
val_encoder = val_encoder.with_kafka_connect(kafka_connect);
176+
}
177+
Ok(false) => {}
178+
_ => {
179+
return Err(SinkError::Config(anyhow!(
180+
"schemas.enable is expected to be `true` or `false`, got {}",
181+
s
182+
)));
183+
}
184+
}
185+
};
186+
187+
// Initialize the upsert_stream
188+
let formatter = UpsertFormatter::new(key_encoder, val_encoder);
189+
Ok(SinkFormatterImpl::UpsertJson(formatter))
161190
}
162-
};
163-
164-
// Initialize the upsert_stream
165-
let formatter = UpsertFormatter::new(key_encoder, val_encoder);
166-
Ok(SinkFormatterImpl::UpsertJson(formatter))
167-
}
168-
}
169-
}
170-
171-
pub fn new_with_redis(
172-
schema: Schema,
173-
pk_indices: Vec<usize>,
174-
is_append_only: bool,
175-
key_format: Option<String>,
176-
value_format: Option<String>,
177-
) -> Result<Self> {
178-
match (key_format, value_format) {
179-
(Some(k), Some(v)) => {
180-
let key_encoder = TemplateEncoder::new(
181-
schema.clone(),
182-
Some(pk_indices),
183-
k,
184-
);
185-
let val_encoder =
186-
TemplateEncoder::new(schema, None, v);
187-
if is_append_only {
188-
Ok(SinkFormatterImpl::AppendOnlyTemplate(AppendOnlyFormatter::new(Some(key_encoder), val_encoder)))
189-
} else {
190-
Ok(SinkFormatterImpl::UpsertTemplate(UpsertFormatter::new(key_encoder, val_encoder)))
191-
}
192-
}
193-
(None, None) => {
194-
let key_encoder = JsonEncoder::new(
195-
schema.clone(),
196-
Some(pk_indices),
197-
TimestampHandlingMode::Milli,
198-
);
199-
let val_encoder = JsonEncoder::new(
200-
schema,
201-
None,
202-
TimestampHandlingMode::Milli,
203-
);
204-
if is_append_only {
205-
Ok(SinkFormatterImpl::AppendOnlyJson(AppendOnlyFormatter::new(Some(key_encoder), val_encoder)))
206-
} else {
207-
Ok(SinkFormatterImpl::UpsertJson(UpsertFormatter::new(key_encoder, val_encoder)))
191+
SinkEncode::Template => {
192+
let key_format = format_desc.options.get(KEY_FORMAT).ok_or_else(|| {
193+
SinkError::Config(anyhow!(
194+
"Cannot find 'key_format',please set it or use JSON"
195+
))
196+
})?;
197+
let value_format =
198+
format_desc.options.get(VALUE_FORMAT).ok_or_else(|| {
199+
SinkError::Config(anyhow!(
200+
"Cannot find 'redis_value_format',please set it or use JSON"
201+
))
202+
})?;
203+
let key_encoder = TemplateEncoder::new(
204+
schema.clone(),
205+
Some(pk_indices),
206+
key_format.clone(),
207+
);
208+
let val_encoder = TemplateEncoder::new(schema, None, value_format.clone());
209+
Ok(SinkFormatterImpl::UpsertTemplate(UpsertFormatter::new(
210+
key_encoder,
211+
val_encoder,
212+
)))
213+
}
214+
_ => err_unsupported(),
208215
}
209216
}
210-
_ => {
211-
Err(SinkError::Encode("Please provide template formats for both key and value, or choose the JSON format.".to_string()))
212-
}
213217
}
214218
}
215219
}

0 commit comments

Comments
 (0)