Skip to content

Commit 312f451

Browse files
committed
s3: avro codec field
1 parent 146e61d commit 312f451

7 files changed

Lines changed: 82 additions & 9 deletions

File tree

flow/connectors/s3/qrep.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,21 @@ func (c *S3Connector) writeToAvroFile(
6868

6969
s3AvroFileKey := fmt.Sprintf("%s/%s/%s.avro", s3o.Prefix, jobName, partitionID)
7070

71-
writer := avro.NewPeerDBOCFWriter(stream, avroSchema, ocf.Null, protos.DBType_S3)
71+
var codec ocf.CodecName
72+
switch c.codec {
73+
case protos.AvroCodec_Null:
74+
codec = ocf.Null
75+
case protos.AvroCodec_Deflate:
76+
codec = ocf.Deflate
77+
case protos.AvroCodec_Snappy:
78+
codec = ocf.Snappy
79+
case protos.AvroCodec_ZStandard:
80+
codec = ocf.ZStandard
81+
default:
82+
return 0, fmt.Errorf("unsupported codec %s", c.codec)
83+
}
84+
85+
writer := avro.NewPeerDBOCFWriter(stream, avroSchema, codec, protos.DBType_S3)
7286
avroFile, err := writer.WriteRecordsToS3(ctx, env, s3o.Bucket, s3AvroFileKey, c.credentialsProvider, nil, nil)
7387
if err != nil {
7488
return 0, fmt.Errorf("failed to write records to S3: %w", err)

flow/connectors/s3/s3.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type S3Connector struct {
2121
credentialsProvider utils.AWSCredentialsProvider
2222
client s3.Client
2323
url string
24+
codec protos.AvroCodec
2425
}
2526

2627
func NewS3Connector(
@@ -44,11 +45,12 @@ func NewS3Connector(
4445
return nil, err
4546
}
4647
return &S3Connector{
47-
url: config.Url,
4848
PostgresMetadata: pgMetadata,
4949
client: *s3Client,
5050
credentialsProvider: provider,
5151
logger: logger,
52+
url: config.Url,
53+
codec: config.Codec,
5254
}, nil
5355
}
5456

nexus/analyzer/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,11 @@ fn parse_db_options(db_type: DbType, with_options: &[SqlOption]) -> anyhow::Resu
731731
.get("tls_host")
732732
.map(|s| s.to_string())
733733
.unwrap_or_default(),
734+
codec: opts
735+
.get("codec")
736+
.and_then(|s| pt::peerdb_peers::AvroCodec::from_str_name(s))
737+
.map(|codec| codec.into())
738+
.unwrap_or_default(),
734739
};
735740
Config::S3Config(s3_config)
736741
}

protos/peers.proto

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ message EventHubGroupConfig {
134134
repeated string unnest_columns = 3;
135135
}
136136

