Skip to content

Commit 0b24a22

Browse files
authored
Merge branch 'main' into helm-2.8.0
Signed-off-by: Nitish Tiwari <nitish@parseable.com>
2 parents e47f802 + dfcaa6d commit 0b24a22

30 files changed

Lines changed: 2879 additions & 457 deletions

Cargo.lock

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "parseable"
3-
version = "2.7.2"
3+
version = "2.8.0"
44
authors = ["Parseable Team <hi@parseable.com>"]
55
edition = "2024"
66
rust-version = "1.88.0"
@@ -127,6 +127,7 @@ opentelemetry-otlp = { version = "0.31.1", features = [
127127
"http-proto",
128128
"http-json",
129129
] }
130+
opentelemetry-stdout = "0.31.0"
130131
tracing-actix-web = "0.7"
131132

132133
# Time and Date
@@ -180,6 +181,7 @@ thiserror = "2.0"
180181
ulid = { version = "1.0", features = ["serde"] }
181182
uuid = { version = "1", features = ["v4"] }
182183
xxhash-rust = { version = "0.8", features = ["xxh3"] }
184+
rustc-hash = "2"
183185
futures-core = "0.3.31"
184186
tempfile = "3.20.0"
185187
lazy_static = "1.4.0"
@@ -204,8 +206,8 @@ arrow = "58.0.0"
204206
temp-dir = "0.1.14"
205207

206208
[package.metadata.parseable_ui]
207-
assets-url = "https://parseable-prism-build.s3.us-east-2.amazonaws.com/v2.7.2/build.zip"
208-
assets-sha1 = "541746bd89b41528477a57a2f6f066dce145dd73"
209+
assets-url = "https://parseable-prism-build.s3.us-east-2.amazonaws.com/v2.8.0/build.zip"
210+
assets-sha1 = "a7523ef819d38678275ae165c443564b2f9a3fc1"
209211

210212
[features]
211213
debug = []
56 KB
Binary file not shown.

src/cli.rs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*/
1818

1919
use clap::{Parser, value_parser};
20-
use std::{env, fs, path::PathBuf};
20+
use std::{env, fs, ops::Div, path::PathBuf};
2121

2222
use url::Url;
2323

@@ -194,6 +194,16 @@ pub struct Options {
194194
)]
195195
pub max_connections: usize,
196196

197+
// DataFusion target partitions
198+
#[arg(
199+
long,
200+
env = "P_DATAFUSION_TARGET_PARTITIONS",
201+
default_value_t = num_cpus::get().div(2).max(1) as u64,
202+
value_parser = value_parser!(u64).range(1..),
203+
help = "Number of partitions for DF to split execution into"
204+
)]
205+
pub target_partitions: u64,
206+
197207
#[arg(
198208
long = "origin",
199209
env = "P_ORIGIN_URI",
@@ -314,6 +324,60 @@ pub struct Options {
314324
)]
315325
pub hot_tier_storage_path: Option<PathBuf>,
316326

