Skip to main content

xlog_core/
traits.rs

1//! Core traits for XLOG extensibility
2
3use crate::types::{AggOp, Schema};
4use crate::Result;
5
6/// Opaque handle to GPU memory buffer
7/// Actual implementation lives in xlog-cuda
8#[derive(Debug)]
9pub struct GpuBuffer {
10    /// Number of rows in this buffer
11    pub num_rows: u64,
12    /// Schema of this buffer
13    pub schema: Schema,
14}
15
16impl GpuBuffer {
17    /// Create an empty buffer
18    pub fn empty() -> Self {
19        Self {
20            num_rows: 0,
21            schema: Schema::new(vec![]),
22        }
23    }
24
25    /// Check if buffer is empty
26    pub fn is_empty(&self) -> bool {
27        self.num_rows == 0
28    }
29
30    /// Estimated memory usage in bytes
31    pub fn estimated_bytes(&self) -> u64 {
32        self.num_rows * self.schema.row_size_bytes() as u64
33    }
34}
35
36/// Trait for GPU kernel execution providers
37///
38/// This abstraction allows swapping CUDA for other backends (HIP, SYCL)
39pub trait KernelProvider: Send + Sync {
40    /// Perform a hash join between two buffers
41    fn hash_join(
42        &self,
43        left: &GpuBuffer,
44        right: &GpuBuffer,
45        left_keys: &[usize],
46        right_keys: &[usize],
47    ) -> Result<GpuBuffer>;
48
49    /// Remove duplicate rows based on key columns
50    fn dedup(&self, input: &GpuBuffer, key_cols: &[usize]) -> Result<GpuBuffer>;
51
52    /// Compute union of two buffers
53    fn union(&self, a: &GpuBuffer, b: &GpuBuffer) -> Result<GpuBuffer>;
54
55    /// Compute set difference (a - b)
56    fn diff(&self, a: &GpuBuffer, b: &GpuBuffer) -> Result<GpuBuffer>;
57
58    /// Perform groupby aggregation
59    fn groupby_agg(
60        &self,
61        input: &GpuBuffer,
62        key_cols: &[usize],
63        agg: AggOp,
64        value_col: usize,
65    ) -> Result<GpuBuffer>;
66}
67
68/// Trait for relation storage backends
69pub trait RelationStore: Send + Sync {
70    /// Get a relation by ID
71    fn get(&self, name: &str) -> Option<&GpuBuffer>;
72
73    /// Store a relation
74    fn put(&mut self, name: &str, buffer: GpuBuffer);
75
76    /// Check if relation exists
77    fn contains(&self, name: &str) -> bool;
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    struct MockProvider;
85
86    impl KernelProvider for MockProvider {
87        fn hash_join(
88            &self,
89            _left: &GpuBuffer,
90            _right: &GpuBuffer,
91            _left_keys: &[usize],
92            _right_keys: &[usize],
93        ) -> Result<GpuBuffer> {
94            Ok(GpuBuffer::empty())
95        }
96
97        fn dedup(&self, _input: &GpuBuffer, _key_cols: &[usize]) -> Result<GpuBuffer> {
98            Ok(GpuBuffer::empty())
99        }
100
101        fn union(&self, _a: &GpuBuffer, _b: &GpuBuffer) -> Result<GpuBuffer> {
102            Ok(GpuBuffer::empty())
103        }
104
105        fn diff(&self, _a: &GpuBuffer, _b: &GpuBuffer) -> Result<GpuBuffer> {
106            Ok(GpuBuffer::empty())
107        }
108
109        fn groupby_agg(
110            &self,
111            _input: &GpuBuffer,
112            _key_cols: &[usize],
113            _agg: AggOp,
114            _value_col: usize,
115        ) -> Result<GpuBuffer> {
116            Ok(GpuBuffer::empty())
117        }
118    }
119
120    #[test]
121    fn test_mock_provider_compiles() {
122        let provider = MockProvider;
123        let empty = GpuBuffer::empty();
124        assert!(provider.dedup(&empty, &[0]).is_ok());
125    }
126
127    #[test]
128    fn test_gpu_buffer_empty() {
129        let buf = GpuBuffer::empty();
130        assert!(buf.is_empty());
131        assert_eq!(buf.estimated_bytes(), 0);
132    }
133}