blob: 3d69b22525f84ca2fe9872405b24ade4a980b748 [file] [log] [blame]
Willy Tarreau172945f2019-08-08 15:28:52 +02001/*
2 * include/types/ring.h
3 * This file provides definitions for ring buffers used for disposable data.
4 *
5 * Copyright (C) 2000-2019 Willy Tarreau - w@1wt.eu
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation, version 2.1
10 * exclusively.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef _TYPES_RING_H
23#define _TYPES_RING_H
24
25#include <common/buffer.h>
26#include <common/compat.h>
27#include <common/config.h>
28#include <common/ist.h>
29
30/* The code below handles circular buffers with single-producer and multiple
31 * readers (up to 255). The buffer storage area must remain always allocated.
32 * It's made of series of payload blocks followed by a readers count (RC).
33 * There is always a readers count at the beginning of the buffer as well. Each
34 * payload block is composed of a varint-encoded size (VI) followed by the
35 * actual payload (PL).
36 *
37 * The readers count is encoded on a single byte. It indicates how many readers
38 * are still waiting at this position. The writer writes after the buffer's
39 * tail, which initially starts just past the first readers count. Then it
40 * knows by reading this count that it must wake up the readers to indicate
41 * data availability. When a reader reads the payload block, it increments the
42 * next readers count and decrements the current one. The area between the
43 * initial readers count and the next one is protected from overwriting for as
44 * long as the initial count is non-null. As such these readers count are
45 * effective barriers against data recycling.
46 *
47 * Only the writer is allowed to update the buffer's tail/head. This ensures
48 * that events can remain as long as possible so that late readers can get the
49 * maximum history available. It also helps dealing with multi-thread accesses
50 * using a simple RW lock during the buffer head's manipulation. The writer
51 * will have to delete some old records starting at the head until the new
52 * message can fit or a non-null readers count is encountered. If a message
53 * cannot fit due to insufficient room, the message is lost and the drop
54 * counted must be incremented.
55 *
56 * Like any buffer, this buffer naturally wraps at the end and continues at the
57 * beginning. The creation process consists in immediately adding a null
58 * readers count byte into the buffer. The write process consists in always
59 * writing a payload block followed by a new readers count. The delete process
60 * consists in removing a null readers count and payload block. As such, there
61 * is always at least one readers count byte in the buffer available at the
62 * head for new readers to attach to, and one before the tail, both of which
63 * may be the same when the buffer doesn't contain any event. It is thus safe
64 * for any reader to simply keep the absolute offset of the last visited
65 * position and to restart from there. The write will update the buffer's
66 * absolute offset when deleting entries. All this also has the benefit of
67 * allowing a buffer to be hot-resized without losing its contents.
68 *
69 * Thus we have this :
70 * - init of empty buffer:
71 * head-, ,-tail
72 * [ RC | xxxxxxxxxxxxxxxxxxxxxxxxxx ]
73 *
74 * - reader attached:
75 * head-, ,-tail
76 * [ RC | xxxxxxxxxxxxxxxxxxxxxxxxxx ]
77 * ^- +1
78 *
79 * - append of one event:
80 * appended
81 * head-, <----------> ,-tail
82 * [ RC | VI | PL | RC | xxxxxxxxxxx ]
83 *
84 * - reader advancing:
85 * head-, ,-tail
86 * [ RC | VI | PL | RC | xxxxxxxxxxx ]
87 * ^- -1 ^- +1
88 *
89 * - writer removing older message:
90 * head-, ,-tail
91 * [ xxxxxxxxxxxx | RC | xxxxxxxxxxx ]
92 * <---------->
93 * removed
94 */
95
96struct ring {
97 struct buffer buf; // storage area
98 size_t ofs; // absolute offset in history of the buffer's head
99 __decl_hathreads(HA_RWLOCK_T lock);
100 int readers_count;
101};
102
103#endif /* _TYPES_RING_H */
104
105/*
106 * Local variables:
107 * c-indent-level: 8
108 * c-basic-offset: 8
109 * End:
110 */