pub enum PgMemoryContexts {
Show 13 variants
CurrentMemoryContext,
TopMemoryContext,
PortalContext,
ErrorContext,
PostmasterContext,
CacheMemoryContext,
MessageContext,
TopTransactionContext,
CurTransactionContext,
For(MemoryContext),
Owned(OwnedMemoryContext),
Of(OwnerMemoryContext),
Transient {
parent: MemoryContext,
name: &'static str,
min_context_size: u32,
initial_block_size: u32,
max_block_size: u32,
},
}Expand description
An Enumeration of Postgres top-level MemoryContexts. Each have their own use and “lifetimes” as defined by Postgres’ memory management model.
It’s possible to deference any one of these (except Transient) via the ::value() method if
it’s necessary to pass the raw pointer to a Postgres function.
Additionally, the ::switch_to() function, which takes a closure as its argument, executes the
closure within that MemoryContext
Variants§
CurrentMemoryContext
Because it would be too much notational overhead to always pass an appropriate memory context to called routines, there always exists the notion of the current memory context CurrentMemoryContext. Without it, for example, the copyObject routines would need to be passed a context, as would function execution routines that return a pass-by-reference datatype. Similarly for routines that temporarily allocate space internally, but don’t return it to their caller? We certainly don’t want to clutter every call in the system with “here is a context to use for any temporary memory allocation you might want to do”.
The upshot of that reasoning, though, is that CurrentMemoryContext should generally point at a short-lifespan context if at all possible. During query execution it usually points to a context that gets reset after each tuple. Only in very circumscribed code should it ever point at a context having greater than transaction lifespan, since doing so risks permanent memory leaks.
TopMemoryContext
this is the actual top level of the context tree; every other context is a direct or indirect child of this one. Allocating here is essentially the same as “malloc”, because this context will never be reset or deleted. This is for stuff that should live forever, or for stuff that the controlling module will take care of deleting at the appropriate time. An example is fd.c’s tables of open files. Avoid allocating stuff here unless really necessary, and especially avoid running with CurrentMemoryContext pointing here.
PortalContext
this is not actually a separate context, but a global variable pointing to the per-portal context of the currently active execution portal. This can be used if it’s necessary to allocate storage that will live just as long as the execution of the current portal requires.
ErrorContext
this permanent context is switched into for error recovery processing, and then reset on completion of recovery. We arrange to have a few KB of memory available in it at all times. In this way, we can ensure that some memory is available for error recovery even if the backend has run out of memory otherwise. This allows out-of-memory to be treated as a normal ERROR condition, not a FATAL error.
PostmasterContext
this is the postmaster’s normal working context. After a backend is spawned, it can delete PostmasterContext to free its copy of memory the postmaster was using that it doesn’t need. Note that in non-EXEC_BACKEND builds, the postmaster’s copy of pg_hba.conf and pg_ident.conf data is used directly during authentication in backend processes; so backends can’t delete PostmasterContext until that’s done. (The postmaster has only TopMemoryContext, PostmasterContext, and ErrorContext — the remaining top-level contexts are set up in each backend during startup.)
CacheMemoryContext
permanent storage for relcache, catcache, and related modules. This will never be reset or deleted, either, so it’s not truly necessary to distinguish it from TopMemoryContext. But it seems worthwhile to maintain the distinction for debugging purposes. (Note: CacheMemoryContext has child contexts with shorter lifespans. For example, a child context is the best place to keep the subsidiary storage associated with a relcache entry; that way we can free rule parsetrees and so forth easily, without having to depend on constructing a reliable version of freeObject().)
MessageContext
this context holds the current command message from the frontend, as well as any derived storage that need only live as long as the current message (for example, in simple-Query mode the parse and plan trees can live here). This context will be reset, and any children deleted, at the top of each cycle of the outer loop of PostgresMain. This is kept separate from per-transaction and per-portal contexts because a query string might need to live either a longer or shorter time than any single transaction or portal.
TopTransactionContext
this holds everything that lives until end of the top-level transaction. This context will be reset, and all its children deleted, at conclusion of each top-level transaction cycle. In most cases you don’t want to allocate stuff directly here, but in CurTransactionContext; what does belong here is control information that exists explicitly to manage status across multiple subtransactions. Note: this context is NOT cleared immediately upon error; its contents will survive until the transaction block is exited by COMMIT/ROLLBACK.
CurTransactionContext
this holds data that has to survive until the end of the current transaction, and in particular will be needed at top-level transaction commit. When we are in a top-level transaction this is the same as TopTransactionContext, but in subtransactions it points to a child context. It is important to understand that if a subtransaction aborts, its CurTransactionContext is thrown away after finishing the abort processing; but a committed subtransaction’s CurTransactionContext is kept until top-level commit (unless of course one of the intermediate levels of subtransaction aborts). This ensures that we do not keep data from a failed subtransaction longer than necessary. Because of this behavior, you must be careful to clean up properly during subtransaction abort — the subtransaction’s state must be delinked from any pointers or lists kept in upper transactions, or you will have dangling pointers leading to a crash at top-level commit. An example of data kept here is pending NOTIFY messages, which are sent at top-level commit, but only if the generating subtransaction did not abort.
For(MemoryContext)
This represents a MemoryContext that was likely created via pg_sys::AllocSetContextCreateExtended.
That could be a MemoryContext you created yourself, or it could be one given to you from
Postgres. For example, the TupleTableSlot struct has a field referencing the MemoryContext
in which slots are allocated.
Owned(OwnedMemoryContext)
A MemoryContext owned by Rust that will be freed when when Dropped
Of(OwnerMemoryContext)
Use the MemoryContext in which the specified pointer was allocated.
It’s incredibly important that the specified pointer be one actually allocated by Postgres’ memory management system. Otherwise, it’s undefined behavior and will absolutely crash Postgres
Transient
Create a temporary MemoryContext for use with ::switch_to(). It gets deleted as soon
as ::switch_to() exits.
Trying to use this context through [::value{}] will result in a panic!().
Implementations§
Source§impl PgMemoryContexts
impl PgMemoryContexts
Sourcepub fn new(name: &str) -> PgMemoryContexts
pub fn new(name: &str) -> PgMemoryContexts
Create a new PgMemoryContext::Owned
Sourcepub unsafe fn of(ptr: void_mut_ptr) -> Option<PgMemoryContexts>
pub unsafe fn of(ptr: void_mut_ptr) -> Option<PgMemoryContexts>
Create a PgMemoryContexts::Of variant that wraps the pg_sys::MemoryContext that owns
the specified pointer.
Note that the specified pointer must be allocated by Postgres, via pg_sys::palloc or
similar functions.
Returns Option::None if the specified pointer is null.
§Safety
This function is incredibly unsafe. If the specified pointer is not one originally allocated by Postgres, there is absolutely no telling what will be returned.
Furthermore, users of this function’s return value have no choice but to assume the returned
PgMemoryContexts::Of variant represents a legitimate pg_sys::MemoryContext.
Sourcepub fn value(&self) -> MemoryContext
pub fn value(&self) -> MemoryContext
Retrieve the underlying Postgres *mut MemoryContextData
This works for every type except the ::Transient type.
Sourcepub unsafe fn set_as_current(&mut self) -> PgMemoryContexts
pub unsafe fn set_as_current(&mut self) -> PgMemoryContexts
Set this MemoryContext as the CurrentMemoryContext, returning whatever CurrentMemoryContext` is
Sourcepub unsafe fn reset(&mut self)
pub unsafe fn reset(&mut self)
Release all space allocated within a context (ie, free the memory) and delete all its descendant contexts (but not the context itself).
§Safety
This function is unsafe as it can easily lead to use-after-free of Postgres allocated memory:
use pgrx::memcxt::PgMemoryContexts;
struct Thing(Option<String>);
let mut thing = unsafe {
// SAFETY: CurrentMemoryContext is always valid and Thing can be allocated as a zero'd struct
PgMemoryContexts::CurrentMemoryContext.palloc0_struct::<Thing>()
};
let mut thing = unsafe {
// SAFETY: We just allocated it, so it must be a valid Thing
thing.as_mut().unwrap()
};
thing.0 = Some("hello, world".into());
unsafe {
// SAFETY: We promise not to use anything allocated by CurrentMemoryContext prior to
// this call to reset(), specifically `thing`.
PgMemoryContexts::CurrentMemoryContext.reset();
}
assert_eq!(thing.0, Some("hello, world".into())) // we lied! UAF happens hereSourcepub unsafe fn parent(&self) -> Option<PgMemoryContexts>
pub unsafe fn parent(&self) -> Option<PgMemoryContexts>
Returns parent memory context if any
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
Sourcepub unsafe fn switch_to<R, F: FnOnce(&mut PgMemoryContexts) -> R>(
&mut self,
f: F,
) -> R
pub unsafe fn switch_to<R, F: FnOnce(&mut PgMemoryContexts) -> R>( &mut self, f: F, ) -> R
Run the specified function “within” the MemoryContext represented by this enum.
The important implementation detail is that Postgres’ CurrentMemoryContext is changed
to be this context, the function is run so that all Postgres memory allocations happen
within that context, and then CurrentMemoryContext is restored to what it was before
we started.
§Examples
use pgrx::prelude::*;
use pgrx::PgMemoryContexts;
pub fn do_something() -> pg_sys::ItemPointer {
unsafe {
// SAFETY: We know for a fact that `PgMemoryContexts::TopTransactionContext` is always valid
PgMemoryContexts::TopTransactionContext.switch_to(|context| {
// allocate a new ItemPointerData, but inside the TopTransactionContext
let tid = PgBox::<pg_sys::ItemPointerData>::alloc();
// do something with the tid and then return it.
// Note that it stays allocated here in the TopTransactionContext
tid.into_pg()
})
}
}§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn pstrdup(&self, s: &str) -> *mut c_char
pub unsafe fn pstrdup(&self, s: &str) -> *mut c_char
Duplicate a Rust &str into a Postgres-allocated “char *”
§Examples
use pgrx::PgMemoryContexts;
// SAFETY: `CurrentMemoryContext` is always valid, and we promise not to use `copy` after
// `CurrentMemoryContext` has been free'd.
let copy = unsafe { PgMemoryContexts::CurrentMemoryContext.pstrdup("make a copy of this") };§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn copy_ptr_into<T>(&mut self, src: *mut T, len: usize) -> *mut T
pub unsafe fn copy_ptr_into<T>(&mut self, src: *mut T, len: usize) -> *mut T
Copies len bytes, starting at src into this memory context and
returns a raw *mut T pointer to the newly allocated location
§Panics
This function will panic if src is a null pointer.
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn palloc(&mut self, len: usize) -> *mut c_void
pub unsafe fn palloc(&mut self, len: usize) -> *mut c_void
Allocate memory in this context, which will be free’d whenever Postgres deletes this MemoryContext
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn palloc_struct<T>(&mut self) -> *mut T
pub unsafe fn palloc_struct<T>(&mut self) -> *mut T
Allocate a struct in this memory context, returning a pointer to it. The memory will be uninitialized and will be freed whenever Postgres deletes this MemoryContext.
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn palloc0_struct<T>(&mut self) -> *mut T
pub unsafe fn palloc0_struct<T>(&mut self) -> *mut T
Allocate a struct in this memory context, returning a pointer to it. The memory will be zeroed and will be freed whenever Postgres deletes this MemoryContext.
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn palloc_slice<'a, T>(&mut self, len: usize) -> &'a mut [T]
pub unsafe fn palloc_slice<'a, T>(&mut self, len: usize) -> &'a mut [T]
Allocate a slice in this context, which will be free’d whenever Postgres deletes this MemoryContext
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn palloc0_slice<'a, T>(&mut self, len: usize) -> &'a mut [T]
pub unsafe fn palloc0_slice<'a, T>(&mut self, len: usize) -> &'a mut [T]
Allocate a slice in this context, where the memory is zero’d, which will be free’d whenever Postgres deletes this MemoryContext
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub unsafe fn palloc0(&mut self, len: usize) -> *mut c_void
pub unsafe fn palloc0(&mut self, len: usize) -> *mut c_void
Allocate memory in this context, which will be free’d whenever Postgres deletes this MemoryContext
The allocated memory is zero’d
§Safety
This function is unsafe because we cannot ensure that any of the PgMemoryContexts variants,
specifically those with payloads, actually represent valid Postgres pg_sys::MemoryContextData
pointers.
We also cannot ensure that the result of this function will stay allocated as long as Rust’s borrow checker thinks it will.
Sourcepub fn leak_and_drop_on_delete<T>(&mut self, v: T) -> *mut T
pub fn leak_and_drop_on_delete<T>(&mut self, v: T) -> *mut T
Consumes an instance of T and leaks it. Whenever Postgres deletes
this MemoryContext, the original instance of T will be resurrected and its impl Drop
will be called.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for PgMemoryContexts
impl RefUnwindSafe for PgMemoryContexts
impl !Send for PgMemoryContexts
impl !Sync for PgMemoryContexts
impl Unpin for PgMemoryContexts
impl UnwindSafe for PgMemoryContexts
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.