gauc 0.3.0

Couchbase Rust Adapter / CLI
Documentation
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2014 Couchbase, Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#ifndef NETBUF_H
#define NETBUF_H

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @file
 * @brief Netbuf write buffers
 */

/**
 * @defgroup netbufs Netbufs
 *
 * # Introduction
 *
 * ## GOALS
 *
 * 1.  provide a simple buffer allocation API
 *     From a logic perspective it's simplest to deal with a straight
 *     contiguous buffer per packet.
 *
 * 2.  provide an efficient way of sending multiple contiguous packets. This
 *     will reduce IOV fragmentation and reduce the number of trips to the
 *     I/O plugin for multiple writes. Currently this is done very efficiently
 *     with the ringbuffer - however this comes at the cost of copying all
 *     request data to the ringbuffer itself. Our aim is to reduce the
 *     number of copies while still maintaining a packed buffer.
 *
 * 3.  Allow a pluggable method by which user-provided data can be plugged
 *     into the span/cursor/flush architecture.
 *
 * @addtogroup netbufs
 * @{
 */

#include "sllist.h"
#include "netbuf-defs.h"
#include "netbuf-mblock.h"

/**
 * @brief Structure representing a buffer within netbufs
 *
 * @note It is recommended that you maintain the individual fields in your
 * own structure and then re-create them as needed. The span structure is 16
 * bytes on 64 bit systems, but can be reduced to 12 if needed. Additionally,
 * you may already have the 'size' field stored/calculated elsewhere.
 */
typedef struct {
    /** @private Parent block */
    nb_MBLOCK *parent;

    /** @private Offset from root at which this buffer begins */
    nb_SIZE offset;

    /** write-once: Allocation size */
    nb_SIZE size;
} nb_SPAN;

#define NETBUF_INVALID_OFFSET (nb_SIZE)-1

/**
 * Creates a span from a buffer _not_ owned by netbufs.
 * @param span the span to initialize
 * @param buf the buffer
 * @param len the length of the buffer
 */
#define CREATE_STANDALONE_SPAN(span, buf, len) \
    (span)->parent = (nb_MBLOCK *) (void *)buf; \
    (span)->offset = NETBUF_INVALID_OFFSET; \
    (span)->size = len;

/** @private */
typedef struct {
    sllist_node slnode;
    char *base;
    nb_SIZE len;
    /* Extra 4 bytes here. WHAT WE DO!!! */
} nb_SNDQELEM;

/** @private */
typedef struct {
    /** Linked list of pending spans to send */
    sllist_root pending;

    /**
     * List of PDUs to be flushed. A PDU is comprised of one or more IOVs
     * (or even a subsection thereof)
     */
    sllist_root pdus;

    /** The last window which was part of the previous fill call */
    nb_SNDQELEM *last_requested;

    /**
     * Number of bytes enqueued in the 'last request' element. This is needed
     * because it is possible for the last element to grow in length during
     * a subsequent flush.
     */
    nb_SIZE last_offset;

    /** Offset from last PDU which was partially flushed */
    nb_SIZE pdu_offset;

    /** Pool of elements to utilize */
    nb_MBPOOL elempool;
} nb_SENDQ;

struct netbuf_st {
    /** Send Queue */
    nb_SENDQ sendq;

    /** Pool for variable-size data */
    nb_MBPOOL datapool;

    nb_SETTINGS settings;
};

/**
 * Quick way to get the span from a buffer, when the buffer is *known* to
 * be standalone (i.e. CREATE_STANDALONE_SPAN()
 * @param span The span from which to extract the buffer
 * @return a pointer to the buffer
 */
#define SPAN_SABUFFER_NC(span) ((char *)(span)->parent)

/**
 * Quick way to get the span from a buffer when the buffer is known *not*
 * to be standalone
 * @param span The span from which to extract the buffer
 * @return A pointer to a buffer
 */
#define SPAN_MBUFFER_NC(span) ((span)->parent->root + (span)->offset)

/**
 * @brief Retrieves a pointer to the buffer related to this span.
 * @param span the span from which to extract the buffer
 * @return a pointer to the buffer.
 *
 * @see SPAN_SABUFFER_NC
 * @see SPAN_MBUFFER_NC
 */
#define SPAN_BUFFER(span) \
        (((span)->offset == NETBUF_INVALID_OFFSET) ? SPAN_SABUFFER_NC(span) : SPAN_MBUFFER_NC(span))

/**
 * @brief allocate a span
 *
 * Reserve a contiguous region of memory, in-order for a given span. The
 * span will be reserved from the last block to be flushed to the network.
 *
 * The contents of the span are guaranteed to be contiguous (though not aligned)
 * and are available via the SPAN_BUFFER macro.
 *
 * @return 0 if successful, -1 on error
 */
