/*
Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#include "glusterfs/circ-buff.h"
#include "glusterfs/libglusterfs-messages.h"
void
cb_destroy_data(circular_buffer_t *cb, void (*destroy_buffer_data)(void *data))
{
if (destroy_buffer_data)
destroy_buffer_data(cb->data);
GF_FREE(cb->data);
return;
}
/* hold lock while calling this function */
int
__cb_add_entry_buffer(buffer_t *buffer, void *item)
{
circular_buffer_t *ptr = NULL;
int ret = -1;
// DO we really need the assert here?
GF_ASSERT(buffer->used_len <= buffer->size_buffer);
if (buffer->use_once == _gf_true &&
buffer->used_len == buffer->size_buffer) {
gf_msg("circ-buff", GF_LOG_WARNING, 0, LG_MSG_BUFFER_ERROR,
"buffer %p is use once buffer", buffer);
return -1;
} else {
if (buffer->used_len == buffer->size_buffer) {
if (buffer->cb[buffer->w_index]) {
ptr = buffer->cb[buffer->w_index];
if (ptr->data) {
cb_destroy_data(ptr, buffer->destroy_buffer_data);
ptr->data = NULL;
GF_FREE(ptr);
}
buffer->cb[buffer->w_index] = NULL;
ptr = NULL;
}
}
buffer->cb[buffer->w_index] = GF_CALLOC(1, sizeof(circular_buffer_t),
gf_common_mt_circular_buffer_t);
if (!buffer->cb[buffer->w_index])
return -1;
buffer->cb[buffer->w_index]->data = item;
ret = gettimeofday(&buffer->cb[buffer->w_index]->tv, NULL);
if (ret == -1)
gf_msg_callingfn("circ-buff", GF_LOG_WARNING, 0,
LG_MSG_GETTIMEOFDAY_FAILED,
"getting time of the day failed");
buffer->w_index++;
buffer->w_index %= buffer->size_buffer;
// used_buffer size cannot be greater than the total buffer size
if (buffer->used_len < buffer->size_buffer)
buffer->used_len++;
return buffer->w_index;
}
}
int
cb_add_entry_buffer(buffer_t *buffer, void *item)
{
int write_index = -1;
pthread_mutex_lock(&buffer->lock);
{
write_index = __cb_add_entry_buffer(buffer, item);
}
pthread_mutex_unlock(&buffer->lock);
return write_index;
}
void
cb_buffer_show(buffer_t *buffer)
{
pthread_mutex_lock(&buffer->lock);
{
gf_msg_debug("circ-buff", 0,
"w_index: %d, size: %" GF_PRI_SIZET " used_buffer: %d",
buffer->w_index, buffer->size_buffer, buffer->used_len);
}
pthread_mutex_unlock(&buffer->lock);
}
void
cb_buffer_dump(buffer_t *buffer, void *data,
int(fn)(circular_buffer_t *buffer, void *data))
{
int index = 0;
circular_buffer_t *entry = NULL;
int entries = 0;
int ul = 0;
int w_ind = 0;
int size_buff = 0;
int i = 0;
ul = buffer->used_len;
w_ind = buffer->w_index;
size_buff = buffer->size_buffer;
pthread_mutex_lock(&buffer->lock);
{
if (buffer->use_once == _gf_false) {
index = (size_buff + (w_ind - ul)) % size_buff;
for (entries = 0; entries < buffer->used_len; entries++) {
entry = buffer->cb[index];
if (entry)
fn(entry, data);
else
gf_msg_callingfn("circ-buff", GF_LOG_WARNING, 0,
LG_MSG_NULL_PTR,
"Null entry in "
"circular buffer at "
"index %d.",
index);
index++;
index %= buffer->size_buffer;
}
} else {
for (i = 0; i < buffer->used_len; i++) {
entry = buffer->cb[i];
fn(entry, data);
}
}
}
pthread_mutex_unlock(&buffer->lock);
}
buffer_t *
cb_buffer_new(size_t buffer_size, gf_boolean_t use_once,
void (*destroy_buffer_data)(void *data))
{
buffer_t *buffer = NULL;
buffer = GF_CALLOC(1, sizeof(*buffer), gf_common_mt_buffer_t);
if (!buffer) {
goto out;
}
buffer->cb = GF_CALLOC(buffer_size, sizeof(circular_buffer_t *),
gf_common_mt_circular_buffer_t);
if (!buffer->cb) {
GF_FREE(buffer);
buffer = NULL;
goto out;
}
buffer->w_index = 0;
buffer->size_buffer = buffer_size;
buffer->use_once = use_once;
buffer->used_len = 0;
buffer->destroy_buffer_data = destroy_buffer_data;
pthread_mutex_init(&buffer->lock, NULL);
out:
return buffer;
}
void
cb_buffer_destroy(buffer_t *buffer)
{
int i = 0;
circular_buffer_t *ptr = NULL;
if (buffer) {
if (buffer->cb) {
for (i = 0; i < buffer->used_len; i++) {
ptr = buffer->cb[i];
if (ptr->data) {
cb_destroy_data(ptr, buffer->destroy_buffer_data);
ptr->data = NULL;
GF_FREE(ptr);
}
}
GF_FREE(buffer->cb);
}
pthread_mutex_destroy(&buffer->lock);
GF_FREE(buffer);
}
}