Struct sp_runtime::offchain::storage::StorageValueRef
source · pub struct StorageValueRef<'a> { /* private fields */ }
Expand description
An abstraction over local storage value.
Implementations§
source§impl<'a> StorageValueRef<'a>
impl<'a> StorageValueRef<'a>
sourcepub fn persistent(key: &'a [u8]) -> Self
pub fn persistent(key: &'a [u8]) -> Self
Create a new reference to a value in the persistent local storage.
Examples found in repository?
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
pub fn with_lockable(key: &'a [u8], lockable: L) -> Self {
Self { value_ref: StorageValueRef::<'a>::persistent(key), lockable }
}
/// Extend active lock's deadline
fn extend_active_lock(&mut self) -> Result<<L as Lockable>::Deadline, ()> {
let res = self.value_ref.mutate(
|s: Result<Option<L::Deadline>, StorageRetrievalError>| -> Result<<L as Lockable>::Deadline, ()> {
match s {
// lock is present and is still active, extend the lock.
Ok(Some(deadline)) if !<L as Lockable>::has_expired(&deadline) =>
Ok(self.lockable.deadline()),
// other cases
_ => Err(()),
}
});
match res {
Ok(deadline) => Ok(deadline),
Err(MutateStorageError::ConcurrentModification(_)) => Err(()),
Err(MutateStorageError::ValueFunctionFailed(e)) => Err(e),
}
}
/// Internal lock helper to avoid lifetime conflicts.
fn try_lock_inner(
&mut self,
new_deadline: L::Deadline,
) -> Result<(), <L as Lockable>::Deadline> {
let res = self.value_ref.mutate(
|s: Result<Option<L::Deadline>, StorageRetrievalError>|
-> Result<<L as Lockable>::Deadline, <L as Lockable>::Deadline> {
match s {
// no lock set, we can safely acquire it
Ok(None) => Ok(new_deadline),
// write was good, but read failed
Err(_) => Ok(new_deadline),
// lock is set, but it is expired. We can re-acquire it.
Ok(Some(deadline)) if <L as Lockable>::has_expired(&deadline) =>
Ok(new_deadline),
// lock is present and is still active
Ok(Some(deadline)) => Err(deadline),
}
},
);
match res {
Ok(_) => Ok(()),
Err(MutateStorageError::ConcurrentModification(deadline)) => Err(deadline),
Err(MutateStorageError::ValueFunctionFailed(e)) => Err(e),
}
}
/// A single attempt to lock using the storage entry.
///
/// Returns a lock guard on success, otherwise an error containing the
/// `<Self::Lockable>::Deadline` in for the currently active lock
/// by another task `Err(<L as Lockable>::Deadline)`.
pub fn try_lock(&mut self) -> Result<StorageLockGuard<'a, '_, L>, <L as Lockable>::Deadline> {
self.try_lock_inner(self.lockable.deadline())?;
Ok(StorageLockGuard::<'a, '_> { lock: Some(self) })
}
/// Repeated lock attempts until the lock is successfully acquired.
///
/// If one uses `fn forget(..)`, it is highly likely `fn try_lock(..)`
/// is the correct API to use instead of `fn lock(..)`, since that might
/// never unlock in the anticipated span i.e. when used with `BlockAndTime`
/// during a certain block number span.
pub fn lock(&mut self) -> StorageLockGuard<'a, '_, L> {
while let Err(deadline) = self.try_lock_inner(self.lockable.deadline()) {
L::snooze(&deadline);
}
StorageLockGuard::<'a, '_, L> { lock: Some(self) }
}
/// Explicitly unlock the lock.
fn unlock(&mut self) {
self.value_ref.clear();
}
}
/// RAII style guard for a lock.
pub struct StorageLockGuard<'a, 'b, L: Lockable> {
lock: Option<&'b mut StorageLock<'a, L>>,
}
impl<'a, 'b, L: Lockable> StorageLockGuard<'a, 'b, L> {
/// Consume the guard but **do not** unlock the underlying lock.
///
/// Can be used to implement a grace period after doing some
/// heavy computations and sending a transaction to be included
/// on-chain. By forgetting the lock, it will stay locked until
/// its expiration deadline is reached while the off-chain worker
/// can already exit.
pub fn forget(mut self) {
let _ = self.lock.take();
}
/// Extend the lock by guard deadline if it already exists.
///
/// i.e. large sets of items for which it is hard to calculate a
/// meaning full conservative deadline which does not block for a
/// very long time on node termination.
pub fn extend_lock(&mut self) -> Result<<L as Lockable>::Deadline, ()> {
if let Some(ref mut lock) = self.lock {
lock.extend_active_lock()
} else {
Err(())
}
}
}
impl<'a, 'b, L: Lockable> Drop for StorageLockGuard<'a, 'b, L> {
fn drop(&mut self) {
if let Some(lock) = self.lock.take() {
lock.unlock();
}
}
}
impl<'a> StorageLock<'a, Time> {
/// Explicitly create a time based storage lock with a non-default
/// expiration timeout.
pub fn with_deadline(key: &'a [u8], expiration_duration: Duration) -> Self {
Self {
value_ref: StorageValueRef::<'a>::persistent(key),
lockable: Time { expiration_duration },
}
}
}
impl<'a, B> StorageLock<'a, BlockAndTime<B>>
where
B: BlockNumberProvider,
{
/// Explicitly create a time and block number based storage lock with
/// a non-default expiration duration and block number offset.
pub fn with_block_and_time_deadline(
key: &'a [u8],
expiration_block_number_offset: u32,
expiration_duration: Duration,
) -> Self {
Self {
value_ref: StorageValueRef::<'a>::persistent(key),
lockable: BlockAndTime::<B> {
expiration_block_number_offset,
expiration_duration,
_phantom: core::marker::PhantomData,
},
}
}
/// Explicitly create a time and block number based storage lock with
/// the default expiration duration and a non-default block number offset.
pub fn with_block_deadline(key: &'a [u8], expiration_block_number_offset: u32) -> Self {
Self {
value_ref: StorageValueRef::<'a>::persistent(key),
lockable: BlockAndTime::<B> {
expiration_block_number_offset,
expiration_duration: STORAGE_LOCK_DEFAULT_EXPIRY_DURATION,
_phantom: core::marker::PhantomData,
},
}
}
sourcepub fn local(key: &'a [u8]) -> Self
pub fn local(key: &'a [u8]) -> Self
Create a new reference to a value in the fork-aware local storage.
sourcepub fn set(&self, value: &impl Encode)
pub fn set(&self, value: &impl Encode)
Set the value of the storage to encoding of given parameter.
Note that the storage may be accessed by workers running concurrently,
if you happen to write a get-check-set
pattern you should most likely
be using mutate
instead.
sourcepub fn get<T: Decode>(&self) -> Result<Option<T>, StorageRetrievalError>
pub fn get<T: Decode>(&self) -> Result<Option<T>, StorageRetrievalError>
Retrieve & decode the value from storage.
Note that if you want to do some checks based on the value
and write changes after that, you should rather be using mutate
.
Returns the value if stored. Returns an error if the value could not be decoded.
sourcepub fn mutate<T, E, F>(
&self,
mutate_val: F
) -> Result<T, MutateStorageError<T, E>>where
T: Codec,
F: FnOnce(Result<Option<T>, StorageRetrievalError>) -> Result<T, E>,
pub fn mutate<T, E, F>(
&self,
mutate_val: F
) -> Result<T, MutateStorageError<T, E>>where
T: Codec,
F: FnOnce(Result<Option<T>, StorageRetrievalError>) -> Result<T, E>,
Retrieve & decode the current value and set it to a new value atomically.
Function mutate_val
takes as input the current value and should
return a new value that is attempted to be written to storage.
This function returns:
Ok(T)
in case the value has been successfully set.Err(MutateStorageError::ConcurrentModification(T))
in case the value was calculated by the passed closuremutate_val
, but it could not be stored.Err(MutateStorageError::ValueFunctionFailed(_))
in casemutate_val
returns an error.
Examples found in repository?
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
fn extend_active_lock(&mut self) -> Result<<L as Lockable>::Deadline, ()> {
let res = self.value_ref.mutate(
|s: Result<Option<L::Deadline>, StorageRetrievalError>| -> Result<<L as Lockable>::Deadline, ()> {
match s {
// lock is present and is still active, extend the lock.
Ok(Some(deadline)) if !<L as Lockable>::has_expired(&deadline) =>
Ok(self.lockable.deadline()),
// other cases
_ => Err(()),
}
});
match res {
Ok(deadline) => Ok(deadline),
Err(MutateStorageError::ConcurrentModification(_)) => Err(()),
Err(MutateStorageError::ValueFunctionFailed(e)) => Err(e),
}
}
/// Internal lock helper to avoid lifetime conflicts.
fn try_lock_inner(
&mut self,
new_deadline: L::Deadline,
) -> Result<(), <L as Lockable>::Deadline> {
let res = self.value_ref.mutate(
|s: Result<Option<L::Deadline>, StorageRetrievalError>|
-> Result<<L as Lockable>::Deadline, <L as Lockable>::Deadline> {
match s {
// no lock set, we can safely acquire it
Ok(None) => Ok(new_deadline),
// write was good, but read failed
Err(_) => Ok(new_deadline),
// lock is set, but it is expired. We can re-acquire it.
Ok(Some(deadline)) if <L as Lockable>::has_expired(&deadline) =>
Ok(new_deadline),
// lock is present and is still active
Ok(Some(deadline)) => Err(deadline),
}
},
);
match res {
Ok(_) => Ok(()),
Err(MutateStorageError::ConcurrentModification(deadline)) => Err(deadline),
Err(MutateStorageError::ValueFunctionFailed(e)) => Err(e),
}
}
Auto Trait Implementations§
impl<'a> RefUnwindSafe for StorageValueRef<'a>
impl<'a> Send for StorageValueRef<'a>
impl<'a> Sync for StorageValueRef<'a>
impl<'a> Unpin for StorageValueRef<'a>
impl<'a> UnwindSafe for StorageValueRef<'a>
Blanket Implementations§
source§impl<T> CheckedConversion for T
impl<T> CheckedConversion for T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>
fn into_any(self: Box<T, Global>) -> Box<dyn Any + 'static, Global>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any + 'static>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.source§impl<T> Instrument for T
impl<T> Instrument for T
source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T, Outer> IsWrappedBy<Outer> for Twhere
Outer: AsRef<T> + AsMut<T> + From<T>,
T: From<Outer>,
impl<T, Outer> IsWrappedBy<Outer> for Twhere
Outer: AsRef<T> + AsMut<T> + From<T>,
T: From<Outer>,
source§impl<T> SaturatedConversion for T
impl<T> SaturatedConversion for T
source§fn saturated_from<T>(t: T) -> Selfwhere
Self: UniqueSaturatedFrom<T>,
fn saturated_from<T>(t: T) -> Selfwhere
Self: UniqueSaturatedFrom<T>,
source§fn saturated_into<T>(self) -> Twhere
Self: UniqueSaturatedInto<T>,
fn saturated_into<T>(self) -> Twhere
Self: UniqueSaturatedInto<T>,
T
. Read moresource§impl<S, T> UncheckedInto<T> for Swhere
T: UncheckedFrom<S>,
impl<S, T> UncheckedInto<T> for Swhere
T: UncheckedFrom<S>,
source§fn unchecked_into(self) -> T
fn unchecked_into(self) -> T
unchecked_from
.source§impl<T, S> UniqueSaturatedInto<T> for Swhere
T: Bounded,
S: TryInto<T>,
impl<T, S> UniqueSaturatedInto<T> for Swhere
T: Bounded,
S: TryInto<T>,
source§fn unique_saturated_into(self) -> T
fn unique_saturated_into(self) -> T
T
.