or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

buffer-management.mdbuilders-factories.mdcore-utilities.mdindex.mdload-balancing-name-resolution.mdservice-providers.mdtransport-layer.md

buffer-management.mddocs/

0

# Buffer Management

1

2

gRPC Core provides memory-efficient buffer abstractions for handling data in gRPC streams. These interfaces allow different transport implementations to optimize memory usage while providing a consistent API for reading and writing data.

3

4

## Capabilities

5

6

### Readable Buffer Interface

7

8

Interface for reading data from buffers in a streaming fashion.

9

10

```java { .api }

11

/**

12

* Interface for readable byte buffers

13

* Located: io.grpc.internal.ReadableBuffer

14

*/

15

interface ReadableBuffer {

16

/**

17

* Gets the number of readable bytes remaining in this buffer

18

* @return Number of bytes that can be read

19

*/

20

int readableBytes();

21

22

/**

23

* Reads a single byte as an unsigned integer (0-255)

24

* @return Unsigned byte value

25

* @throws IndexOutOfBoundsException if no bytes are readable

26

*/

27

int readUnsignedByte();

28

29

/**

30

* Reads bytes into the destination array

31

* @param dest Destination byte array

32

* @param destOffset Starting offset in destination array

33

* @param length Number of bytes to read

34

* @throws IndexOutOfBoundsException if not enough bytes are readable

35

*/

36

void readBytes(byte[] dest, int destOffset, int length);

37

38

/**

39

* Reads bytes into a newly allocated byte array

40

* @param length Number of bytes to read

41

* @return Byte array containing the read data

42

* @throws IndexOutOfBoundsException if not enough bytes are readable

43

*/

44

void readBytes(byte[] dest);

45

46

/**

47

* Reads bytes into a new readable buffer

48

* @param length Number of bytes to read

49

* @return New ReadableBuffer containing the read data

50

* @throws IndexOutOfBoundsException if not enough bytes are readable

51

*/

52

ReadableBuffer readBytes(int length);

53

54

/**

55

* Skips the specified number of bytes

56

* @param length Number of bytes to skip

57

* @throws IndexOutOfBoundsException if not enough bytes are readable

58

*/

59

void skipBytes(int length);

60

61

/**

62

* Checks if this buffer has a backing byte array

63

* @return true if hasArray() and array() are supported

64

*/

65

boolean hasArray();

66

67

/**

68

* Gets the backing byte array (if available)

69

* @return Backing byte array

70

* @throws UnsupportedOperationException if hasArray() returns false

71

*/

72

byte[] array();

73

74

/**

75

* Gets the offset in the backing array where readable data starts

76

* @return Array offset

77

* @throws UnsupportedOperationException if hasArray() returns false

78

*/

79

int arrayOffset();

80

81

/**

82

* Closes the buffer and releases any associated resources

83

*/

84

void close();

85

}

86

```

87

88

### Writable Buffer Interface

89

90

Interface for writing data to buffers.

91

92

```java { .api }

93

/**

94

* Interface for writable byte buffers

95

* Located: io.grpc.internal.WritableBuffer

96

*/

97

interface WritableBuffer {

98

/**

99

* Writes bytes from the source array to this buffer

100

* @param src Source byte array

101

* @param srcOffset Starting offset in source array

102

* @param length Number of bytes to write

103

* @throws IndexOutOfBoundsException if buffer doesn't have enough space

104

*/

105

void write(byte[] src, int srcOffset, int length);

106

107

/**

108

* Writes all bytes from the source array to this buffer

109

* @param src Source byte array

110

* @throws IndexOutOfBoundsException if buffer doesn't have enough space

111

*/

112

void write(byte[] src);

113

114

/**

115

* Writes a single byte to this buffer

116

* @param b Byte value to write

117

* @throws IndexOutOfBoundsException if buffer doesn't have enough space

118

*/

119

void write(int b);

120

121

/**

122

* Gets the number of bytes that can still be written to this buffer

123

* @return Number of writable bytes remaining

124

*/

125

int writableBytes();

126

127

/**

128

* Gets the number of bytes that have been written and can be read

129

* @return Number of readable bytes

130

*/

131

int readableBytes();

132

133

/**

134

* Releases the buffer and returns it as a ReadableBuffer

135

* After calling this method, the WritableBuffer should not be used

136

* @return ReadableBuffer containing the written data

137

*/

138

ReadableBuffer readableBuffer();

139

}

140

```

