1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Measurable entry points into work this crate does not otherwise expose.
//!
//! Benches in this workspace drive their crate's public API. Two do not: this
//! module, and `spate-coordination`'s.
//!
//! This crate's public entry point is [`S3Source`](crate::S3Source), which is
//! asynchronous and driven by object-store I/O. Both properties stop an
//! instruction count being deterministic: under a runtime the number becomes
//! a function of how the scheduler interleaved polls. Packing, split identity
//! and record framing are pure, synchronous, on the per-object path and so
//! countable, but reaching them means reaching past the async surface.
//!
//! The rules a future seam has to honor:
//!
//! - It is behind the off-by-default `testing` feature and `#[doc(hidden)]`,
//! so it is not part of this crate's semver surface and no consumer of the
//! `spate` facade can see it.
//! - It exports **functions and the aliases they need, never this crate's own
//! types**. `ObjectFramer`, `ObjectEntry` and the rest stay private and free
//! to change; only the shape of the work is fixed. `MakeFramer` is an alias
//! over `std` and `spate-core` types, which a caller must be able to name to
//! supply a framer at all.
//! - Each function is one whole unit of the work a stage does (a plan, an
//! object run) rather than one internal call. Attribution below that level
//! comes from the callgrind profile the bench already writes.
use crateCompression;
use crateObjectEntry;
use crate;
use crate;
use SplitId;
use RecordFramer;
use black_box;
use io;
use Arc;
/// Builds a fresh record framer, as the source does per object.
pub type MakeFramer = ;
/// Pack a listing into splits, mint each split's id, and encode each
/// descriptor: the whole of what the leader's planner does with a listing,
/// once per plan.
///
/// `objects` is `(key, size_bytes, etag)` **sorted by key**, which is the
/// order `list_all` hands the planner; packing preserves listing order, so
/// feeding it anything else measures a arrangement production never produces.
/// Taken by value so the keys move into the entries rather than being cloned
/// inside the measured region.
///
/// The three stages are one function because the planner does them as one
/// pass per split and a change to any of them moves the others: the id
/// digests the member keys and ETags, and the descriptor serializes the same
/// members immediately afterwards. Splitting them would measure the parts
/// while missing the per-split loop that carries all three, and the
/// serialization is the term most likely to dominate.
///
/// # Panics
///
/// If a packed bin is empty, which `pack` cannot produce, or if a descriptor
/// fails to encode. Neither is reachable from a well-formed listing; both are
/// asserted rather than propagated because a bench has no policy to apply.
/// Frame a run of objects into records through one framer, returning how
/// many records they produced in total.
///
/// Mirrors the lane, which builds a single `ObjectFramer` and cycles
/// `begin_object`/`finish_object` over the members of its split, so a run of
/// several objects here measures the per-object codec resolution and state
/// reset a multi-member split pays, not the cost of constructing a framer
/// per object. One object is a one-element slice.
///
/// Each object is `(key, chunks)`: the key because the codec is resolved from
/// it per object, and the chunks already split the way a fetcher would
/// deliver them, already compressed if `compression` says so, since
/// compressing here would count the compressor rather than the decompressor.
///
/// Entering an object part-way through needs no parameter: the framer's
/// contract is that the record sequence is a pure function of the bytes it is
/// given, so a mid-object entry is a chunk list that starts at an offset.
///
/// # Errors
///
/// Whatever the decompressor or the framer reports: a truncated stream, a
/// corrupt frame, or a record over the framer's cap.