int
netbuf_mblock_reserve(nb_MGR *mgr, nb_SPAN *span);

/**
 * @brief release a span
 *
 * Release a span previously allocated via reserve_span. It is assumed that the
 * contents of the span have either:
 *
 * 1. been successfully sent to the network
 * 2. have just been scheduled (and are being removed due to error handling)
 * 3. have been partially sent to a connection which is being closed.
 *
 * @param mgr the manager in which this span is reserved
 * @param span the span
 */
void
netbuf_mblock_release(nb_MGR *mgr, nb_SPAN *span);

/**
 * @brief Enqueue a span for serialization
 *
 * Schedules an IOV to be placed inside the send queue. The storage of the
 * underlying buffer must not be freed or otherwise modified until it has
 * been sent.
 *
 * With the current usage model, flush status is implicitly completed once
 * a response has arrived.
 *
 * Note that you may create the IOV from a SPAN object like so:
 * @code{.c}
 * iov->iov_len = span->size;
 * iov->iov_base = SPAN_BUFFER(span);
 * @endcode
 */
void
netbuf_enqueue(nb_MGR *mgr, const nb_IOV *bufinfo);

void
netbuf_enqueue_span(nb_MGR *mgr, nb_SPAN *span);

/**
 * Gets the number of IOV structures required to flush the entire contents of
 * all buffers.
 */
unsigned int
netbuf_get_niov(nb_MGR *mgr);

/**
 * @brief
 * Populates an iovec structure for flushing a set of bytes from the various
 * blocks.
 *
 * You may call this function mutltiple times, so long as each call to
 * start_flush is eventually mapped with a call to end_flush.
 *
 * @code{.c}
 * netbuf_start_flush(mgr, iov1, niov1);
 * netbuf_start_flush(mgr, iov2, niov2);
 * ...
 * netbuf_end_flush(mgr, nbytes1);
 * netbuf_end_flush(mgr, nbytes2);
 * @endcode
 *
 * Additionally, only the LAST end_flush call may be supplied an nflushed
 * parameter which is smaller than the size returned by start_flush. If the
 * entire contents of the `iovs` structure cannot be flushed immediately and
 * you do not wish to persist it until such a time that it may be flushed, then
 * netbuf_reset_flush() should be called. See that functions' documentation
 * for more details.
 *
 * This function may be thought of advancing a virtual cursor which is mapped
 * to a send queue. Each time this function is called the cursor is advanced
 * by the number of bytes that the library expects you to flush (i.e. the return
 * value of this function). Typically the cursor is never rewound and any
 * operation that advances the cursor places the burden on the user to
 * actually flush the data contained within the IOV objects.
 * The netbuf_end_flush() function merely has the task of releasing any memory
 * used for mapping of already-flushed data.
 *
 * From a different perspective, each call to netbuf_start_flush() establishes
 * a contract between the library and the user: The library guarantees that
 * this specific region (referred to within the IOVs) will not be flushed by
 * any other subsystem (i.e. nothing else will try to flush the same data).
 * The user guarantees that the data will eventually be flushed, and that the
 * data will be flushed in the order it was received via start_flush().
 *
 *
 * @param mgr the manager object
 * @param iovs an array of iovec structures
 * @param niov the number of iovec structures allocated.
 * @param[out] nused how many IOVs are actually required
 *
 * @return the number of bytes which can be flushed in this IOV. If the
 * return value is 0 then there are no more bytes to flush.
 *
 * Note that the return value is limited by the number of IOV structures
 * provided and should not be taken as an indicator of how many bytes are
 * used overall.
 */
nb_SIZE
netbuf_start_flush(nb_MGR *mgr, nb_IOV *iovs, int niov, int *nused);

/**
 * @brief Indicate that a flush has completed.
 *
 * Indicate that a number of bytes have been flushed. This should be called after
 * the data retrieved by get_flushing_iov has been flushed to the TCP buffers.
 *
 * @param mgr the manager object
 * @param nflushed how much data in bytes was flushed to the network.
 */
void
netbuf_end_flush(nb_MGR *mgr, nb_SIZE nflushed);

/**
 * Reset the flush context for the buffer. This should be called only when the
 * following is true:
 *
 * (1) There is only a single open call to netbuf_start_flush
 * (2) The last call to end_flush did not pass all the bytes which were to
 *     be flushed.
 *
 * In this case, the next call to start_flush() will return an IOV which begins
 * where the last end_flush() finished, rather than the last start_flush().
 * As a consequence it means that the previous IOV populated with start_flush
 * is no longer valid and start_flush should be called again.
 */
