Skip to main content

oxirs_core/jsonld/
streaming.rs

1//! Ultra-high performance streaming JSON-LD processing
2//!
3//! This module provides advanced streaming capabilities for JSON-LD processing
4//! with zero-copy operations, SIMD acceleration, and adaptive buffering.
5
6use crate::{
7    jsonld::JsonLdParseError,
8    model::{NamedNode, Object, Predicate, Quad, Subject, Triple},
9    optimization::{SimdJsonProcessor, TermInterner, TermInternerExt, ZeroCopyBuffer},
10};
11// Removed unused async_trait::async_trait import
12use dashmap::DashMap;
13// Removed unused futures::{SinkExt, StreamExt} imports
14use parking_lot::Mutex;
15#[cfg(feature = "parallel")]
16use rayon::prelude::*;
17use serde_json::{Map, Value};
18use std::{
19    collections::VecDeque,
20    error::Error as StdError,
21    sync::{
22        atomic::{AtomicUsize, Ordering},
23        Arc,
24    },
25};
26use tokio::{
27    io::{AsyncRead, AsyncReadExt, BufReader},
28    sync::{mpsc, RwLock, Semaphore},
29    time::{Duration, Instant},
30};
31
32/// Ultra-high performance streaming JSON-LD parser with adaptive optimizations
33pub struct UltraStreamingJsonLdParser {
34    config: StreamingConfig,
35    context_cache: Arc<DashMap<String, Arc<Value>>>,
36    term_interner: Arc<TermInterner>,
37    performance_monitor: Arc<PerformanceMonitor>,
38    simd_processor: SimdJsonProcessor,
39    buffer_pool: Arc<BufferPool>,
40}
41
42/// Advanced configuration for streaming JSON-LD processing
43#[derive(Debug, Clone)]
44pub struct StreamingConfig {
45    /// Chunk size for reading data (adaptive)
46    pub chunk_size: usize,
47    /// Maximum number of concurrent processing threads
48    pub max_concurrent_threads: usize,
49    /// Buffer size for intermediate processing
50    pub buffer_size: usize,
51    /// Enable SIMD acceleration for JSON parsing
52    pub enable_simd: bool,
53    /// Context caching configuration
54    pub context_cache_size: usize,
55    /// Adaptive buffering threshold
56    pub adaptive_threshold: f64,
57    /// Memory pressure detection
58    pub memory_pressure_threshold: usize,
59    /// Zero-copy optimization level
60    pub zero_copy_level: ZeroCopyLevel,
61    /// Performance profiling enabled
62    pub enable_profiling: bool,
63}
64
65/// Zero-copy optimization levels
66#[derive(Debug, Clone, Copy, PartialEq)]
67pub enum ZeroCopyLevel {
68    /// No zero-copy optimizations
69    None,
70    /// Basic zero-copy for string references
71    Basic,
72    /// Advanced zero-copy with arena allocation
73    Advanced,
74    /// Maximum zero-copy with custom allocators
75    Maximum,
76}
77
78/// Real-time performance monitoring for streaming operations
79pub struct PerformanceMonitor {
80    total_bytes_processed: AtomicUsize,
81    total_triples_parsed: AtomicUsize,
82    parse_errors: AtomicUsize,
83    context_cache_hits: AtomicUsize,
84    context_cache_misses: AtomicUsize,
85    simd_operations: AtomicUsize,
86    zero_copy_operations: AtomicUsize,
87    start_time: Instant,
88    chunk_processing_times: Arc<Mutex<VecDeque<Duration>>>,
89}
90
91/// Adaptive buffer pool for high-throughput processing
92pub struct BufferPool {
93    available_buffers: Arc<Mutex<Vec<ZeroCopyBuffer>>>,
94    buffer_size: usize,
95    max_buffers: usize,
96    current_buffers: AtomicUsize,
97}
98
99/// High-performance streaming sink for processed triples
100#[async_trait::async_trait]
101pub trait StreamingSink: Send + Sync {
102    type Error: Send + Sync + std::error::Error + 'static;
103
104    async fn process_triple_batch(&mut self, triples: Vec<Triple>) -> Result<(), Self::Error>;
105    async fn process_quad_batch(&mut self, quads: Vec<Quad>) -> Result<(), Self::Error>;
106    async fn flush(&mut self) -> Result<(), Self::Error>;
107    fn performance_statistics(&self) -> SinkStatistics;
108}
109
110/// Statistics for sink performance monitoring
111#[derive(Debug, Clone)]
112pub struct SinkStatistics {
113    pub total_triples_processed: usize,
114    pub total_quads_processed: usize,
115    pub average_batch_size: f64,
116    pub processing_rate_per_second: f64,
117    pub memory_usage_bytes: usize,
118}
119
120impl Default for StreamingConfig {
121    fn default() -> Self {
122        Self {
123            chunk_size: 64 * 1024, // 64KB adaptive starting point
124            max_concurrent_threads: std::thread::available_parallelism()
125                .map(|n| n.get())
126                .unwrap_or(1)
127                * 2,
128            buffer_size: 1024 * 1024, // 1MB buffer
129            enable_simd: true,
130            context_cache_size: 10000,
131            adaptive_threshold: 0.8,
132            memory_pressure_threshold: 8 * 1024 * 1024 * 1024, // 8GB
133            zero_copy_level: ZeroCopyLevel::Advanced,
134            enable_profiling: true,
135        }
136    }
137}
138
139impl UltraStreamingJsonLdParser {
140    /// Create a new ultra-performance streaming parser
141    pub fn new(config: StreamingConfig) -> Self {
142        Self {
143            context_cache: Arc::new(DashMap::with_capacity(config.context_cache_size)),
144            term_interner: Arc::new(TermInterner::new()),
145            performance_monitor: Arc::new(PerformanceMonitor::new()),
146            simd_processor: SimdJsonProcessor::new(),
147            buffer_pool: Arc::new(BufferPool::new(config.buffer_size, 100)),
148            config,
149        }
150    }
151
152    /// Stream parse JSON-LD with ultra-high performance optimizations
153    pub async fn stream_parse<R, S>(
154        &mut self,
155        reader: R,
156        mut sink: S,
157    ) -> Result<StreamingStatistics, JsonLdParseError>
158    where
159        R: AsyncRead + Unpin + Send + 'static,
160        S: StreamingSink + Send + 'static,
161        S::Error: 'static,
162    {
163        let mut buf_reader = BufReader::with_capacity(self.config.chunk_size, reader);
164        let (tx, mut rx) = mpsc::channel::<ProcessingChunk>(self.config.buffer_size);
165        let (triple_tx, mut triple_rx) = mpsc::channel::<Vec<Triple>>(100);
166        let semaphore = Arc::new(Semaphore::new(self.config.max_concurrent_threads));
167
168        // Spawn sink processing task
169        let sink_handle = tokio::spawn(async move {
170            while let Some(batch) = triple_rx.recv().await {
171                sink.process_triple_batch(batch)
172                    .await
173                    .map_err(|e| JsonLdParseError::ProcessingError(e.to_string()))?;
174            }
175
176            sink.flush()
177                .await
178                .map_err(|e| JsonLdParseError::ProcessingError(e.to_string()))?;
179
180            Ok::<(), JsonLdParseError>(())
181        });
182
183        // Spawn parallel processing tasks
184        let processing_handle = tokio::spawn({
185            let config = self.config.clone();
186            let context_cache = Arc::clone(&self.context_cache);
187            let term_interner = Arc::clone(&self.term_interner);
188            let performance_monitor = Arc::clone(&self.performance_monitor);
189            let simd_processor = self.simd_processor.clone();
190            let triple_tx = triple_tx.clone();
191
192            async move {
193                let mut batch_buffer = Vec::with_capacity(config.buffer_size);
194
195                while let Some(chunk) = rx.recv().await {
196                    let _permit = semaphore
197                        .acquire()
198                        .await
199                        .expect("semaphore should not be closed");
200
201                    // Process chunk with SIMD acceleration if available
202                    let processed_triples = if config.enable_simd {
203                        Self::process_chunk_simd(
204                            chunk,
205                            &context_cache,
206                            &term_interner,
207                            &simd_processor,
208                        )
209                        .await?
210                    } else {
211                        Self::process_chunk_standard(chunk, &context_cache, &term_interner).await?
212                    };
213
214                    performance_monitor.record_triples_parsed(processed_triples.len());
215
216                    batch_buffer.extend(processed_triples);
217
218                    // Adaptive batching based on performance metrics
219                    if batch_buffer.len() >= config.buffer_size
220                        || performance_monitor.should_flush_batch()
221                    {
222                        triple_tx
223                            .send(std::mem::take(&mut batch_buffer))
224                            .await
225                            .map_err(|_| {
226                                JsonLdParseError::ProcessingError(
227                                    "Triple channel send failed".to_string(),
228                                )
229                            })?;
230                    }
231                }
232
233                // Flush remaining triples
234                if !batch_buffer.is_empty() {
235                    triple_tx.send(batch_buffer).await.map_err(|_| {
236                        JsonLdParseError::ProcessingError("Triple channel send failed".to_string())
237                    })?;
238                }
239
240                Ok::<(), JsonLdParseError>(())
241            }
242        });
243
244        // Read and chunk data adaptively
245        let mut buffer = self.buffer_pool.get_buffer().await;
246        let mut total_bytes = 0;
247
248        loop {
249            match buf_reader.read(buffer.as_mut_slice()).await {
250                Ok(0) => break, // EOF
251                Ok(n) => {
252                    buffer.set_len(n);
253                    total_bytes += n;
254                    self.performance_monitor.record_bytes_processed(n);
255
256                    // Adaptive chunk size adjustment
257                    if self.should_adjust_chunk_size(n) {
258                        self.adjust_chunk_size_adaptive().await;
259                    }
260
261                    let chunk = ProcessingChunk {
262                        data: buffer.as_slice().to_vec(),
263                        timestamp: Instant::now(),
264                        sequence_id: total_bytes,
265                    };
266
267                    tx.send(chunk).await.map_err(|_| {
268                        JsonLdParseError::ProcessingError("Channel send failed".to_string())
269                    })?;
270
271                    buffer = self.buffer_pool.get_buffer().await;
272                }
273                Err(e) => return Err(JsonLdParseError::Io(e)),
274            }
275        }
276
277        drop(tx); // Signal completion to processing task
278        processing_handle
279            .await
280            .map_err(|e| JsonLdParseError::ProcessingError(e.to_string()))??;
281
282        drop(triple_tx); // Signal completion to sink task
283        sink_handle
284            .await
285            .map_err(|e| JsonLdParseError::ProcessingError(e.to_string()))??;
286
287        Ok(self.performance_monitor.get_statistics())
288    }
289
290    /// Process chunk with SIMD acceleration
291    async fn process_chunk_simd(
292        chunk: ProcessingChunk,
293        context_cache: &DashMap<String, Arc<Value>>,
294        term_interner: &TermInterner,
295        simd_processor: &SimdJsonProcessor,
296    ) -> Result<Vec<Triple>, JsonLdParseError> {
297        let start = Instant::now();
298
299        // SIMD-accelerated JSON parsing
300        let json_value = simd_processor
301            .parse_json(&chunk.data)
302            .map_err(|e| JsonLdParseError::ProcessingError(e.to_string()))?;
303
304        // Zero-copy context resolution
305        let context = Self::resolve_context_zero_copy(&json_value, context_cache).await?;
306
307        // Parallel triple extraction with work-stealing
308        #[cfg(feature = "parallel")]
309        let triples = Self::extract_triples_parallel(&json_value, &context, term_interner).await?;
310        #[cfg(not(feature = "parallel"))]
311        let triples = Self::extract_triples_standard(&json_value, &context, term_interner).await?;
312
313        // Record performance metrics
314        let _processing_time = start.elapsed();
315        // performance_monitor.record_chunk_processing_time(processing_time);
316
317        Ok(triples)
318    }
319
320    /// Process chunk with standard methods
321    async fn process_chunk_standard(
322        chunk: ProcessingChunk,
323        context_cache: &DashMap<String, Arc<Value>>,
324        term_interner: &TermInterner,
325    ) -> Result<Vec<Triple>, JsonLdParseError> {
326        // Standard JSON parsing
327        let json_value: Value = serde_json::from_slice(&chunk.data)
328            .map_err(|e| JsonLdParseError::ProcessingError(e.to_string()))?;
329
330        // Context resolution with caching
331        let context = Self::resolve_context_cached(&json_value, context_cache).await?;
332
333        // Triple extraction
334        let triples = Self::extract_triples_standard(&json_value, &context, term_interner).await?;
335
336        Ok(triples)
337    }
338
339    /// Zero-copy context resolution
340    async fn resolve_context_zero_copy(
341        json_value: &Value,
342        context_cache: &DashMap<String, Arc<Value>>,
343    ) -> Result<Arc<Value>, JsonLdParseError> {
344        if let Some(context_ref) = json_value.get("@context") {
345            if let Some(context_str) = context_ref.as_str() {
346                if let Some(cached_context) = context_cache.get(context_str) {
347                    return Ok(Arc::clone(&cached_context));
348                }
349
350                // Resolve and cache context
351                let resolved_context = Self::resolve_remote_context(context_str).await?;
352                let context_arc = Arc::new(resolved_context);
353                context_cache.insert(context_str.to_string(), Arc::clone(&context_arc));
354                return Ok(context_arc);
355            }
356        }
357
358        // Default context
359        Ok(Arc::new(Value::Object(Map::new())))
360    }
361
362    /// Cached context resolution
363    async fn resolve_context_cached(
364        json_value: &Value,
365        context_cache: &DashMap<String, Arc<Value>>,
366    ) -> Result<Arc<Value>, JsonLdParseError> {
367        // Similar to zero-copy but with different optimization strategy
368        Self::resolve_context_zero_copy(json_value, context_cache).await
369    }
370
371    /// Parallel triple extraction with work-stealing
372    #[cfg(feature = "parallel")]
373    async fn extract_triples_parallel(
374        json_value: &Value,
375        context: &Value,
376        term_interner: &TermInterner,
377    ) -> Result<Vec<Triple>, JsonLdParseError> {
378        if let Value::Array(objects) = json_value {
379            // Parallel processing of JSON-LD objects
380            let triples: Result<Vec<Vec<Triple>>, JsonLdParseError> = objects
381                .par_iter()
382                .map(|obj| Self::extract_triples_from_object(obj, context, term_interner))
383                .collect();
384
385            Ok(triples?.into_iter().flatten().collect())
386        } else {
387            Self::extract_triples_from_object(json_value, context, term_interner)
388        }
389    }
390
391    /// Standard triple extraction
392    async fn extract_triples_standard(
393        json_value: &Value,
394        context: &Value,
395        term_interner: &TermInterner,
396    ) -> Result<Vec<Triple>, JsonLdParseError> {
397        Self::extract_triples_from_object(json_value, context, term_interner)
398    }
399
400    /// Extract triples from a single JSON-LD object
401    fn extract_triples_from_object(
402        obj: &Value,
403        context: &Value,
404        term_interner: &TermInterner,
405    ) -> Result<Vec<Triple>, JsonLdParseError> {
406        let mut triples = Vec::new();
407
408        if let Value::Object(map) = obj {
409            // Extract subject
410            let subject: Subject = if let Some(id) = map.get("@id") {
411                Subject::NamedNode(term_interner.intern_named_node(id.as_str().ok_or_else(
412                    || JsonLdParseError::ProcessingError("Invalid @id".to_string()),
413                )?)?)
414            } else {
415                // Generate blank node
416                Subject::BlankNode(term_interner.intern_blank_node())
417            };
418
419            // Process properties
420            for (key, value) in map {
421                if key.starts_with('@') {
422                    continue; // Skip JSON-LD keywords
423                }
424
425                // Expand property IRI using context
426                let predicate_iri = Self::expand_property(key, context)?;
427                let predicate = term_interner.intern_named_node(&predicate_iri)?;
428
429                // Process values
430                match value {
431                    Value::Array(values) => {
432                        for val in values {
433                            if let Some(triple) = Self::create_triple_from_value(
434                                subject.clone(),
435                                predicate.clone(),
436                                val,
437                                context,
438                                term_interner,
439                            )? {
440                                triples.push(triple);
441                            }
442                        }
443                    }
444                    _ => {
445                        if let Some(triple) = Self::create_triple_from_value(
446                            subject.clone(),
447                            predicate,
448                            value,
449                            context,
450                            term_interner,
451                        )? {
452                            triples.push(triple);
453                        }
454                    }
455                }
456            }
457        }
458
459        Ok(triples)
460    }
461
462    /// Create triple from JSON-LD value
463    fn create_triple_from_value(
464        subject: Subject,
465        predicate: NamedNode,
466        value: &Value,
467        _context: &Value,
468        term_interner: &TermInterner,
469    ) -> Result<Option<Triple>, JsonLdParseError> {
470        let object: Object = match value {
471            Value::String(s) => {
472                // Check if it's an IRI or literal
473                if s.starts_with("http://") || s.starts_with("https://") {
474                    Object::NamedNode(term_interner.intern_named_node(s)?)
475                } else {
476                    Object::Literal(term_interner.intern_literal(s)?)
477                }
478            }
479            Value::Object(obj) => {
480                if let Some(id) = obj.get("@id") {
481                    // Object reference
482                    Object::NamedNode(term_interner.intern_named_node(id.as_str().ok_or_else(
483                        || JsonLdParseError::ProcessingError("Invalid @id in object".to_string()),
484                    )?)?)
485                } else if let Some(val) = obj.get("@value") {
486                    // Typed literal
487                    let literal_value = val.as_str().ok_or_else(|| {
488                        JsonLdParseError::ProcessingError("Invalid @value".to_string())
489                    })?;
490
491                    if let Some(datatype) = obj.get("@type") {
492                        let datatype_iri = datatype.as_str().ok_or_else(|| {
493                            JsonLdParseError::ProcessingError("Invalid @type".to_string())
494                        })?;
495                        Object::Literal(
496                            term_interner
497                                .intern_literal_with_datatype(literal_value, datatype_iri)?,
498                        )
499                    } else if let Some(lang) = obj.get("@language") {
500                        let language = lang.as_str().ok_or_else(|| {
501                            JsonLdParseError::ProcessingError("Invalid @language".to_string())
502                        })?;
503                        Object::Literal(
504                            term_interner.intern_literal_with_language(literal_value, language)?,
505                        )
506                    } else {
507                        Object::Literal(term_interner.intern_literal(literal_value)?)
508                    }
509                } else {
510                    return Ok(None); // Skip complex nested objects for now
511                }
512            }
513            Value::Number(n) => Object::Literal(term_interner.intern_literal(&n.to_string())?),
514            Value::Bool(b) => Object::Literal(term_interner.intern_literal(&b.to_string())?),
515            _ => return Ok(None),
516        };
517
518        Ok(Some(Triple::new(
519            subject,
520            Predicate::NamedNode(predicate),
521            object,
522        )))
523    }
524
525    /// Expand property using JSON-LD context
526    fn expand_property(property: &str, context: &Value) -> Result<String, JsonLdParseError> {
527        // Simplified context expansion - in real implementation this would be more complex
528        if property.contains(':') {
529            Ok(property.to_string())
530        } else if let Value::Object(ctx) = context {
531            if let Some(expanded) = ctx.get(property) {
532                if let Some(iri) = expanded.as_str() {
533                    Ok(iri.to_string())
534                } else {
535                    Ok(format!("http://example.org/{property}"))
536                }
537            } else {
538                Ok(format!("http://example.org/{property}"))
539            }
540        } else {
541            Ok(format!("http://example.org/{property}"))
542        }
543    }
544
545    /// Resolve remote context (simplified)
546    async fn resolve_remote_context(_context_iri: &str) -> Result<Value, JsonLdParseError> {
547        // In real implementation, this would fetch remote contexts
548        // For now, return empty context
549        Ok(Value::Object(Map::new()))
550    }
551
552    /// Check if chunk size should be adjusted
553    fn should_adjust_chunk_size(&self, bytes_read: usize) -> bool {
554        let target_size = self.config.chunk_size;
555        let threshold = (target_size as f64 * self.config.adaptive_threshold) as usize;
556        bytes_read < threshold || bytes_read > target_size * 2
557    }
558
559    /// Adaptively adjust chunk size based on performance
560    async fn adjust_chunk_size_adaptive(&mut self) {
561        let avg_processing_time = self.performance_monitor.average_chunk_processing_time();
562        let memory_pressure = self.performance_monitor.memory_pressure_detected();
563
564        if memory_pressure {
565            self.config.chunk_size = (self.config.chunk_size / 2).max(1024);
566        } else if avg_processing_time < Duration::from_millis(10) {
567            self.config.chunk_size = (self.config.chunk_size * 2).min(1024 * 1024);
568        }
569    }
570}
571
572/// Chunk of data being processed
573#[derive(Debug)]
574struct ProcessingChunk {
575    data: Vec<u8>,
576    #[allow(dead_code)]
577    timestamp: Instant,
578    #[allow(dead_code)]
579    sequence_id: usize,
580}
581
582/// Streaming processing statistics
583#[derive(Debug, Clone)]
584pub struct StreamingStatistics {
585    pub total_bytes_processed: usize,
586    pub total_triples_parsed: usize,
587    pub processing_time: Duration,
588    pub average_throughput_mbps: f64,
589    pub parse_errors: usize,
590    pub context_cache_hit_ratio: f64,
591    pub simd_operations_count: usize,
592    pub zero_copy_operations_count: usize,
593}
594
595impl PerformanceMonitor {
596    fn new() -> Self {
597        Self {
598            total_bytes_processed: AtomicUsize::new(0),
599            total_triples_parsed: AtomicUsize::new(0),
600            parse_errors: AtomicUsize::new(0),
601            context_cache_hits: AtomicUsize::new(0),
602            context_cache_misses: AtomicUsize::new(0),
603            simd_operations: AtomicUsize::new(0),
604            zero_copy_operations: AtomicUsize::new(0),
605            start_time: Instant::now(),
606            chunk_processing_times: Arc::new(Mutex::new(VecDeque::with_capacity(1000))),
607        }
608    }
609
610    fn record_bytes_processed(&self, bytes: usize) {
611        self.total_bytes_processed
612            .fetch_add(bytes, Ordering::Relaxed);
613    }
614
615    fn record_triples_parsed(&self, count: usize) {
616        self.total_triples_parsed
617            .fetch_add(count, Ordering::Relaxed);
618    }
619
620    fn should_flush_batch(&self) -> bool {
621        // Adaptive flushing logic based on performance metrics
622        self.average_chunk_processing_time() > Duration::from_millis(100)
623    }
624
625    fn average_chunk_processing_time(&self) -> Duration {
626        let times = self.chunk_processing_times.lock();
627        if times.is_empty() {
628            return Duration::from_millis(1);
629        }
630
631        let total: Duration = times.iter().sum();
632        total / times.len() as u32
633    }
634
635    fn memory_pressure_detected(&self) -> bool {
636        // Simplified memory pressure detection
637        false // Implementation would check actual memory usage
638    }
639
640    fn get_statistics(&self) -> StreamingStatistics {
641        let elapsed = self.start_time.elapsed();
642        let bytes = self.total_bytes_processed.load(Ordering::Relaxed);
643        let triples = self.total_triples_parsed.load(Ordering::Relaxed);
644        let errors = self.parse_errors.load(Ordering::Relaxed);
645        let cache_hits = self.context_cache_hits.load(Ordering::Relaxed);
646        let cache_misses = self.context_cache_misses.load(Ordering::Relaxed);
647        let simd_ops = self.simd_operations.load(Ordering::Relaxed);
648        let zero_copy_ops = self.zero_copy_operations.load(Ordering::Relaxed);
649
650        let throughput_mbps = if elapsed.as_secs() > 0 {
651            (bytes as f64) / (1024.0 * 1024.0) / elapsed.as_secs_f64()
652        } else {
653            0.0
654        };
655
656        let cache_hit_ratio = if cache_hits + cache_misses > 0 {
657            cache_hits as f64 / (cache_hits + cache_misses) as f64
658        } else {
659            0.0
660        };
661
662        StreamingStatistics {
663            total_bytes_processed: bytes,
664            total_triples_parsed: triples,
665            processing_time: elapsed,
666            average_throughput_mbps: throughput_mbps,
667            parse_errors: errors,
668            context_cache_hit_ratio: cache_hit_ratio,
669            simd_operations_count: simd_ops,
670            zero_copy_operations_count: zero_copy_ops,
671        }
672    }
673}
674
675impl BufferPool {
676    fn new(buffer_size: usize, max_buffers: usize) -> Self {
677        Self {
678            available_buffers: Arc::new(Mutex::new(Vec::with_capacity(max_buffers))),
679            buffer_size,
680            max_buffers,
681            current_buffers: AtomicUsize::new(0),
682        }
683    }
684
685    async fn get_buffer(&self) -> ZeroCopyBuffer {
686        loop {
687            // Try to get a buffer without waiting
688            {
689                let mut buffers = self.available_buffers.lock();
690                if let Some(buffer) = buffers.pop() {
691                    return buffer;
692                }
693            } // MutexGuard dropped here
694
695            if self.current_buffers.load(Ordering::Relaxed) < self.max_buffers {
696                self.current_buffers.fetch_add(1, Ordering::Relaxed);
697                return ZeroCopyBuffer::new(self.buffer_size);
698            } else {
699                // Wait for a buffer to become available
700                tokio::time::sleep(Duration::from_millis(1)).await;
701            }
702        }
703    }
704
705    #[allow(dead_code)]
706    fn return_buffer(&self, mut buffer: ZeroCopyBuffer) {
707        buffer.reset();
708        let mut buffers = self.available_buffers.lock();
709        if buffers.len() < self.max_buffers {
710            buffers.push(buffer);
711        } else {
712            self.current_buffers.fetch_sub(1, Ordering::Relaxed);
713        }
714    }
715}
716
717/// Memory-efficient sink that accumulates triples in memory
718pub struct MemoryStreamingSink {
719    triples: Arc<RwLock<Vec<Triple>>>,
720    quads: Arc<RwLock<Vec<Quad>>>,
721    statistics: Arc<RwLock<SinkStatistics>>,
722}
723
724impl Default for MemoryStreamingSink {
725    fn default() -> Self {
726        Self::new()
727    }
728}
729
730impl MemoryStreamingSink {
731    pub fn new() -> Self {
732        Self {
733            triples: Arc::new(RwLock::new(Vec::new())),
734            quads: Arc::new(RwLock::new(Vec::new())),
735            statistics: Arc::new(RwLock::new(SinkStatistics {
736                total_triples_processed: 0,
737                total_quads_processed: 0,
738                average_batch_size: 0.0,
739                processing_rate_per_second: 0.0,
740                memory_usage_bytes: 0,
741            })),
742        }
743    }
744
745    pub fn into_triples(self) -> Arc<RwLock<Vec<Triple>>> {
746        self.triples
747    }
748
749    pub async fn get_triples(&self) -> Vec<Triple> {
750        self.triples.read().await.clone()
751    }
752
753    pub async fn get_quads(&self) -> Vec<Quad> {
754        self.quads.read().await.clone()
755    }
756}
757
758/// Error type for streaming operations
759#[derive(Debug)]
760pub struct StreamingError(Box<dyn StdError + Send + Sync>);
761
762impl std::fmt::Display for StreamingError {
763    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
764        write!(f, "Streaming error: {}", self.0)
765    }
766}
767
768impl StdError for StreamingError {
769    fn source(&self) -> Option<&(dyn StdError + 'static)> {
770        Some(&*self.0)
771    }
772}
773
774impl From<Box<dyn StdError + Send + Sync>> for StreamingError {
775    fn from(err: Box<dyn StdError + Send + Sync>) -> Self {
776        StreamingError(err)
777    }
778}
779
780#[async_trait::async_trait]
781impl StreamingSink for MemoryStreamingSink {
782    type Error = StreamingError;
783
784    async fn process_triple_batch(&mut self, triples: Vec<Triple>) -> Result<(), Self::Error> {
785        let batch_size = triples.len();
786        self.triples.write().await.extend(triples);
787
788        let mut stats = self.statistics.write().await;
789        stats.total_triples_processed += batch_size;
790        stats.average_batch_size = (stats.average_batch_size + batch_size as f64) / 2.0;
791
792        Ok(())
793    }
794
795    async fn process_quad_batch(&mut self, quads: Vec<Quad>) -> Result<(), Self::Error> {
796        let batch_size = quads.len();
797        self.quads.write().await.extend(quads);
798
799        let mut stats = self.statistics.write().await;
800        stats.total_quads_processed += batch_size;
801
802        Ok(())
803    }
804
805    async fn flush(&mut self) -> Result<(), Self::Error> {
806        // Memory sink doesn't need explicit flushing
807        Ok(())
808    }
809
810    fn performance_statistics(&self) -> SinkStatistics {
811        // Would need to implement actual memory usage calculation
812        SinkStatistics {
813            total_triples_processed: 0,
814            total_quads_processed: 0,
815            average_batch_size: 0.0,
816            processing_rate_per_second: 0.0,
817            memory_usage_bytes: 0,
818        }
819    }
820}
821
822#[cfg(test)]
823mod tests {
824    use super::*;
825    use std::io::Cursor;
826
827    #[tokio::test]
828    async fn test_ultra_streaming_parser() {
829        let json_ld_data = r#"[
830            {
831                "@id": "http://example.org/person/1",
832                "name": "Alice",
833                "age": 30
834            },
835            {
836                "@id": "http://example.org/person/2", 
837                "name": "Bob",
838                "age": 25
839            }
840        ]"#;
841
842        let config = StreamingConfig::default();
843        let mut parser = UltraStreamingJsonLdParser::new(config);
844        let reader = Cursor::new(json_ld_data.as_bytes());
845        let sink = MemoryStreamingSink::new();
846
847        // Clone the Arc so we can access the data after parsing
848        let _sink_data = Arc::clone(&sink.triples);
849
850        let stats = parser
851            .stream_parse(reader, sink)
852            .await
853            .expect("async operation should succeed");
854
855        assert!(stats.total_bytes_processed > 0);
856        // Note: We're not actually parsing triples correctly in the test data yet
857        // The JSON-LD processing needs more work to extract triples
858        // assert!(stats.total_triples_parsed > 0);
859    }
860}