327+
#[arg(
328+
long = "hot-tier-download-chunk-size",
329+
env = "P_HOT_TIER_DOWNLOAD_CHUNK_SIZE",
330+
value_parser = clap::value_parser!(u64).range(5242880..),
331+
default_value = "8388608",
332+
help = "Chunk size in bytes for parallel hot tier downloads (default 8 MiB)"
333+
)]
334+
pub hot_tier_download_chunk_size: u64,
335+
336+
#[arg(
337+
long = "hot-tier-download-concurrency",
338+
env = "P_HOT_TIER_DOWNLOAD_CONCURRENCY",
339+
value_parser = clap::value_parser!(u64).range(1..),
340+
default_value = "16",
341+
help = "Number of concurrent range requests per hot tier download"
342+
)]
343+
pub hot_tier_download_concurrency: u64,
344+
345+
#[arg(
346+
long = "hot-tier-files-per-stream-concurrency",
347+
env = "P_HOT_TIER_FILES_PER_STREAM_CONCURRENCY",
348+
value_parser = clap::value_parser!(u32).range(1..),
349+
default_value = "4",
350+
help = "Number of concurrent parquet file downloads per stream during hot tier sync"
351+
)]
352+
pub hot_tier_files_per_stream_concurrency: u32,
353+
354+
#[arg(
355+
long = "hot-tier-latest-minutes",
356+
env = "P_HOT_TIER_LATEST_MINUTES",
357+
value_parser = clap::value_parser!(u64).range(1..),
358+
default_value = "10",
359+
help = "Files whose timestamp is within the last N minutes are 'latest'; rest are 'historic'."
360+
)]
361+
pub hot_tier_latest_minutes: u64,
362+
363+
#[arg(
364+
long = "hot-tier-per-tick-cap",
365+
env = "P_HISTORIC_PER_TICK_CAP",
366+
value_parser = clap::value_parser!(u32).range(10..),
367+
default_value = "100",
368+
help = "Maximum files to download per historic tick."
369+
)]
370+
pub historic_per_tick_cap: u32,
371+
372+
#[arg(
373+
long = "hot-tier-historic-sync-minutes",
374+
env = "P_HOT_TIER_HISTORIC_SYNC_MINUTES",
375+
value_parser = clap::value_parser!(u32).range(1..),
376+
default_value = "5",
377+
help = "Interval (minutes) at which the historic hot-tier sync runs."
378+
)]
379+
pub hot_tier_historic_sync_minutes: u32,
380+
317381
//TODO: remove this when smart cache is implemented
318382
#[arg(
319383
long = "index-storage-path",

