Skip to content

Commit 603b095

Browse files
author
Devdutt Shenoi
authored
fix+refactor: JSON flattening, custom partition check (#1055)
- Refactor parts of JSON flattening code to improve readability and performance (lesser cloning). - Fixes custom partition check by not allowing objects, arrays as well. - Adds tests and documentation also
1 parent d332358 commit 603b095

File tree

9 files changed

+426
-387
lines changed

9 files changed

+426
-387
lines changed

src/alerts/mod.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,10 @@ impl Alert {
108108
);
109109
let deployment_id = storage::StorageMetadata::global().deployment_id;
110110
let deployment_mode = storage::StorageMetadata::global().mode.to_string();
111-
let additional_labels =
111+
let mut additional_labels =
112112
serde_json::to_value(rule).expect("rule is perfectly deserializable");
113-
let flatten_additional_labels =
114-
utils::json::flatten::flatten_with_parent_prefix(additional_labels, "rule", "_")
115-
.expect("can be flattened");
113+
utils::json::flatten::flatten_with_parent_prefix(&mut additional_labels, "rule", "_")
114+
.expect("can be flattened");
116115
Context::new(
117116
stream_name,
118117
AlertInfo::new(
@@ -122,7 +121,7 @@ impl Alert {
122121
alert_state,
123122
),
124123
DeploymentInfo::new(deployment_instance, deployment_id, deployment_mode),
125-
flatten_additional_labels,
124+
additional_labels,
126125
)
127126
}
128127
}