#define netbuf_reset_flush(mgr) do { \
    (mgr)->sendq.last_requested = NULL; \
    (mgr)->sendq.last_offset = 0; \
} while (0);

/**
 * Informational function to get the total size of all data in the
 * buffers. This traverses all blocks, so call this for debugging only.
 */
nb_SIZE
netbuf_get_size(const nb_MGR *mgr);

/**
 * Get the maximum size of a span which can be satisfied without using an
 * additional block.
 *
 * @param mgr
 *
 * @param allow_wrap
 * Whether to take into consideration wrapping. If this is true then the span
 * size will allow wrapping. If disabled, then only the packed size will be
 * available. Consider:
 * <pre>
 * [ ooooooo{S:10}xxxxxxxxx{C:10}ooooo{A:5} ]
 * </pre>
 * If wrapping is allowed, then the maximum span size will be 10, from 0..10
 * but the last 5 bytes at the end will be lost for the duration of the block.
 * If wrapping is not allowed then the maximum span size will be 5.
 *
 * @return
 * the maximum span size without requiring additional blocks.
 */
nb_SIZE
netbuf_mblock_get_next_size(const nb_MGR *mgr, int allow_wrap);

/**
 * @brief Initializes an nb_MGR structure
 * @param mgr the manager to initialize
 * @param settings
 */
void
netbuf_init(nb_MGR *mgr, const nb_SETTINGS *settings);

/**
 * @brief Frees up any allocated resources for a given manager
 * @param mgr the manager for which to release resources
 */
void
netbuf_cleanup(nb_MGR *mgr);

/**
 * Populates the settings structure with the default settings. This structure
 * may then be modified or tuned and passed to netbuf_init()
 */
void
netbuf_default_settings(nb_SETTINGS *settings);

/**
 * Dump the internal structure of the manager to the screen. Useful for
 * debugging.
 */
void
netbuf_dump_status(nb_MGR *mgr, FILE *fp);


/**
 * Mark a PDU as being enqueued. This should be called whenever the final IOV
 * for a given PDU has just been enqueued.
 *
 * The PDU itself must remain valid and is assumed to contain an 'slnode'
 * structure which will point to the next PDU. The PDU will later be removed
 * from the queue when 'end_flush' has been called including its range.
 *
 * @param mgr The manager
 *
 * @param pdu An opaque pointer
 *
 * @param lloff The offset from the pdu pointer at which the slist_node
 *        structure may be found.
 */
void
netbuf_pdu_enqueue(nb_MGR *mgr, void *pdu, nb_SIZE lloff);


/**
 * This callback is invoked during 'end_flush2'.
 *
 * @param pdu The PDU pointer enqueued via netbuf_pdu_enqueue()
 *
 * @param remaining A hint passed to the callback indicating how many bytes
 *        remain on the stream. IFF remaining is greater than the size of the
 *        PDU the callback may change internal state within the packet to mark
 *        it as flushed.
 *
 *        XXX:
 *        If nremaining < pdusize then it <b>must</b> be ignored. The value
 *        may have been previously passed to the same callback during a
 *        prior iteration.
 *
 *        This is done by design in order to avoid forcing each PDU to maintain
 *        a variable indicating "How much was flushed".
 *
 * @param arg A pointer passed to the start_flush call; used to correlate any
 *        data common to the queue itself.
 *
 * @return The size of the PDU. This will be used to determine future calls
 *         to the callback for subsequent PDUs.
 *
 *         If size <= remaining then this PDU will be popped off the PDU queue
 *         and is deemed to be no longer utilized by the send queue (and may
 *         be released from the mblock allocator; if it's being used).
 *
 *         If size > remaining then no further callbacks will be invoked on
 *         the relevant PDUs.
 */
typedef nb_SIZE (*nb_getsize_fn)(void *pdu, nb_SIZE remaining, void *arg);

void
netbuf_end_flush2(nb_MGR *mgr,
                  unsigned int nflushed,
                  nb_getsize_fn callback,
                  nb_SIZE lloff, void *arg);


/**
 * Ensures that the given internal structures of the manager are not allocated
 * or otherwise in use by other systems. This is useful for testing to ensure
 * that we wouldn't accidentally think everything is OK.
 *
 * Because resources are released at the block level, we might have had blocks
 * which were partially allocated.
 *
 * This also checks the PDU and send queues as well.
 */
int
netbuf_is_clean(nb_MGR *mgr);

/**
 * Determines if there is any data to be flushed to the network
 */
int
netbuf_has_flushdata(nb_MGR *mgr);

/**@}*/

#ifdef __cplusplus
}
#endif

#endif /* LCB_PACKET_H */