blob: b512b07d29157be40c9e5b7ff5397401d0d05d09 [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
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020025#include <haproxy/api-t.h>
Willy Tarreau8dabda72020-05-27 17:22:10 +020026#include <haproxy/buf-t.h>
Willy Tarreaueb6f7012020-05-27 16:21:26 +020027#include <import/ist.h>
Willy Tarreau172945f2019-08-08 15:28:52 +020028
29/* The code below handles circular buffers with single-producer and multiple
30 * readers (up to 255). The buffer storage area must remain always allocated.
31 * It's made of series of payload blocks followed by a readers count (RC).
32 * There is always a readers count at the beginning of the buffer as well. Each
33 * payload block is composed of a varint-encoded size (VI) followed by the
34 * actual payload (PL).
35 *
36 * The readers count is encoded on a single byte. It indicates how many readers
37 * are still waiting at this position. The writer writes after the buffer's
38 * tail, which initially starts just past the first readers count. Then it
39 * knows by reading this count that it must wake up the readers to indicate
40 * data availability. When a reader reads the payload block, it increments the
41 * next readers count and decrements the current one. The area between the
42 * initial readers count and the next one is protected from overwriting for as
43 * long as the initial count is non-null. As such these readers count are
44 * effective barriers against data recycling.
45 *
46 * Only the writer is allowed to update the buffer's tail/head. This ensures
47 * that events can remain as long as possible so that late readers can get the
48 * maximum history available. It also helps dealing with multi-thread accesses
49 * using a simple RW lock during the buffer head's manipulation. The writer
50 * will have to delete some old records starting at the head until the new
51 * message can fit or a non-null readers count is encountered. If a message
52 * cannot fit due to insufficient room, the message is lost and the drop
53 * counted must be incremented.
54 *
55 * Like any buffer, this buffer naturally wraps at the end and continues at the
56 * beginning. The creation process consists in immediately adding a null
57 * readers count byte into the buffer. The write process consists in always
58 * writing a payload block followed by a new readers count. The delete process
59 * consists in removing a null readers count and payload block. As such, there
60 * is always at least one readers count byte in the buffer available at the
61 * head for new readers to attach to, and one before the tail, both of which
62 * may be the same when the buffer doesn't contain any event. It is thus safe
63 * for any reader to simply keep the absolute offset of the last visited
64 * position and to restart from there. The write will update the buffer's
65 * absolute offset when deleting entries. All this also has the benefit of
66 * allowing a buffer to be hot-resized without losing its contents.
67 *
68 * Thus we have this :
69 * - init of empty buffer:
70 * head-, ,-tail
71 * [ RC | xxxxxxxxxxxxxxxxxxxxxxxxxx ]
72 *
73 * - reader attached:
74 * head-, ,-tail
75 * [ RC | xxxxxxxxxxxxxxxxxxxxxxxxxx ]
76 * ^- +1
77 *
78 * - append of one event:
79 * appended
80 * head-, <----------> ,-tail
81 * [ RC | VI | PL | RC | xxxxxxxxxxx ]
82 *
83 * - reader advancing:
84 * head-, ,-tail
85 * [ RC | VI | PL | RC | xxxxxxxxxxx ]
86 * ^- -1 ^- +1
87 *
88 * - writer removing older message:
89 * head-, ,-tail
90 * [ xxxxxxxxxxxx | RC | xxxxxxxxxxx ]
91 * <---------->
92 * removed
93 */
94
95struct ring {
96 struct buffer buf; // storage area
97 size_t ofs; // absolute offset in history of the buffer's head
Willy Tarreau1d181e42019-08-30 11:17:01 +020098 struct list waiters; // list of waiters, for now, CLI "show event"
Willy Tarreauaf613e82020-06-05 08:40:51 +020099 __decl_thread(HA_RWLOCK_T lock);
Willy Tarreau172945f2019-08-08 15:28:52 +0200100 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 */