> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arupa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# KV 存储

> 在服务中使用内核共享的内存键值存储。

内核为所有正在运行的服务提供一个共享的键值存储。服务可以用它保存一些必须通过内核读取或更新的小型状态，例如缓存值、服务状态，或与其他服务共享的数据。

KV 中的值是原始字节。内核不会为它们指定数据格式，因此您可以将某个值编码为 JSON、文本、二进制结构，或您的服务所理解的任何其他格式。

## 存储模型

该存储采用两级结构：

```text theme={null}
命名空间 → 键 → 字节值
```

例如：

```text theme={null}
命名空间: preferences
键:      theme
值:      dark
```

KV 存储属于内核，而不属于某个具体的服务实例。所有连接到同一个内核的服务都使用同一个存储。服务命名空间只是一种组织上的约定，并不是权限边界。在当前实现中，除非某个命名空间是只读的，否则一个服务可以读写另一个服务的命名空间。

按照约定，请使用您服务专属的命名空间，通常从服务名称派生而来。如果多个服务有意共享同一个命名空间，请为它们约定好的键名和值格式编写文档。

## 操作

这些操作由[协议](./protocol)中描述的 Host 契约定义。

### 读取一个值

读取请求包含：

| 字段          | 类型       | 含义         |
| ----------- | -------- | ---------- |
| `namespace` | `string` | 包含该键的命名空间。 |
| `key`       | `string` | 要读取的键。     |

响应包含一个 `found` 布尔值和一个 `value` 字节序列。键不存在并不是一种错误：`found` 为 `false`，且不返回值。

读取一个值不会创建其命名空间或键。

### 写入一个值

写入请求包含相同的 `namespace` 和 `key` 字段，此外还有：

| 字段      | 类型      | 含义       |
| ------- | ------- | -------- |
| `value` | `bytes` | 要存储的原始值。 |

写入一个已存在的键会替换其值。当写入被拒绝时（例如该命名空间是只读的），该操作会返回一个错误字符串。

### 删除一个值

删除请求包含 `namespace` 和 `key`。删除一个已存在的键会移除其值；删除一个不存在的键会成功执行，且不会改变该存储。

当删除被拒绝时（包括尝试从只读命名空间中删除），该操作会返回一个错误字符串。

### 列出键

列表请求包含一个 `namespace` 字段：

* 当 `namespace` 非空时，响应包含该命名空间中当前存在的键。
* 当 `namespace` 为空时，响应包含存储中当前存在的所有命名空间的名称。

返回的名称由内核排序。列出操作不会返回值。

## 生命周期与持久性

内核在创建服务管理器时创建该 KV 存储。该存储位于内存中：

* 停止或重启一个服务不会清除其 KV 值；
* 加载同一服务的新版本不会清除其 KV 值；以及
* 重启内核会创建一个新的空存储，并清除所有值。

因此 KV 并不是一个持久化数据库。如果数据必须在内核重启后依然存在，请将其持久化到别处，并将 KV 视为运行时状态或共享缓存。

## 并发与值的所有权

内核会对每一次 KV 操作进行同步。当多个服务并发调用时，读取、写入、删除和列出操作都是安全的。

不存在事务或比较并交换（compare-and-swap）操作。类似"读取、修改、写入"这样的一系列操作，相对于另一个服务而言并不是原子的。如果多个服务更新同一个键，请协调好所有权，或者设计好值的结构，使丢失更新不会破坏应用状态。

内核在存储和读取字节值时都会进行拷贝。在写入之后修改一个字节缓冲区不会改变已存储的值，修改一个返回的缓冲区也不会改变存储中的值。

## `sys` 命名空间

`sys` 是一个由内核管理的只读命名空间。服务可以读取和列出它，但通过服务的 host 边界进行的写入和删除都会返回错误。

内核使用该命名空间保存主机管理的状态，包括服务注册表信息——例如，`sys/service/catalog/<name>` 用于保存扫描到的包元数据，`sys/service/<instance-id>` 用于保存某个运行实例已注册的路由和传输。请不要写入 `sys`，也不要依赖未在文档中说明的系统键，除非内核文档明确定义了它们。

## 后端行为

WASM 和 gRPC 服务使用相同的 KV 契约：

* WASM 服务通过生成的 host 绑定访问该存储；以及
* gRPC 服务通过内核的 host 回调通道访问该存储。

两种运行时类型的存储语义是相同的。运行时改变的是请求跨越服务边界的方式，而不是内核存储或返回值的方式。`static` 服务没有代码，永远不会自己调用这些操作。

## 推荐用法

请使用可预测的命名空间和键方案：

```text theme={null}
命名空间: my-service
键:
  config/theme
  cache/user/<id>
  state/last-sync
```

请保持值足够小以适应调用路径，并在其他组件使用之前就定义好其编码方式。在解码某个值之前先检查 `found` 结果，处理好写入和删除的错误，并且不要把一次成功的写入当作持久化保证。