141

142

### Writable Buffer Allocator Interface

143

144

Interface for allocating writable buffers.

145

146

```java { .api }

147

/**

148

* Interface for allocating writable buffers

149

* Located: io.grpc.internal.WritableBufferAllocator

150

*/

151

interface WritableBufferAllocator {

152

/**

153

* Allocates a new writable buffer with the specified capacity hint

154

* @param capacityHint Hint for the desired buffer capacity

155

* @return New WritableBuffer instance

156

*/

157

WritableBuffer allocate(int capacityHint);

158

}

159

```

160

161

## Buffer Implementations

162

163

### Composite Readable Buffer

164

165

Implementation that combines multiple readable buffers into a single logical buffer.

166

167

```java { .api }

168

/**

169

* Composite readable buffer implementation

170

* Located: io.grpc.internal.CompositeReadableBuffer

171

*/

172

class CompositeReadableBuffer implements ReadableBuffer {

173

/**

174

* Creates a new composite buffer

175

*/

176

public CompositeReadableBuffer();

177

178

/**

179

* Adds a buffer to the end of this composite buffer

180

* @param buffer Buffer to add

181

* @throws IllegalArgumentException if buffer is null

182

*/

183

public void addBuffer(ReadableBuffer buffer);

184

185

@Override

186

public int readableBytes();

187

188

@Override

189

public int readUnsignedByte();

190

191

@Override

192

public void readBytes(byte[] dest, int destOffset, int length);

193

194

@Override

195

public void readBytes(byte[] dest);

196

197

@Override

198

public ReadableBuffer readBytes(int length);

199

200

@Override

201

public void skipBytes(int length);

202

203

@Override

204

public boolean hasArray();

205

206

@Override

207

public byte[] array();

208

209

@Override

210

public int arrayOffset();

211

212

@Override

213

public void close();

214

}

215

```

216

217

### Array-Based Buffer Implementations

218

219

Simple implementations using byte arrays as backing storage.

220

221

```java { .api }

222

/**

223

* ReadableBuffer implementation backed by a byte array

224

* Located: io.grpc.internal.ReadableBuffers

225

*/

226

class ReadableBuffers {

227

/**

228

* Creates a readable buffer wrapping the entire byte array

229

* @param bytes Byte array to wrap

230

* @return ReadableBuffer wrapping the array

231

*/

232

public static ReadableBuffer wrap(byte[] bytes);

233

234

/**

235

* Creates a readable buffer wrapping part of a byte array

236

* @param bytes Byte array to wrap

237

* @param offset Starting offset in the array

238

* @param length Number of bytes to include

239

* @return ReadableBuffer wrapping the specified array section

240

*/

241

public static ReadableBuffer wrap(byte[] bytes, int offset, int length);

242

243

/**

244

* Creates an empty readable buffer

245

* @return Empty ReadableBuffer

246

*/

247

public static ReadableBuffer empty();

248

}

249

250

/**

251

* WritableBuffer implementation backed by a byte array

252

* Located: io.grpc.internal.WritableBuffers

253

*/

254

class WritableBuffers {

255

/**

256

* Creates a writable buffer with the specified initial capacity

257

* @param capacity Initial capacity in bytes

258

* @return WritableBuffer with the specified capacity

259

*/

260

public static WritableBuffer allocate(int capacity);

261

}

262

```

263

264

## Buffer Usage Patterns

265

266

### Reading Data from Streams

267

268