137+
enum AvroCodec {
138+
Null = 0;
139+
Deflate = 1;
140+
Snappy = 2;
141+
ZStandard = 3;
142+
}
143+
137144
message S3Config {
138145
string url = 1;
139146
optional string access_key_id = 2 [(peerdb_redacted) = true];
@@ -143,6 +150,7 @@ message S3Config {
143150
optional string endpoint = 6;
144151
optional string root_ca = 7 [(peerdb_redacted) = true];
145152
string tls_host = 8;
153+
AvroCodec codec = 9;
146154
}
147155

148156
message ClickhouseConfig{

ui/app/peers/create/[peerType]/helpers/s3.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { S3Config } from '@/grpc_generated/peers';
1+
import { AvroCodec, S3Config, avroCodecFromJSON } from '@/grpc_generated/peers';
22
import { PeerSetting } from './common';
33

44
export const s3Setting: PeerSetting[] = [
@@ -74,6 +74,20 @@ export const s3Setting: PeerSetting[] = [
7474
tips: 'Overrides expected hostname during tls cert verification.',
7575
optional: true,
7676
},
77+
{
78+
label: 'Avro Codec',
79+
field: 'codec',
80+
stateHandler: (value, setter) =>
81+
setter((curr) => ({ ...curr, codec: avroCodecFromJSON(value) })),
82+
type: 'select',
83+
placeholder: 'Select avro codec',
84+
options: [
85+
{ value: 'Null', label: 'Null' },
86+
{ value: 'Deflate', label: 'Deflate' },
87+
{ value: 'Snappy', label: 'Snappy' },
88+
{ value: 'ZStandard', label: 'ZStandard' },
89+
],
90+
},
7791
];
7892

7993
export const blankS3Setting: S3Config = {
@@ -85,4 +99,5 @@ export const blankS3Setting: S3Config = {
8599
endpoint: '',
86100
rootCa: undefined,
87101
tlsHost: '',
102+
codec: AvroCodec.Null,
88103
};

ui/app/peers/create/[peerType]/schema.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ehSchema } from '@/components/PeerForms/Eventhubs/schema';
22
import {
3+
AvroCodec,
34
ElasticsearchAuthType,
45
MySqlFlavor,
56
MySqlReplicationMechanism,
@@ -526,6 +527,12 @@ export const s3Schema = z.object({
526527
error: () => 'Endpoint must be a string',
527528
})
528529
.optional(),
530+
codec: z.enum(AvroCodec, {
531+
error: (issue) =>
532+
issue.input === undefined
533+
? 'Avro codec is required'
534+
: 'Avro codec must be one of [Null,Deflate,Snappy,ZStandard]',
535+
}),
529536
});
530537

531538
export const psSchema = z.object({

ui/components/PeerForms/S3Form.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
'use client';
22
import { PeerSetter } from '@/app/dto/PeersDTO';
33
import { s3Setting } from '@/app/peers/create/[peerType]/helpers/s3';
4+
import SelectTheme from '@/app/styles/select';
45
import { GCS_ENDPOINT } from '@/app/utils/gcsEndpoint';
56
import InfoPopover from '@/components/InfoPopover';
67
import { Label } from '@/lib/Label';
7-
import { RowWithRadiobutton, RowWithTextField } from '@/lib/Layout';
8+
import {
9+
RowWithRadiobutton,
10+
RowWithSelect,
11+
RowWithTextField,
12+
} from '@/lib/Layout';
813
import { RadioButton, RadioButtonGroup } from '@/lib/RadioButtonGroup';
914
import { TextField } from '@/lib/TextField';
1015
import { Tooltip } from '@/lib/Tooltip';
1116
import { useEffect, useState } from 'react';
17+
import ReactSelect from 'react-select';
1218
import { handleFieldChange } from './common';
1319

1420
interface S3Props {
@@ -65,9 +71,25 @@ export default function S3Form({ setter }: S3Props) {
6571
action={<RadioButton value='GCS' />}
6672
/>
6773
</RadioButtonGroup>
68-
{s3Setting.map((setting, index) => {
69-
if (displayCondition(setting.label))
70-
return (
74+
{s3Setting.map(
75+
(setting, index) =>
76+
displayCondition(setting.label) &&
77+
(setting.type === 'select' ? (
78+
<RowWithSelect
79+
key={index}
80+
label={<Label>{setting.label}</Label>}
81+
action={
82+
<ReactSelect
83+
placeholder={setting.placeholder}
84+
onChange={(val) =>
85+
val && setting.stateHandler(val.value, setter)
86+
}
87+
options={setting.options}
88+
theme={SelectTheme}
89+
/>
90+
}
91+
/>
92+
) : (
7193
<RowWithTextField
7294
key={index}
7395
label={
@@ -115,8 +137,8 @@ export default function S3Form({ setter }: S3Props) {
115137
</div>
116138
}
117139
/>
118-
);
119-
})}
140+
))
141+
)}
120142
</div>
121143
);
122144
}

0 commit comments

Comments
 (0)