src/handlers/airplane.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ impl FlightService for AirServiceImpl {
235235

236236
if event.is_some() {
237237
// Clear staging of stream once airplane has taxied
238-
PARSEABLE.get_or_create_stream(&stream_name, &None).clear();
238+
let _ = PARSEABLE.get_or_create_stream(&stream_name, &None).clear();
239239
}
240240

241241
let time = time.elapsed().as_secs_f64();

src/handlers/http/logstream.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use self::error::StreamError;
2020
use super::cluster::utils::{IngestionStats, QueriedStats, StorageStats};
2121
use super::query::update_schema_when_distributed;
2222
use crate::event::format::override_data_type;
23-
use crate::hottier::{CURRENT_HOT_TIER_VERSION, HotTierManager, StreamHotTier};
23+
use crate::hottier::{CURRENT_HOT_TIER_VERSION, GLOBAL_HOTTIER, StreamHotTier};
2424
use crate::metadata::SchemaVersion;
2525
use crate::metrics::{EVENTS_INGESTED_DATE, EVENTS_INGESTED_SIZE_DATE, EVENTS_STORAGE_SIZE_DATE};
2626
use crate::parseable::{DEFAULT_TENANT, PARSEABLE, StreamNotFound};
@@ -47,7 +47,7 @@ use itertools::Itertools;
4747
use serde_json::{Value, json};
4848
use std::fs;
4949
use std::sync::Arc;
50-
use tracing::warn;
50+
use tracing::{Instrument, warn};
5151

5252
pub async fn delete(
5353
req: HttpRequest,
@@ -77,7 +77,7 @@ pub async fn delete(
7777
)
7878
}
7979

80-
if let Some(hot_tier_manager) = HotTierManager::global()
80+
if let Some(hot_tier_manager) = GLOBAL_HOTTIER.get()
8181
&& hot_tier_manager.check_stream_hot_tier_exists(&stream_name, &tenant_id)
8282
{
8383
hot_tier_manager
@@ -413,16 +413,25 @@ pub async fn get_stream_info(
413413
Ok((web::Json(stream_info), StatusCode::OK))
414414
}
415415

416+
#[tracing::instrument(
417+
name = "http.put_stream_hot_tier",
418+
skip(req, logstream, hottier),
419+
fields(stream = tracing::field::Empty, tenant = tracing::field::Empty, size = hottier.size)
420+
)]
416421
pub async fn put_stream_hot_tier(
417422
req: HttpRequest,
418423
logstream: Path<String>,
419424
Json(mut hottier): Json<StreamHotTier>,
420425
) -> Result<impl Responder, StreamError> {
421426
let stream_name = logstream.into_inner();
422427
let tenant_id = get_tenant_id_from_request(&req);
428+
let current_span = tracing::Span::current();
429+
current_span
430+
.record("stream", tracing::field::display(&stream_name))
431+
.record("tenant", tracing::field::debug(&tenant_id));
423432
// For query mode, if the stream not found in memory map,
424-
//check if it exists in the storage
425-
//create stream and schema from storage
433+
// check if it exists in the storage
434+
// create stream and schema from storage
426435
if !PARSEABLE
427436
.check_or_load_stream(&stream_name, &tenant_id)
428437
.await
@@ -441,16 +450,14 @@ pub async fn put_stream_hot_tier(
441450

442451
validator::hot_tier(&hottier.size.to_string())?;
443452

444-
// TODO tenants
445-
stream.set_hot_tier(Some(hottier.clone()));
446-
let Some(hot_tier_manager) = HotTierManager::global() else {
453+
let Some(hot_tier_manager) = GLOBAL_HOTTIER.get() else {
447454
return Err(StreamError::HotTierNotEnabled(stream_name));
448455
};
449456
let existing_hot_tier_used_size = hot_tier_manager
450457
.validate_hot_tier_size(&stream_name, hottier.size, &tenant_id)
451458
.await?;
452459
hottier.used_size = existing_hot_tier_used_size;
453-
hottier.available_size = hottier.size;
460+
hottier.available_size = hottier.size.saturating_sub(existing_hot_tier_used_size);
454461
hottier.version = Some(CURRENT_HOT_TIER_VERSION.to_string());
455462
hot_tier_manager
456463
.put_hot_tier(&stream_name, &mut hottier, &tenant_id)
@@ -469,19 +476,34 @@ pub async fn put_stream_hot_tier(
469476
.metastore
470477
.put_stream_json(&stream_metadata, &stream_name, &tenant_id)
471478
.await?;
479+
stream.set_hot_tier(Some(hottier.clone()));
480+
let stream = stream_name.clone();
481+
let tenant = tenant_id.clone();
482+
hot_tier_manager
483+
.spawn_stream_task(stream, tenant)
484+
.instrument(current_span)
485+
.await;
472486

473487
Ok((
474488
format!("hot tier set for stream {stream_name}"),
475489
StatusCode::OK,
476490
))
477491
}
478492

493+
#[tracing::instrument(
494+
name = "http.get_stream_hot_tier",
495+
skip(req, logstream),
496+
fields(stream = tracing::field::Empty, tenant = tracing::field::Empty)
497+
)]
479498
pub async fn get_stream_hot_tier(
480499
req: HttpRequest,
481500
logstream: Path<String>,
482501
) -> Result<impl Responder, StreamError> {
483502
let stream_name = logstream.into_inner();
484503
let tenant_id = get_tenant_id_from_request(&req);
504+
tracing::Span::current()
505+
.record("stream", tracing::field::display(&stream_name))
506+
.record("tenant", tracing::field::debug(&tenant_id));
485507
// For query mode, if the stream not found in memory map,
486508
//check if it exists in the storage
487509
//create stream and schema from storage
@@ -492,7 +514,7 @@ pub async fn get_stream_hot_tier(
492514
return Err(StreamNotFound(stream_name.clone()).into());
493515
}
494516

495-
let Some(hot_tier_manager) = HotTierManager::global() else {
517+
let Some(hot_tier_manager) = GLOBAL_HOTTIER.get() else {
496518
return Err(StreamError::HotTierNotEnabled(stream_name));
497519
};
498520
let meta = hot_tier_manager
@@ -502,12 +524,21 @@ pub async fn get_stream_hot_tier(
502524
Ok((web::Json(meta), StatusCode::OK))
503525
}
504526

527+
#[tracing::instrument(
528+
name = "http.delete_stream_hot_tier",
529+
skip(req, logstream),
530+
fields(stream = tracing::field::Empty, tenant = tracing::field::Empty)
531+
)]
505532
pub async fn delete_stream_hot_tier(
506533
req: HttpRequest,
507534
logstream: Path<String>,
508535
) -> Result<impl Responder, StreamError> {
509536
let stream_name = logstream.into_inner();
510537
let tenant_id = get_tenant_id_from_request(&req);
538+
let current_span = tracing::Span::current();
539+
current_span
540+
.record("stream", tracing::field::display(&stream_name))
541+
.record("tenant", tracing::field::debug(&tenant_id));
511542
// For query mode, if the stream not found in memory map,
512543
//check if it exists in the storage
513544
//create stream and schema from storage
@@ -529,12 +560,13 @@ pub async fn delete_stream_hot_tier(
529560
});
530561
}
531562