```java

269

import io.grpc.internal.ReadableBuffer;

270

import io.grpc.internal.CompositeReadableBuffer;

271

272

// Reading from a single buffer

273

ReadableBuffer buffer = getMessageBuffer();

274

byte[] messageData = new byte[buffer.readableBytes()];

275

buffer.readBytes(messageData);

276

buffer.close();

277

278

// Reading from composite buffer (multiple chunks)

279

CompositeReadableBuffer composite = new CompositeReadableBuffer();

280

composite.addBuffer(chunk1);

281

composite.addBuffer(chunk2);

282

composite.addBuffer(chunk3);

283

284

// Read the entire composite as one logical buffer

285

byte[] fullMessage = new byte[composite.readableBytes()];

286

composite.readBytes(fullMessage);

287

composite.close();

288

```

289

290

### Writing Data to Streams

291

292

```java

293

import io.grpc.internal.WritableBuffer;

294

import io.grpc.internal.WritableBufferAllocator;

295

296

// Allocate buffer for writing

297

WritableBufferAllocator allocator = getBufferAllocator();

298

WritableBuffer buffer = allocator.allocate(1024);

299

300

// Write data to buffer

301

byte[] messageData = serializeMessage(message);

302

buffer.write(messageData);

303

304

// Convert to readable buffer for transmission

305

ReadableBuffer readable = buffer.readableBuffer();

306

sendBuffer(readable);

307

```

308

309

### Custom Buffer Allocator

310

311

```java

312

import io.grpc.internal.WritableBufferAllocator;

313

import io.grpc.internal.WritableBuffer;

314

315

// Custom allocator implementation

316

public class PooledBufferAllocator implements WritableBufferAllocator {

317

private final BufferPool pool;

318

319

public PooledBufferAllocator(BufferPool pool) {

320

this.pool = pool;

321

}

322

323

@Override

324

public WritableBuffer allocate(int capacityHint) {

325

// Get buffer from pool based on capacity hint

326

return pool.borrowBuffer(capacityHint);

327

}

328

}

329

```

330

331

## Memory Management

332

333

### Buffer Lifecycle

334

335

1. **Allocation**: Buffers are allocated through allocator interfaces

336

2. **Writing**: Data is written to WritableBuffer instances

337

3. **Conversion**: WritableBuffers are converted to ReadableBuffers

338

4. **Reading**: Data is read from ReadableBuffer instances

339

5. **Cleanup**: Buffers are closed to release resources

340

341

### Resource Management Best Practices

342

343

```java

344

// Always close buffers to prevent memory leaks

345

ReadableBuffer buffer = null;

346

try {

347

buffer = receiveBuffer();

348

processBuffer(buffer);

349

} finally {

350

if (buffer != null) {

351

buffer.close();

352

}

353

}

354

355

// Or use try-with-resources if buffer implements AutoCloseable

356

try (ReadableBuffer buffer = receiveBuffer()) {

357

processBuffer(buffer);

358

}

359

```

360

361

### Performance Considerations

362

363

- **Buffer Reuse**: Implement buffer pooling for high-throughput scenarios

364

- **Copy Avoidance**: Use `hasArray()` to access backing arrays directly when possible

365

- **Composite Buffers**: Use for scatter-gather operations to avoid copying

366

- **Capacity Hints**: Provide accurate capacity hints to reduce allocations

367

- **Early Release**: Close buffers as soon as reading is complete

368

369

## Error Handling

370

371

Buffer operations handle errors through:

372

373

- **IndexOutOfBoundsException**: Thrown when reading beyond buffer capacity

374

- **IllegalArgumentException**: Thrown for invalid parameters (null buffers, negative lengths)

375

- **UnsupportedOperationException**: Thrown when operations are not supported (e.g., `array()` when `hasArray()` is false)

376

- **Resource Cleanup**: Buffers implement proper cleanup in `close()` methods

377

- **State Validation**: Operations check buffer state and throw appropriate exceptions