Brazenle commited on
Commit
2c76aad
·
verified ·
1 Parent(s): 079b631

Add accepted KVC1 reference implementation

Browse files
Files changed (1) hide show
  1. reference/kvcache.py +194 -0
reference/kvcache.py ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Portable, fail-closed raw KV-cache container.
2
+
3
+ KVC1 stores already-materialized key/value tensor bytes plus the exact model,
4
+ tokenizer, tensor geometry, RoPE, dtype, layout, and sequence-position identity
5
+ needed to decide whether a runtime may safely reuse them. Cross-architecture
6
+ translation is deliberately out of scope for this byte container.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import hashlib
13
+ import hmac
14
+ import json
15
+ import os
16
+ from pathlib import Path
17
+ import struct
18
+ import tempfile
19
+ from typing import Any, Mapping
20
+
21
+
22
+ MAGIC = b"KVC1"
23
+ PREFIX = struct.Struct(">4sIQ32s")
24
+ REQUIRED_FIELDS = {
25
+ "model_revision",
26
+ "tokenizer_sha256",
27
+ "rope_theta",
28
+ "layers",
29
+ "kv_heads",
30
+ "head_dim",
31
+ "dtype",
32
+ "layout",
33
+ "sequence_start",
34
+ "sequence_length",
35
+ }
36
+ ALLOWED_DTYPES = {"f16", "bf16", "f32", "i8", "u8"}
37
+ ALLOWED_LAYOUTS = {"layer-major-k-then-v"}
38
+ MAX_METADATA_BYTES = 1_048_576
39
+
40
+
41
+ class CacheFormatError(ValueError):
42
+ """The container is malformed, incomplete, corrupt, or unsupported."""
43
+
44
+
45
+ class CacheCompatibilityError(ValueError):
46
+ """The container is valid but does not match the requested runtime."""
47
+
48
+
49
+ def _plain_dict(metadata: Mapping[str, Any]) -> dict[str, Any]:
50
+ if not isinstance(metadata, Mapping):
51
+ raise CacheFormatError("metadata must be a mapping")
52
+ value = dict(metadata)
53
+ missing = REQUIRED_FIELDS.difference(value)
54
+ extra = set(value).difference(REQUIRED_FIELDS)
55
+ if missing or extra:
56
+ raise CacheFormatError(f"metadata fields differ: missing={sorted(missing)}, extra={sorted(extra)}")
57
+ if not isinstance(value["model_revision"], str) or "@" not in value["model_revision"]:
58
+ raise CacheFormatError("model_revision must identify an immutable revision")
59
+ tokenizer_hash = value["tokenizer_sha256"]
60
+ if not isinstance(tokenizer_hash, str) or len(tokenizer_hash) != 64:
61
+ raise CacheFormatError("tokenizer_sha256 must contain 64 hexadecimal characters")
62
+ try:
63
+ int(tokenizer_hash, 16)
64
+ except ValueError as error:
65
+ raise CacheFormatError("tokenizer_sha256 is not hexadecimal") from error
66
+ if not isinstance(value["rope_theta"], (int, float)) or isinstance(value["rope_theta"], bool) or value["rope_theta"] <= 0:
67
+ raise CacheFormatError("rope_theta must be positive")
68
+ for field in ("layers", "kv_heads", "head_dim", "sequence_length"):
69
+ if not isinstance(value[field], int) or isinstance(value[field], bool) or value[field] <= 0:
70
+ raise CacheFormatError(f"{field} must be a positive integer")
71
+ if not isinstance(value["sequence_start"], int) or isinstance(value["sequence_start"], bool) or value["sequence_start"] < 0:
72
+ raise CacheFormatError("sequence_start must be a non-negative integer")
73
+ if value["dtype"] not in ALLOWED_DTYPES:
74
+ raise CacheFormatError("unsupported dtype")
75
+ if value["layout"] not in ALLOWED_LAYOUTS:
76
+ raise CacheFormatError("unsupported layout")
77
+ return value
78
+
79
+
80
+ def _metadata_bytes(metadata: Mapping[str, Any]) -> bytes:
81
+ try:
82
+ encoded = json.dumps(_plain_dict(metadata), sort_keys=True, separators=(",", ":"), allow_nan=False).encode("utf-8")
83
+ except (TypeError, ValueError) as error:
84
+ if isinstance(error, CacheFormatError):
85
+ raise
86
+ raise CacheFormatError("metadata is not canonical JSON") from error
87
+ if len(encoded) > MAX_METADATA_BYTES:
88
+ raise CacheFormatError("metadata is too large")
89
+ return encoded
90
+
91
+
92
+ def write_cache(path: str | os.PathLike[str], metadata: Mapping[str, Any], payload: bytes) -> None:
93
+ """Atomically publish one KVC1 generation."""
94
+ if type(payload) is not bytes:
95
+ raise CacheFormatError("payload must be raw bytes")
96
+ destination = Path(path)
97
+ destination.parent.mkdir(parents=True, exist_ok=True)
98
+ metadata_bytes = _metadata_bytes(metadata)
99
+ digest = hashlib.sha256(payload).digest()
100
+ prefix = PREFIX.pack(MAGIC, len(metadata_bytes), len(payload), digest)
101
+ temporary_name: str | None = None
102
+ try:
103
+ with tempfile.NamedTemporaryFile(
104
+ mode="wb",
105
+ prefix=f".{destination.name}.",
106
+ suffix=".tmp",
107
+ dir=destination.parent,
108
+ delete=False,
109
+ ) as temporary:
110
+ temporary_name = temporary.name
111
+ temporary.write(prefix)
112
+ temporary.write(metadata_bytes)
113
+ temporary.write(payload)
114
+ temporary.flush()
115
+ os.fsync(temporary.fileno())
116
+ os.replace(temporary_name, destination)
117
+ temporary_name = None
118
+ finally:
119
+ if temporary_name is not None:
120
+ try:
121
+ os.unlink(temporary_name)
122
+ except FileNotFoundError:
123
+ pass
124
+
125
+
126
+ def _decode(path: str | os.PathLike[str]) -> tuple[dict[str, Any], bytes, str]:
127
+ try:
128
+ raw = Path(path).read_bytes()
129
+ except OSError as error:
130
+ raise CacheFormatError(f"cache could not be read: {error}") from error
131
+ if len(raw) < PREFIX.size:
132
+ raise CacheFormatError("container is truncated")
133
+ try:
134
+ magic, metadata_length, payload_length, expected_digest = PREFIX.unpack_from(raw)
135
+ except struct.error as error:
136
+ raise CacheFormatError("container prefix is malformed") from error
137
+ if magic != MAGIC:
138
+ raise CacheFormatError("unsupported container magic or version")
139
+ if metadata_length == 0 or metadata_length > MAX_METADATA_BYTES:
140
+ raise CacheFormatError("metadata length is invalid")
141
+ expected_length = PREFIX.size + metadata_length + payload_length
142
+ if len(raw) != expected_length:
143
+ raise CacheFormatError("container length does not match its header")
144
+ metadata_raw = raw[PREFIX.size:PREFIX.size + metadata_length]
145
+ payload = raw[PREFIX.size + metadata_length:]
146
+ try:
147
+ decoded = json.loads(metadata_raw.decode("utf-8"))
148
+ except (UnicodeDecodeError, json.JSONDecodeError) as error:
149
+ raise CacheFormatError("metadata is not valid UTF-8 JSON") from error
150
+ metadata = _plain_dict(decoded)
151
+ if _metadata_bytes(metadata) != metadata_raw:
152
+ raise CacheFormatError("metadata is not in canonical form")
153
+ actual_digest = hashlib.sha256(payload).digest()
154
+ if not hmac.compare_digest(actual_digest, expected_digest):
155
+ raise CacheFormatError("payload checksum mismatch")
156
+ return metadata, payload, actual_digest.hex()
157
+
158
+
159
+ def read_cache(path: str | os.PathLike[str], expected_metadata: Mapping[str, Any] | None = None) -> tuple[dict[str, Any], bytes]:
160
+ metadata, payload, _ = _decode(path)
161
+ if expected_metadata is not None:
162
+ expected = _plain_dict(expected_metadata)
163
+ differences = [field for field in sorted(REQUIRED_FIELDS) if metadata[field] != expected[field]]
164
+ if differences:
165
+ raise CacheCompatibilityError(f"cache is incompatible: {', '.join(differences)}")
166
+ return metadata, payload
167
+
168
+
169
+ def inspect_cache(path: str | os.PathLike[str]) -> dict[str, Any]:
170
+ metadata, payload, digest = _decode(path)
171
+ return {
172
+ "format": "KVC1",
173
+ "metadata": metadata,
174
+ "payload_bytes": len(payload),
175
+ "payload_sha256": digest,
176
+ }
177
+
178
+
179
+ def main() -> int:
180
+ parser = argparse.ArgumentParser(description="Inspect a portable raw KV-cache container.")
181
+ subparsers = parser.add_subparsers(dest="command", required=True)
182
+ inspect_parser = subparsers.add_parser("inspect")
183
+ inspect_parser.add_argument("path")
184
+ args = parser.parse_args()
185
+ if args.command == "inspect":
186
+ try:
187
+ print(json.dumps(inspect_cache(args.path), sort_keys=True))
188
+ except (CacheFormatError, CacheCompatibilityError) as error:
189
+ parser.exit(1, f"kvcache: {error}\n")
190
+ return 0
191
+
192
+
193
+ if __name__ == "__main__":
194
+ raise SystemExit(main())