summaryrefslogtreecommitdiff
path: root/bipbuffer.c
diff options
context:
space:
mode:
authordormando <dormando@rydia.net>2015-11-18 01:49:53 -0800
committerdormando <dormando@rydia.net>2016-06-16 17:14:34 -0700
commit916fff3609b7ab817513a1a8498795c9f740d0e0 (patch)
treee38dbb1ee69f7de94d4f2a9f71016dadd89567e2 /bipbuffer.c
parentcad0ecbf381ab9e4ea4af80a0e24b86167d1e2a5 (diff)
downloadmemcached-916fff3609b7ab817513a1a8498795c9f740d0e0.tar.gz
initial logger code.
Logs are written to per-thread buffers. A new background thread aggregates the logs, further processes them, then writes them to any "watchers". Logs can have the time added to them, and all have a GID so they can be put back into strict order. This is an early preview. Code needs refactoring and a more complete set of options. All watchers are also stuck viewing the global feed of logs, even if they asked for different data. As of this commit there's no way to toggle the "stderr" watcher.
Diffstat (limited to 'bipbuffer.c')
-rw-r--r--bipbuffer.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/bipbuffer.c b/bipbuffer.c
new file mode 100644
index 0000000..ee48c84
--- /dev/null
+++ b/bipbuffer.c
@@ -0,0 +1,182 @@
+/**
+ * Copyright (c) 2011, Willem-Hendrik Thiart
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE.bipbuffer file.
+ *
+ * @file
+ * @author Willem Thiart himself@willemthiart.com
+ */
+
+#include "stdio.h"
+#include <stdlib.h>
+
+/* for memcpy */
+#include <string.h>
+
+#include "bipbuffer.h"
+
+static size_t bipbuf_sizeof(const unsigned int size)
+{
+ return sizeof(bipbuf_t) + size;
+}
+
+int bipbuf_unused(const bipbuf_t* me)
+{
+ if (1 == me->b_inuse)
+ /* distance between region B and region A */
+ return me->a_start - me->b_end;
+ else
+ return me->size - me->a_end;
+}
+
+int bipbuf_size(const bipbuf_t* me)
+{
+ return me->size;
+}
+
+int bipbuf_used(const bipbuf_t* me)
+{
+ return (me->a_end - me->a_start) + me->b_end;
+}
+
+void bipbuf_init(bipbuf_t* me, const unsigned int size)
+{
+ me->a_start = me->a_end = me->b_end = 0;
+ me->size = size;
+ me->b_inuse = 0;
+}
+
+bipbuf_t *bipbuf_new(const unsigned int size)
+{
+ bipbuf_t *me = malloc(bipbuf_sizeof(size));
+ if (!me)
+ return NULL;
+ bipbuf_init(me, size);
+ return me;
+}
+
+void bipbuf_free(bipbuf_t* me)
+{
+ free(me);
+}
+
+int bipbuf_is_empty(const bipbuf_t* me)
+{
+ return me->a_start == me->a_end;
+}
+
+/* find out if we should turn on region B
+ * ie. is the distance from A to buffer's end less than B to A? */
+static void __check_for_switch_to_b(bipbuf_t* me)
+{
+ if (me->size - me->a_end < me->a_start - me->b_end)
+ me->b_inuse = 1;
+}
+
+/* TODO: DOCUMENT THESE TWO FUNCTIONS */
+unsigned char *bipbuf_request(bipbuf_t* me, const int size)
+{
+ if (bipbuf_unused(me) < size)
+ return 0;
+ if (1 == me->b_inuse)
+ {
+ return (unsigned char *)me->data + me->b_end;
+ }
+ else
+ {
+ return (unsigned char *)me->data + me->a_end;
+ }
+
+ return NULL;
+}
+
+int bipbuf_push(bipbuf_t* me, const int size)
+{
+ if (bipbuf_unused(me) < size)
+ return 0;
+
+ if (1 == me->b_inuse)
+ {
+ me->b_end += size;
+ }
+ else
+ {
+ me->a_end += size;
+ }
+
+ __check_for_switch_to_b(me);
+ return size;
+}
+
+int bipbuf_offer(bipbuf_t* me, const unsigned char *data, const int size)
+{
+ /* not enough space */
+ if (bipbuf_unused(me) < size)
+ return 0;
+
+ if (1 == me->b_inuse)
+ {
+ memcpy(me->data + me->b_end, data, size);
+ me->b_end += size;
+ }
+ else
+ {
+ memcpy(me->data + me->a_end, data, size);
+ me->a_end += size;
+ }
+
+ __check_for_switch_to_b(me);
+ return size;
+}
+
+unsigned char *bipbuf_peek(const bipbuf_t* me, const unsigned int size)
+{
+ /* make sure we can actually peek at this data */
+ if (me->size < me->a_start + size)
+ return NULL;
+
+ if (bipbuf_is_empty(me))
+ return NULL;
+
+ return (unsigned char *)me->data + me->a_start;
+}
+
+unsigned char *bipbuf_peek_all(const bipbuf_t* me, unsigned int *size)
+{
+ if (bipbuf_is_empty(me))
+ return NULL;
+
+ *size = me->a_end - me->a_start;
+ return (unsigned char*)me->data + me->a_start;
+}
+
+unsigned char *bipbuf_poll(bipbuf_t* me, const unsigned int size)
+{
+ if (bipbuf_is_empty(me))
+ return NULL;
+
+ /* make sure we can actually poll this data */
+ if (me->size < me->a_start + size)
+ return NULL;
+
+ void *end = me->data + me->a_start;
+ me->a_start += size;
+
+ /* we seem to be empty.. */
+ if (me->a_start == me->a_end)
+ {
+ /* replace a with region b */
+ if (1 == me->b_inuse)
+ {
+ me->a_start = 0;
+ me->a_end = me->b_end;
+ me->b_end = me->b_inuse = 0;
+ }
+ else
+ /* safely move cursor back to the start because we are empty */
+ me->a_start = me->a_end = 0;
+ }
+
+ __check_for_switch_to_b(me);
+ return end;
+}