///|
let stored_field_block_size : Int = 32
///|
pub(all) struct StoredFieldBlock {
first_doc : Int
doc_count : Int
uncompressed_length : Int
compressed : Bytes
} derive(Eq, @debug.Debug)
///|
pub struct StoredFieldsReader {
blocks : ReadOnlyArray[StoredFieldBlock]
document_count : Int
}
///|
fn write_stored_value(buffer : @buffer.Buffer, value : FieldValue) -> Unit {
match value {
@core.Text(value) => {
buffer.write_byte(b'\x00')
write_string(buffer, value)
}
@core.Keyword(value) => {
buffer.write_byte(b'\x01')
write_string(buffer, value)
}
@core.I64(value) => {
buffer.write_byte(b'\x02')
write_int64(buffer, value)
}
@core.U64(value) => {
buffer.write_byte(b'\x03')
write_uint64(buffer, value)
}
@core.F64(value) => {
buffer.write_byte(b'\x04')
write_double(buffer, value)
}
@core.Bool(value) => {
buffer.write_byte(b'\x05')
write_bool(buffer, value)
}
@core.Date(value) => {
buffer.write_byte(b'\x06')
write_int64(buffer, value)
}
@core.Bytes(value) => {
buffer.write_byte(b'\x07')
buffer.write_int_be(value.length())
buffer.write_bytes(value[:])
}
}
}
///|
fn read_stored_value(
decoder : SegmentDecoder,
) -> FieldValue raise PersistenceError {
match decoder.read_byte("stored value type") {
b'\x00' => @core.Text(decoder.read_string("stored text value"))
b'\x01' => @core.Keyword(decoder.read_string("stored keyword value"))
b'\x02' => @core.I64(decoder.read_int64("stored i64 value"))
b'\x03' => @core.U64(decoder.read_uint64("stored u64 value"))
b'\x04' => @core.F64(decoder.read_double("stored f64 value"))
b'\x05' => @core.Bool(decoder.read_bool("stored bool value"))
b'\x06' => @core.Date(decoder.read_int64("stored date value"))
b'\x07' => @core.Bytes(decoder.read_bytes("stored bytes value"))
_ => raise PersistenceError::InvalidFormat("invalid stored value type")
}
}
///|
fn encode_stored_documents(documents : Array[StoredDocument]) -> Bytes {
let buffer = @buffer.Buffer()
buffer.write_int_be(documents.length())
for document in documents {
buffer.write_int_be(document.field_ids.length())
for index in 0.. Bytes {
let output = @buffer.Buffer(size_hint=input.length())
let mut cursor = 0
while cursor < input.length() {
let mut run_length = 1
while cursor + run_length < input.length() &&
input[cursor + run_length] == input[cursor] &&
run_length < 128 {
run_length += 1
}
if run_length >= 4 {
output.write_byte((127 + run_length).to_byte())
output.write_byte(input[cursor])
cursor += run_length
continue
}
let literal_start = cursor
cursor += run_length
while cursor < input.length() && cursor - literal_start < 128 {
let mut next_run = 1
while cursor + next_run < input.length() &&
input[cursor + next_run] == input[cursor] &&
next_run < 128 {
next_run += 1
}
if next_run >= 4 {
break
}
cursor += next_run
}
let literal_length = cursor - literal_start
output.write_byte((literal_length - 1).to_byte())
output.write_bytes(input[literal_start:cursor])
}
output.to_bytes()
}
///|
fn rle_decompress(
input : Bytes,
expected_length : Int,
) -> Bytes raise PersistenceError {
let output = @buffer.Buffer(size_hint=expected_length)
let mut cursor = 0
while cursor < input.length() {
let control = input[cursor].to_int()
cursor += 1
if control < 128 {
let length = control + 1
guard cursor + length <= input.length() else {
raise PersistenceError::InvalidFormat("truncated stored literal")
}
output.write_bytes(input[cursor:cursor + length])
cursor += length
} else {
let length = control - 127
guard cursor < input.length() else {
raise PersistenceError::InvalidFormat("truncated stored run")
}
let value = input[cursor]
cursor += 1
for _ in 0.. ReadOnlyArray[StoredDocument] raise PersistenceError {
let decoder = SegmentDecoder::new(bytes)
let count = decoder.read_count("stored block document count")
guard count == expected_count else {
raise PersistenceError::InvalidFormat(
"stored block document count mismatch",
)
}
let documents : Array[StoredDocument] = []
for _ in 0.. ReadOnlyArray[StoredDocument] raise PersistenceError {
decode_stored_documents(
rle_decompress(block.compressed, block.uncompressed_length),
block.doc_count,
)
}
///|
fn build_stored_field_blocks(
documents : Array[StoredDocument],
) -> ReadOnlyArray[StoredFieldBlock] {
let blocks : Array[StoredFieldBlock] = []
let mut start = 0
while start < documents.length() {
let end = if start + stored_field_block_size < documents.length() {
start + stored_field_block_size
} else {
documents.length()
}
let block_documents : Array[StoredDocument] = []
for index in start.. Unit raise PersistenceError {
let mut next_doc = 0
for block in blocks {
guard block.first_doc == next_doc && block.doc_count > 0 else {
raise PersistenceError::InvalidFormat("invalid stored block range")
}
ignore(stored_block_documents(block))
next_doc += block.doc_count
}
guard next_doc == document_count else {
raise PersistenceError::InvalidFormat("stored block coverage mismatch")
}
}
///|
fn StoredFieldsReader::new(
blocks : ReadOnlyArray[StoredFieldBlock],
document_count : Int,
) -> StoredFieldsReader {
{ blocks, document_count }
}
///|
pub fn StoredFieldsReader::doc(
self : StoredFieldsReader,
doc_id : DocId,
) -> StoredDocument? {
if doc_id.value < 0 || doc_id.value >= self.document_count {
return None
}
let block_index = doc_id.value / stored_field_block_size
guard block_index >= 0 && block_index < self.blocks.length() else {
return None
}
let block = self.blocks[block_index]
let documents = stored_block_documents(block) catch {
error => abort(error.to_string())
}
Some(documents[doc_id.value - block.first_doc])
}
///|
pub fn StoredFieldsReader::compressed_bytes(self : StoredFieldsReader) -> Int {
let mut total = 0
for block in self.blocks {
total += block.compressed.length()
}
total
}
///|
pub fn StoredFieldsReader::block_count(self : StoredFieldsReader) -> Int {
self.blocks.length()
}