booblik
Wiki

booblik-protocol

Generated page

Model gemma-mtp, commit ef58254ca7be, 2026-08-16, sources: 6. Edit the code or the hand-written documentation instead.

What this module is responsible for

The booblik-protocol module defines the shared language between a client and a broker. It contains the wire format constants, the client-side request encoding logic, and the core domain types (like Offset and TopicName) that ensure both sides interpret the byte stream identically.

Diagram

Protocol Constants and Versioning

The protocol uses a big-endian byte order to allow FETCH responses to hand segment bytes directly to a socket without modification (Protocol.kt:8-10). The following table describes the header structures and limits:

ComponentStructure / LimitDescription
Request Header[int32 length][int16 apiKey][int16 apiVersion][int32 correlationId]Standard header for all requests (Protocol.kt:19)
Response Header[int32 correlationId][int16 errorCode]Standard header for all responses (Protocol.kt:22)
Max Frame Size8 * 1024 * 1024 bytesCeiling to prevent OOM attacks (Protocol.kt:31)
Max Fetch Wait60,000 msClamped wait time for FETCH requests (Protocol.kt:44)

The supports function determines version compatibility for specific APIs (Protocol.kt:54-57).

More: Protocol Constants and Versioning

RequestEncoder

The RequestEncoder is the client-side implementation responsible for building request frames (RequestEncoder.kt:18). It handles the following API types:

API KeyVersionDescription
PRODUCEVERSIONSends records to a specific topic and partition (RequestEncoder.kt:20)
FETCHFETCH_VERSIONRequests data from a partition with maxWaitMillis and minBytes (RequestEncoder.kt:55)
METADATAVERSIONRequests topic and partition information (RequestEncoder.kt:85)

AckPolicy

The AckPolicy defines the durability promises made to the producer (AckPolicy.kt:21).

PolicyPromiseDescription
NONENothingFire-and-forget; no reply is sent (AckPolicy.kt:22)
WRITTENBytes in logOffset is final, but not necessarily durable against power loss (AckPolicy.kt:23)
FORCEDDurabilityRequires a disk barrier/flush (AckPolicy.kt:24)

More: AckPolicy

Partitioner

The Partitioner interface allows clients to decide which partition a record is assigned to (Partitioner.kt:11).

AlgorithmImplementationCharacteristics
Fnv1afnv1a32Uses 32-bit FNV-1a with unsigned remainder for cross-language agreement (Partitioner.kt:38)
JavaArrayHashkey.contentHashCode()A JVM-specific implementation used for legacy compatibility (Partitioner.kt:73)

Offset, TopicName, and PartitionId

These value classes represent the core identifiers used in the protocol (Ids.kt:1-75):

TypeUnderlying TypeConstraints / Notes
OffsetLongMonotonic, non-negative, gap-free (Ids.kt:24)
TopicNameStringMax 249 chars; alphanumeric, ., _, or - (Ids.kt:46)
PartitionIdIntNon-negative integer (Ids.kt:66)

Key files

FileLinesWhat is there
…/log/AckPolicy.kt21-25The AckPolicy enum defining durability levels.
…/wire/Protocol.kt15-58Protocol constants, API keys, and versioning logic.
…/wire/RequestEncoder.kt18-104Logic for encoding client requests.
…/client/Partitioner.kt11-81Partitioning algorithms (FNV-1a and Java-based).
…/booblik/Ids.kt23-75Value classes for Offset, TopicName, and PartitionId.

Public API

WhatWhereWhy
ProtocolProtocol.kt:15Provides wire format constants and versioning.
CorruptRequestExceptionProtocol.kt:105Thrown when decoding a frame fails.
RequestEncoderRequestEncoder.kt:18Encodes client requests into ByteArray.
PartitionerPartitioner.kt:11Interface for mapping keys to partitions.
OffsetIds.kt:23Represents a logical record position.
TopicNameIds.kt:46Represents a topic identifier.
PartitionIdIds.kt:66Represents a partition identifier.

Behaviour that surprises

  • RequestEncoder always emits version 2 for FETCH requests, even when no waiting is required, to avoid maintaining two separate code paths for the same logic (RequestEncoder.kt:49-53).
  • Partitioner.Fnv1a uses and 0xFF during hashing to ensure that Kotlin's signed Byte type does not cause sign-extension issues that would break cross-language compatibility (Partitioner.kt:54).
  • Offset is implemented as a value class to avoid boxing in most cases, but it will still allocate memory when used in a generic position like Map<Offset, ...> (Ids.kt:15-17).

On this page