---
title: "Session and segment layout"
description: "How AerospikeSessionService maps ADK sessions to session rows and segment records."
---

# Session and segment layout

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

The [overview](https://aerospike.com/docs/develop/adk-atomic-session-append) describes a coordinator agent whose sub-agents all write to one session. The demo you run on the next pages is a simplified version of that scenario: a single Python script, `atomic-session-append-demo.py`, that calls `append_event` on one session in two phases.

| Phase | What the script does | What you verify |
| :-- | :-- | :-- |
| Sequential | Five appends, each with a `state_delta` that updates tenant, locale, and turn counter | State merges correctly after every turn |
| Concurrent | 64 async workers each issue 1,000 appends on the same session | Event count stays exact with no duplicates or gaps under parallel writes |

The script does not start real sub-agents. The concurrent phase simulates many workers appending at once, the way sub-agents append in production.

Before you run it, this page explains how `AerospikeSessionService` stores that one session in Aerospike so both phases stay safe.

## How one session maps to Aerospike records

`AerospikeSessionService` stores one ADK session as two kinds of Aerospike records.

The _session row_ is a small Aerospike record (called a _row_ here because it holds session metadata like a row in a session table). It holds session-scoped state and tracks which segment is currently active.

_Segment records_ hold events in chronological order. Events append to the active segment until it reaches Aerospike’s record size limit, then the service creates the next segment and updates the session row.

The demo script only calls `append_event` and `get_session`. It never creates segments or manages rollover itself. `AerospikeSessionService` handles that behind those ADK APIs.

## What each record holds

| Record | What is stored |
| :-- | :-- |
| Session row | Session-scoped state (merged from each append’s `state_delta`), the active segment index, and a last-updated timestamp |
| Segment record | A chronological batch of events (user messages, assistant replies, and tool results) |

_Merged state_ means the session row holds the latest value for each session-scoped key. When an append includes `state_delta: { "turn": 3 }`, the service writes the event to the active segment and updates `turn` on the session row in the same round trip.

Here is a simplified view after three sequential appends:

```text
Session row

  state: { turn: 2 }

  cur_segment: 0

Segment 0

  events:

    [0] assistant reply 0

    [1] assistant reply 1

    [2] assistant reply 2
```

The demo prints the active segment index as `cur_segment`. In Aerospike, this value is stored in the `cur` bin on the session row.

App- and user-scoped keys from `state_delta` (for example, `app:tenant`, `user:locale`) are stored on separate Aerospike records keyed by scope, not on the session row shown here. The sequential phase of the demo exercises all three scopes.

In Aerospike, all records for one session live in the `adk_sessions` set.

-   Session row key: `app_name`, `user_id`, and `session_id`
-   Segment record key: the same fields plus a `:g:NNNNNNNN` suffix (for example, `demo-app:user-1:session-1:g:00000001`)

Segment 0 holds the earliest events, segment 1 holds the next batch, and higher-numbered segments hold later batches.

## How appends work

Every `append_event` call adds one event to the active segment. The call is optional about state: you can include a `state_delta` when the turn also updates session metadata.

A `state_delta` is a dictionary of key-value changes passed through `EventActions` on the `Event` object. Keys without a prefix (for example, `turn`) update session-scoped state on the session row. Keys with an `app:` or `user:` prefix update app-wide or user-wide state on separate Aerospike records.

| Demo phase | Includes `state_delta`? | Why |
| :-- | :-- | :-- |
| Sequential | Yes, on every append | Shows how tenant, locale, and turn counter merge after each turn |
| Concurrent | No | The sequential phase proves state merging. The concurrent phase then tests append correctness under load without also updating session state. |

When you run the demo, `session_state_keys` in the output counts session-scoped keys on the session row. The concurrent phase omits `state_delta` on purpose, the way production workers often append turns without updating session metadata on every write. Session state was set in the sequential phase, so that count stays at 1 while event count grows.

When a `state_delta` is present, the service writes the event and applies the state changes in one round trip. An event never lands without its state update, and state never updates without the event.

### Idempotent retries

Each event gets a stable map key from `event.id` and `event.timestamp`. If a network retry re-appends the same `Event` (same `id` and `timestamp`), the service updates the existing slot. No second copy is added. That is what makes appends idempotent.

### Segment rollover

As events accumulate, the active segment grows. When it reaches Aerospike’s record size limit, the service creates the next segment, moves new appends there, and updates the `cur` bin on the session row (printed as `cur_segment` in the demo). After five sequential appends, `cur_segment` stays at 0. Under 64,000 concurrent appends, it increases as segments fill.

On the next page, you run the demo so you can verify this layout under sequential and concurrent appends.

::: undefined
-   I understand the difference between the session row and segment records.
-   I know why retried appends cannot create duplicate events.
:::

[Previous  
Install and connect](https://aerospike.com/docs/develop/adk-atomic-session-append/step/1/part/1/install-and-connect) [Next  
Run sequential appends](https://aerospike.com/docs/develop/adk-atomic-session-append/step/3/part/0/sequential-appends)