Skip to content

Commit d1f8107

Browse files
committed
Use ArcSwap for aggregate fn registry
Signed-off-by: Robert Kruszewski <github@robertk.io>
1 parent 7a93d3e commit d1f8107

4 files changed

Lines changed: 34 additions & 32 deletions

File tree

vortex-array/src/aggregate_fn/accumulator.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,21 +142,19 @@ impl<V: AggregateFnVTable> DynAccumulator for Accumulator<V> {
142142
}
143143

144144
let session = ctx.session().clone();
145-
let kernels = &session.aggregate_fns().kernels;
145+
let kernels = &session.aggregate_fns().kernels.load();
146146

147147
// 1. Kernel registry first: a registered `(encoding, aggregate_fn)` kernel is strictly
148148
// more specific than the vtable's `try_accumulate` short-circuit. Checking the
149149
// registry first gives kernels for `Combined<V>` aggregates a chance to fire —
150150
// `Combined::try_accumulate` always returns true, so a later kernel check would be
151151
// unreachable.
152152
{
153-
let kernels_r = kernels.read();
154153
let batch_id = batch.encoding_id();
155-
let kernel = kernels_r
154+
let kernel = kernels
156155
.get(&(batch_id, Some(self.aggregate_fn.id())))
157-
.or_else(|| kernels_r.get(&(batch_id, None)))
156+
.or_else(|| kernels.get(&(batch_id, None)))
158157
.copied();
159-
drop(kernels_r);
160158
if let Some(kernel) = kernel
161159
&& let Some(result) = kernel.aggregate(&self.aggregate_fn, batch, ctx)?
162160
{
@@ -187,13 +185,11 @@ impl<V: AggregateFnVTable> DynAccumulator for Accumulator<V> {
187185
break;
188186
}
189187

190-
let kernels_r = kernels.read();
191188
let batch_id = batch.encoding_id();
192-
let kernel = kernels_r
189+
let kernel = kernels
193190
.get(&(batch_id, Some(self.aggregate_fn.id())))
194-
.or_else(|| kernels_r.get(&(batch_id, None)))
191+
.or_else(|| kernels.get(&(batch_id, None)))
195192
.copied();
196-
drop(kernels_r);
197193
if let Some(kernel) = kernel
198194
&& let Some(result) = kernel.aggregate(&self.aggregate_fn, &batch, ctx)?
199195
{

vortex-array/src/aggregate_fn/accumulator_grouped.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,17 +163,16 @@ impl<V: AggregateFnVTable> GroupedAccumulator<V> {
163163
let mut elements = groups.elements().clone();
164164
let groups_validity = groups.validity()?;
165165
let session = ctx.session().clone();
166-
let kernels = &session.aggregate_fns().grouped_kernels;
166+
let kernels = &session.aggregate_fns().grouped_kernels.load();
167167

168168
for _ in 0..max_iterations() {
169169
if elements.is::<AnyCanonical>() {
170170
break;
171171
}
172172

173-
let kernels_r = kernels.read();
174-
if let Some(result) = kernels_r
173+
if let Some(result) = kernels
175174
.get(&(elements.encoding_id(), Some(self.aggregate_fn.id())))
176-
.or_else(|| kernels_r.get(&(elements.encoding_id(), None)))
175+
.or_else(|| kernels.get(&(elements.encoding_id(), None)))
177176
.and_then(|kernel| {
178177
// SAFETY: we assume that elements execution is safe
179178
let groups = unsafe {
@@ -255,17 +254,16 @@ impl<V: AggregateFnVTable> GroupedAccumulator<V> {
255254
let mut elements = groups.elements().clone();
256255
let groups_validity = groups.validity()?;
257256
let session = ctx.session().clone();
258-
let kernels = &session.aggregate_fns().grouped_kernels;
257+
let kernels = &session.aggregate_fns().grouped_kernels.load();
259258

260259
for _ in 0..64 {
261260
if elements.is::<AnyCanonical>() {
262261
break;
263262
}
264263

265-
let kernels_r = kernels.read();
266-
if let Some(result) = kernels_r
264+
if let Some(result) = kernels
267265
.get(&(elements.encoding_id(), Some(self.aggregate_fn.id())))
268-
.or_else(|| kernels_r.get(&(elements.encoding_id(), None)))
266+
.or_else(|| kernels.get(&(elements.encoding_id(), None)))
269267
.and_then(|kernel| {
270268
// SAFETY: we assume that elements execution is safe
271269
let groups = unsafe {

vortex-array/src/aggregate_fn/proto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl AggregateFnRef {
3636
/// Note: the serialization format is not stable and may change between versions.
3737
pub fn from_proto(proto: &pb::AggregateFn, session: &VortexSession) -> VortexResult<Self> {
3838
let agg_fn_id: AggregateFnId = AggregateFnId::new(proto.id.as_str());
39-
let agg_fn = if let Some(plugin) = session.aggregate_fns().registry().find(&agg_fn_id) {
39+
let agg_fn = if let Some(plugin) = session.aggregate_fns().find_plugin(&agg_fn_id) {
4040
plugin.deserialize(proto.metadata(), session)?
4141
} else if session.allows_unknown() {
4242
new_foreign_aggregate_fn(agg_fn_id, proto.metadata().to_vec())

vortex-array/src/aggregate_fn/session.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
use std::any::Any;
55
use std::sync::Arc;
66

7-
use parking_lot::RwLock;
7+
use arc_swap::ArcSwap;
88
use vortex_session::Ref;
99
use vortex_session::SessionExt;
1010
use vortex_session::SessionVar;
@@ -49,10 +49,10 @@ pub type AggregateFnRegistry = Registry<AggregateFnPluginRef>;
4949
/// Session state for aggregate function vtables.
5050
#[derive(Debug)]
5151
pub struct AggregateFnSession {
52-
registry: AggregateFnRegistry,
52+
registry: ArcSwap<HashMap<AggregateFnId, AggregateFnPluginRef>>,
5353

54-
pub(super) kernels: RwLock<HashMap<KernelKey, &'static dyn DynAggregateKernel>>,
55-
pub(super) grouped_kernels: RwLock<HashMap<KernelKey, &'static dyn DynGroupedAggregateKernel>>,
54+
pub(super) kernels: ArcSwap<HashMap<KernelKey, &'static dyn DynAggregateKernel>>,
55+
pub(super) grouped_kernels: ArcSwap<HashMap<KernelKey, &'static dyn DynGroupedAggregateKernel>>,
5656
}
5757

5858
impl SessionVar for AggregateFnSession {
@@ -70,9 +70,9 @@ type KernelKey = (ArrayId, Option<AggregateFnId>);
7070
impl Default for AggregateFnSession {
7171
fn default() -> Self {
7272
let this = Self {
73-
registry: AggregateFnRegistry::default(),
74-
kernels: RwLock::new(HashMap::default()),
75-
grouped_kernels: RwLock::new(HashMap::default()),
73+
registry: ArcSwap::from_pointee(HashMap::default()),
74+
kernels: ArcSwap::from_pointee(HashMap::default()),
75+
grouped_kernels: ArcSwap::from_pointee(HashMap::default()),
7676
};
7777

7878
// Register the built-in aggregate functions
@@ -107,15 +107,20 @@ impl Default for AggregateFnSession {
107107

108108
impl AggregateFnSession {
109109
/// Returns the aggregate function registry.
110-
pub fn registry(&self) -> &AggregateFnRegistry {
111-
&self.registry
110+
pub fn find_plugin(&self, id: &AggregateFnId) -> Option<AggregateFnPluginRef> {
111+
self.registry.load().get(id).cloned()
112112
}
113113

114114
/// Register an aggregate function vtable in the session, replacing any existing vtable with
115115
/// the same ID.
116116
pub fn register<V: AggregateFnVTable>(&self, vtable: V) {
117-
self.registry
118-
.register(vtable.id(), Arc::new(vtable) as AggregateFnPluginRef);
117+
let id = vtable.id();
118+
let pluginref = Arc::new(vtable) as AggregateFnPluginRef;
119+
self.registry.rcu(move |registry| {
120+
let mut existing = registry.as_ref().clone();
121+
existing.insert(id, Arc::clone(&pluginref));
122+
existing
123+
});
119124
}
120125

121126
/// Register an aggregate function kernel for a specific aggregate function and array type.
@@ -125,9 +130,12 @@ impl AggregateFnSession {
125130
agg_fn_id: Option<impl Into<AggregateFnId>>,
126131
kernel: &'static dyn DynAggregateKernel,
127132
) {
128-
self.kernels
129-
.write()
130-
.insert((array_id.into(), agg_fn_id.map(|id| id.into())), kernel);
133+
let id = (array_id.into(), agg_fn_id.map(|id| id.into()));
134+
self.kernels.rcu(move |registry| {
135+
let mut existing = registry.as_ref().clone();
136+
existing.insert(id, kernel);
137+
existing
138+
});
131139
}
132140
}
133141

0 commit comments

Comments
 (0)