use wbase::store_type::StoreType;
use crate::{
transaction_manager::TransactionManager,
txn_key_entry::{LockType, TxnKeyEntries},
txn_key_entry_comparison::TxnKeyEntryComparison,
txn_key_spec::TxnKeySpec,
txn_session::TxnSession,
};
#[derive(Debug, Clone)]
pub struct TxnCommandKeys {
pub store_type: StoreType,
pub key_specs: Vec<TxnKeySpec>,
}
impl TransactionManager {
pub(crate) fn register_key_lock(
key_entries: &mut TxnKeyEntries,
perform_writes: &mut bool,
key: &[u8],
lock_type: LockType,
) {
*perform_writes |= lock_type == LockType::Exclusive;
key_entries.add_key(TxnKeyEntryComparison::key_hash(key), lock_type);
}
pub fn save_key_entry_to_lock(&mut self, key: &[u8], lock_type: LockType) {
Self::register_key_lock(
&mut self.key_entries,
&mut self.perform_writes,
key,
lock_type,
);
if self.cluster_enabled && !self.stored_proc_mode {
self.txn_keys.push(key);
}
}
pub fn lock_keys(&mut self, session: &(impl TxnSession + ?Sized), command_keys: &TxnCommandKeys) {
if command_keys.key_specs.is_empty() {
return;
}
self.add_transaction_store_type(command_keys.store_type);
let arg_count = session.arg_count();
for key_spec in &command_keys.key_specs {
let last_idx = if key_spec.last_idx < 0 {
arg_count as i64 + key_spec.last_idx
} else {
key_spec.last_idx
};
if last_idx < 0 {
continue;
}
let last_idx = (last_idx as usize).min(arg_count.saturating_sub(1));
if key_spec.first_idx > last_idx || key_spec.first_idx >= arg_count {
continue;
}
let lock_type = if key_spec.read_only {
LockType::Shared
} else {
LockType::Exclusive
};
let step = key_spec.step.max(1);
for idx in (key_spec.first_idx..=last_idx).step_by(step) {
let key_bytes = session.get_arg(idx);
self.save_key_entry_to_lock(key_bytes, lock_type);
}
}
}
}