You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
4.6 KiB
111 lines
4.6 KiB
5 months ago
|
/*
|
||
|
* include/haproxy/ring-t.h
|
||
|
* This file provides definitions for ring buffers used for disposable data.
|
||
|
*
|
||
|
* Copyright (C) 2000-2019 Willy Tarreau - w@1wt.eu
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation, version 2.1
|
||
|
* exclusively.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
|
||
|
#ifndef _HAPROXY_RING_T_H
|
||
|
#define _HAPROXY_RING_T_H
|
||
|
|
||
|
#include <haproxy/api-t.h>
|
||
|
#include <haproxy/buf-t.h>
|
||
|
#include <haproxy/thread.h>
|
||
|
|
||
|
/* The code below handles circular buffers with single-producer and multiple
|
||
|
* readers (up to 255). The buffer storage area must remain always allocated.
|
||
|
* It's made of series of payload blocks followed by a readers count (RC).
|
||
|
* There is always a readers count at the beginning of the buffer as well. Each
|
||
|
* payload block is composed of a varint-encoded size (VI) followed by the
|
||
|
* actual payload (PL).
|
||
|
*
|
||
|
* The readers count is encoded on a single byte. It indicates how many readers
|
||
|
* are still waiting at this position. The writer writes after the buffer's
|
||
|
* tail, which initially starts just past the first readers count. Then it
|
||
|
* knows by reading this count that it must wake up the readers to indicate
|
||
|
* data availability. When a reader reads the payload block, it increments the
|
||
|
* next readers count and decrements the current one. The area between the
|
||
|
* initial readers count and the next one is protected from overwriting for as
|
||
|
* long as the initial count is non-null. As such these readers count are
|
||
|
* effective barriers against data recycling.
|
||
|
*
|
||
|
* Only the writer is allowed to update the buffer's tail/head. This ensures
|
||
|
* that events can remain as long as possible so that late readers can get the
|
||
|
* maximum history available. It also helps dealing with multi-thread accesses
|
||
|
* using a simple RW lock during the buffer head's manipulation. The writer
|
||
|
* will have to delete some old records starting at the head until the new
|
||
|
* message can fit or a non-null readers count is encountered. If a message
|
||
|
* cannot fit due to insufficient room, the message is lost and the drop
|
||
|
* counted must be incremented.
|
||
|
*
|
||
|
* Like any buffer, this buffer naturally wraps at the end and continues at the
|
||
|
* beginning. The creation process consists in immediately adding a null
|
||
|
* readers count byte into the buffer. The write process consists in always
|
||
|
* writing a payload block followed by a new readers count. The delete process
|
||
|
* consists in removing a null readers count and payload block. As such, there
|
||
|
* is always at least one readers count byte in the buffer available at the
|
||
|
* head for new readers to attach to, and one before the tail, both of which
|
||
|
* may be the same when the buffer doesn't contain any event. It is thus safe
|
||
|
* for any reader to simply keep the absolute offset of the last visited
|
||
|
* position and to restart from there. The write will update the buffer's
|
||
|
* absolute offset when deleting entries. All this also has the benefit of
|
||
|
* allowing a buffer to be hot-resized without losing its contents.
|
||
|
*
|
||
|
* Thus we have this :
|
||
|
* - init of empty buffer:
|
||
|
* head-, ,-tail
|
||
|
* [ RC | xxxxxxxxxxxxxxxxxxxxxxxxxx ]
|
||
|
*
|
||
|
* - reader attached:
|
||
|
* head-, ,-tail
|
||
|
* [ RC | xxxxxxxxxxxxxxxxxxxxxxxxxx ]
|
||
|
* ^- +1
|
||
|
*
|
||
|
* - append of one event:
|
||
|
* appended
|
||
|
* head-, <----------> ,-tail
|
||
|
* [ RC | VI | PL | RC | xxxxxxxxxxx ]
|
||
|
*
|
||
|
* - reader advancing:
|
||
|
* head-, ,-tail
|
||
|
* [ RC | VI | PL | RC | xxxxxxxxxxx ]
|
||
|
* ^- -1 ^- +1
|
||
|
*
|
||
|
* - writer removing older message:
|
||
|
* head-, ,-tail
|
||
|
* [ xxxxxxxxxxxx | RC | xxxxxxxxxxx ]
|
||
|
* <---------->
|
||
|
* removed
|
||
|
*/
|
||
|
|
||
|
struct ring {
|
||
|
struct buffer buf; // storage area
|
||
|
size_t ofs; // absolute offset in history of the buffer's head
|
||
|
struct list waiters; // list of waiters, for now, CLI "show event"
|
||
|
__decl_thread(HA_RWLOCK_T lock);
|
||
|
int readers_count;
|
||
|
};
|
||
|
|
||
|
#endif /* _HAPROXY_RING_T_H */
|
||
|
|
||
|
/*
|
||
|
* Local variables:
|
||
|
* c-indent-level: 8
|
||
|
* c-basic-offset: 8
|
||
|
* End:
|
||
|
*/
|