liveBook · Manning

Memory pool

As explained in Refactoring to Rust

A memory pool is an allocator that obtains memory from a managed region and releases its allocations together when the pool is destroyed.

A memory pool is an allocator that obtains memory from a managed region and releases all allocations together when the pool is destroyed. NGINX keeps a pool on each request, so temporary response buffers can share the request lifetime without individual cleanup code. section 4.6

Allocating an HTTP response buffer

A response writer uses ngx_pcalloc(request.pool, ...) to allocate an ngx_buf_t and its response bytes. It checks for null pointers, copies the response into the allocated memory, and lets NGINX reclaim both buffers when request handling ends. section 4.6

unsafe fn write_response(
  request: &mut ngx_http_request_t,
  response_body: &str,
  status_code: ngx_uint_t,
) -> Result<(), &'static str> {
  let headers = &mut request.headers_out;

  headers.status = status_code;

  let response_bytes = response_body.as_bytes();
  headers.content_length_n = response_bytes.len() as off_t;

  let rc = ngx_http_send_header(request);  #1
  if rc != 0 {
    return Err("failed to send headers");
  }

  let buf_p =
    ngx_pcalloc(request.pool, std::mem::size_of::<
      ngx_buf_t>() as size_t)  #2
      as *mut ngx_buf_t;
  if buf_p.is_null() {
    return Err("Failed to allocate buffer");
  }

  let buf = &mut (*buf_p);

  buf.set_last_buf(1);  #3
  buf.set_last_in_chain(1);
  buf.set_memory(1);

  let response_buffer =
    ngx_pcalloc(request.pool, response_bytes.len() as size_t);  #4
  if response_buffer.is_null() {
    return Err("Failed to allocate response buffer");
  }

  std::ptr::copy_nonoverlapping(  #5
    response_bytes.as_ptr(),
    response_buffer as *mut u8,
    response_bytes.len(),
  );

  buf.pos = response_buffer as *mut u8;
  buf.last = response_buffer.offset(
    response_bytes.len() as isize) as *mut u8;

  let mut out_chain = ngx_chain_t {
    buf,
    next: std::ptr::null_mut(),
  };

  if ngx_http_output_filter(request, &mut out_chain) != 0 {  #6
    return Err("Failed to perform http output filter chain");
  }

  Ok(())
}

Inspect the request-pool allocations alongside the size_of calculation, null check, buffer initialization, and response-buffer allocation. section 4.6

How Refactoring to Rust covers it

How deep it goes
Explains pool allocation, request-lifetime deallocation, size calculation, null checks, and buffer copying, but not pool internals.
Examples
Demonstrates ngx_pcalloc allocations for ngx_buf_t and response bytes during HTTP response construction.
What you can do after
Apply it via NGINX's ngx_pcalloc to allocate request-scoped buffers and avoid extra cleanup bookkeeping.
How it connects
Connects memory pools with Rust ownership, request lifetimes, NGINX allocators, pointers, and unsafe FFI.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.