532-
let Some(hot_tier_manager) = HotTierManager::global() else {
563+
let Some(hot_tier_manager) = GLOBAL_HOTTIER.get() else {
533564
return Err(StreamError::HotTierNotEnabled(stream_name));
534565
};
535566

536567
hot_tier_manager
537568
.delete_hot_tier(&stream_name, &tenant_id)
569+
.instrument(tracing::Span::current())
538570
.await?;
539571

540572
let mut stream_metadata: ObjectStoreFormat = serde_json::from_slice(

src/handlers/http/modal/mod.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use crate::{
3838
alerts::{ALERTS, get_alert_manager, target::TARGETS},
3939
cli::Options,
4040
correlation::CORRELATIONS,
41-
hottier::{HotTierManager, StreamHotTier},
41+
hottier::{GLOBAL_HOTTIER, HotTierManager, StreamHotTier},
4242
metastore::metastore_traits::MetastoreObject,
4343
oauth::{OAuthProvider, connect_oidc},
4444
option::Mode,
@@ -160,6 +160,11 @@ pub trait ParseableServer {
160160
// Shutdown resource monitor
161161
let _ = resource_shutdown_tx.send(());
162162

163+
// Shutdown hottier
164+
if let Some(htm) = GLOBAL_HOTTIER.get() {
165+
htm.abort_all().await;
166+
}
167+
163168
// Initiate graceful shutdown
164169
info!("Graceful shutdown of HTTP server triggered");
165170
srv_handle.stop(true).await;
@@ -627,7 +632,7 @@ pub type PrismMetadata = NodeMetadata;
627632
/// in their stream metadata but don't have local hot tier metadata files yet.
628633
/// This function is called once during query server startup.
629634
pub async fn initialize_hot_tier_metadata_on_startup(
630-
hot_tier_manager: &HotTierManager,
635+
hot_tier_manager: &'static HotTierManager,
631636
) -> anyhow::Result<()> {
632637
// Collect hot tier configurations from streams before doing async operations
633638
let hot_tier_configs: Vec<(String, Option<String>, StreamHotTier)> = {
@@ -653,21 +658,6 @@ pub async fn initialize_hot_tier_metadata_on_startup(
653658
})
654659
})
655660
.collect()
656-
// let streams_guard = PARSEABLE.streams.read().unwrap();
657-
// streams_guard
658-
// .iter()
659-
// .filter_map(|(stream_name, stream)| {
660-
// // Skip if hot tier metadata file already exists for this stream
661-
// if hot_tier_manager.check_stream_hot_tier_exists(stream_name) {
662-
// return None;
663-
// }
664-
665-
// // Get the hot tier configuration from the in-memory stream metadata
666-
// stream
667-
// .get_hot_tier()
668-
// .map(|config| (stream_name.clone(), config))
669-
// })
670-
// .collect()
671661
};
672662

673663
for (stream_name, tenant_id, hot_tier_config) in hot_tier_configs {

0 commit comments

Comments
 (0)