src/handlers/http/ingest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ pub async fn create_stream_if_not_exists(
196196
super::logstream::create_stream(
197197
stream_name.to_string(),
198198
"",
199-
"",
199+
None,
200200
"",
201201
"",
202202
Arc::new(Schema::empty()),

src/handlers/http/logstream.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use http::{HeaderName, HeaderValue};
4949
use serde_json::Value;
5050
use std::collections::HashMap;
5151
use std::fs;
52+
use std::num::NonZeroU32;
5253
use std::str::FromStr;
5354
use std::sync::Arc;
5455
use tracing::{error, warn};
@@ -471,7 +472,7 @@ fn remove_id_from_alerts(value: &mut Value) {
471472
pub async fn create_stream(
472473
stream_name: String,
473474
time_partition: &str,
474-
time_partition_limit: &str,
475+
time_partition_limit: Option<NonZeroU32>,
475476
custom_partition: &str,
476477
static_schema_flag: &str,
477478
schema: Arc<Schema>,
@@ -511,7 +512,7 @@ pub async fn create_stream(
511512
stream_name.to_string(),
512513
created_at,
513514
time_partition.to_string(),
514-
time_partition_limit.to_string(),
515+
time_partition_limit,
515516
custom_partition.to_string(),
516517
static_schema_flag.to_string(),
517518
static_schema,
@@ -561,7 +562,9 @@ pub async fn get_stream_info(req: HttpRequest) -> Result<impl Responder, StreamE
561562
created_at: stream_meta.created_at.clone(),
562563
first_event_at: stream_meta.first_event_at.clone(),
563564
time_partition: stream_meta.time_partition.clone(),
564-
time_partition_limit: stream_meta.time_partition_limit.clone(),
565+
time_partition_limit: stream_meta
566+
.time_partition_limit
567+
.map(|limit| limit.to_string()),
565568
custom_partition: stream_meta.custom_partition.clone(),
566569
cache_enabled: stream_meta.cache_enabled,
567570
static_schema_flag: stream_meta.static_schema_flag.clone(),

src/handlers/http/modal/utils/ingest_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ pub async fn push_logs(
113113
let data = convert_array_to_object(
114114
&body_val,
115115
time_partition.as_ref(),
116-
time_partition_limit.as_ref(),
116+
time_partition_limit,
117117
None,
118118
)?;
119119
for value in data {
@@ -135,7 +135,7 @@ pub async fn push_logs(
135135
let data = convert_array_to_object(
136136
&body_val,
137137
time_partition.as_ref(),
138-
time_partition_limit.as_ref(),
138+
time_partition_limit,
139139
custom_partition.as_ref(),
140140
)?;
141141
let custom_partition = custom_partition.unwrap();

src/handlers/http/modal/utils/logstream_utils.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ pub async fn create_update_stream(
8484
}
8585

8686
let time_partition_in_days = if !time_partition_limit.is_empty() {
87-
validate_time_partition_limit(&time_partition_limit)?
87+
Some(validate_time_partition_limit(&time_partition_limit)?)
8888
} else {
89-
""
89+
None
9090
};
9191

9292
if !custom_partition.is_empty() {
@@ -207,20 +207,20 @@ pub fn fetch_headers_from_put_stream_request(
207207

208208
pub fn validate_time_partition_limit(
209209
time_partition_limit: &str,
210-
) -> Result<&str, CreateStreamError> {
210+
) -> Result<NonZeroU32, CreateStreamError> {
211211
if !time_partition_limit.ends_with('d') {
212212
return Err(CreateStreamError::Custom {
213213
msg: "Missing 'd' suffix for duration value".to_string(),
214214
status: StatusCode::BAD_REQUEST,
215215
});
216216
}
217217
let days = &time_partition_limit[0..time_partition_limit.len() - 1];
218-
if days.parse::<NonZeroU32>().is_err() {
218+
let Ok(days) = days.parse::<NonZeroU32>() else {
219219
return Err(CreateStreamError::Custom {
220220
msg: "Could not convert duration to an unsigned number".to_string(),
221221
status: StatusCode::BAD_REQUEST,
222222
});
223-
}
223+
};
224224

225225
Ok(days)
226226
}
@@ -288,7 +288,7 @@ pub fn validate_static_schema(
288288

289289
pub async fn update_time_partition_limit_in_stream(
290290
stream_name: String,
291-
time_partition_limit: &str,
291+
time_partition_limit: NonZeroU32,
292292
) -> Result<(), CreateStreamError> {
293293
let storage = CONFIG.storage().get_object_store();
294294
if let Err(err) = storage
@@ -299,7 +299,7 @@ pub async fn update_time_partition_limit_in_stream(
299299
}
300300

301301
if metadata::STREAM_INFO
302-
.update_time_partition_limit(&stream_name, time_partition_limit.to_string())
302+
.update_time_partition_limit(&stream_name, time_partition_limit)
303303
.is_err()
304304
{
305305
return Err(CreateStreamError::Custom {
@@ -381,7 +381,7 @@ pub async fn update_custom_partition_in_stream(
381381
pub async fn create_stream(
382382
stream_name: String,
383383
time_partition: &str,
384-
time_partition_limit: &str,
384+
time_partition_limit: Option<NonZeroU32>,
385385
custom_partition: &str,
386386
static_schema_flag: &str,
387387
schema: Arc<Schema>,
@@ -421,7 +421,7 @@ pub async fn create_stream(
421421
stream_name.to_string(),
422422
created_at,
423423
time_partition.to_string(),
424-
time_partition_limit.to_string(),
424+
time_partition_limit,
425425
custom_partition.to_string(),
426426
static_schema_flag.to_string(),
427427
static_schema,
@@ -470,8 +470,7 @@ pub async fn create_stream_and_schema_from_storage(stream_name: &str) -> Result<
470470
let time_partition = stream_metadata.time_partition.as_deref().unwrap_or("");
471471
let time_partition_limit = stream_metadata
472472
.time_partition_limit
473-
.as_deref()
474-
.unwrap_or("");
473+
.and_then(|limit| limit.parse().ok());
475474
let custom_partition = stream_metadata.custom_partition.as_deref().unwrap_or("");
476475
let static_schema_flag = stream_metadata.static_schema_flag.as_deref().unwrap_or("");
477476
let stream_type = stream_metadata.stream_type.as_deref().unwrap_or("");
@@ -480,7 +479,7 @@ pub async fn create_stream_and_schema_from_storage(stream_name: &str) -> Result<
480479
stream_name.to_string(),
481480
stream_metadata.created_at,
482481
time_partition.to_string(),
483-
time_partition_limit.to_string(),
482+
time_partition_limit,
484483
custom_partition.to_string(),
485484
static_schema_flag.to_string(),
486485
static_schema,

src/metadata.rs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use itertools::Itertools;
2323
use once_cell::sync::Lazy;
2424
use serde_json::Value;
2525
use std::collections::HashMap;
26+
use std::num::NonZeroU32;
2627
use std::sync::{Arc, RwLock};
2728

2829
use self::error::stream_info::{CheckAlertError, LoadError, MetadataError};
@@ -53,7 +54,7 @@ pub struct LogStreamMetadata {
5354
pub created_at: String,
5455
pub first_event_at: Option<String>,
5556
pub time_partition: Option<String>,
56-
pub time_partition_limit: Option<String>,
57+
pub time_partition_limit: Option<NonZeroU32>,
5758
pub custom_partition: Option<String>,
5859
pub static_schema_flag: Option<String>,
5960
pub hot_tier_enabled: Option<bool>,
@@ -113,11 +114,11 @@ impl StreamInfo {
113114
pub fn get_time_partition_limit(
114115
&self,
115116
stream_name: &str,
116-
) -> Result<Option<String>, MetadataError> {
117+
) -> Result<Option<NonZeroU32>, MetadataError> {
117118
let map = self.read().expect(LOCK_EXPECT);
118119
map.get(stream_name)
119120
.ok_or(MetadataError::StreamMetaNotFound(stream_name.to_string()))
120-
.map(|metadata| metadata.time_partition_limit.clone())
121+
.map(|metadata| metadata.time_partition_limit)
121122
}
122123

123124
pub fn get_custom_partition(&self, stream_name: &str) -> Result<Option<String>, MetadataError> {
@@ -202,7 +203,7 @@ impl StreamInfo {
202203
pub fn update_time_partition_limit(
203204
&self,
204205
stream_name: &str,
205-
time_partition_limit: String,
206+
time_partition_limit: NonZeroU32,
206207
) -> Result<(), MetadataError> {
207208
let mut map = self.write().expect(LOCK_EXPECT);
208209
map.get_mut(stream_name)
@@ -244,7 +245,7 @@ impl StreamInfo {
244245
stream_name: String,
245246
created_at: String,
246247
time_partition: String,
247-
time_partition_limit: String,
248+
time_partition_limit: Option<NonZeroU32>,
248249
custom_partition: String,
249250
static_schema_flag: String,
250251
static_schema: HashMap<String, Arc<Field>>,
@@ -262,11 +263,7 @@ impl StreamInfo {
262263
} else {
263264
Some(time_partition)
264265
},
265-
time_partition_limit: if time_partition_limit.is_empty() {
266-
None
267-
} else {
268-
Some(time_partition_limit)
269-
},
266+
time_partition_limit,
270267
custom_partition: if custom_partition.is_empty() {
271268
None
272269
} else {
@@ -320,7 +317,9 @@ impl StreamInfo {
320317
created_at: meta.created_at,
321318
first_event_at: meta.first_event_at,
322319
time_partition: meta.time_partition,
323-
time_partition_limit: meta.time_partition_limit,
320+
time_partition_limit: meta
321+
.time_partition_limit
322+
.and_then(|limit| limit.parse().ok()),
324323
custom_partition: meta.custom_partition,
325324
static_schema_flag: meta.static_schema_flag,
326325
hot_tier_enabled: meta.hot_tier_enabled,
@@ -473,7 +472,9 @@ pub async fn load_stream_metadata_on_server_start(
473472
created_at: meta.created_at,
474473
first_event_at: meta.first_event_at,
475474
time_partition: meta.time_partition,
476-
time_partition_limit: meta.time_partition_limit,
475+
time_partition_limit: meta
476+
.time_partition_limit
477+
.and_then(|limit| limit.parse().ok()),
477478
custom_partition: meta.custom_partition,
478479
static_schema_flag: meta.static_schema_flag,
479480
hot_tier_enabled: meta.hot_tier_enabled,

src/storage/object_storage.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ use relative_path::RelativePathBuf;
5050
use tracing::error;
5151

5252
use std::collections::BTreeMap;
53+
use std::num::NonZeroU32;
5354
use std::{
5455
collections::HashMap,
5556
fs,
@@ -145,7 +146,7 @@ pub trait ObjectStorage: Send + Sync + 'static {
145146
&self,
146147
stream_name: &str,
147148
time_partition: &str,
148-
time_partition_limit: &str,
149+
time_partition_limit: Option<NonZeroU32>,
149150
custom_partition: &str,
150151
static_schema_flag: &str,
151152
schema: Arc<Schema>,
@@ -162,11 +163,7 @@ pub trait ObjectStorage: Send + Sync + 'static {
162163
} else {
163164
format.time_partition = Some(time_partition.to_string());
164165
}
165-
if time_partition_limit.is_empty() {
166-
format.time_partition_limit = None;
167-
} else {
168-
format.time_partition_limit = Some(time_partition_limit.to_string());
169-
}
166+
format.time_partition_limit = time_partition_limit.map(|limit| limit.to_string());
170167
if custom_partition.is_empty() {
171168
format.custom_partition = None;
172169
} else {
@@ -190,14 +187,10 @@ pub trait ObjectStorage: Send + Sync + 'static {
190187
async fn update_time_partition_limit_in_stream(
191188
&self,
192189
stream_name: &str,
193-
time_partition_limit: &str,
190+
time_partition_limit: NonZeroU32,
194191
) -> Result<(), ObjectStorageError> {
195192
let mut format = self.get_object_store_format(stream_name).await?;
196-
if time_partition_limit.is_empty() {
197-
format.time_partition_limit = None;
198-
} else {
199-
format.time_partition_limit = Some(time_partition_limit.to_string());
200-
}
193+
format.time_partition_limit = Some(time_partition_limit.to_string());
201194
let format_json = to_bytes(&format);
202195
self.put_object(&stream_json_path(stream_name), format_json)
203196
.await?;

0 commit comments

Comments
 (0)