X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Futil.c;h=5412963cefc31efd18f84ab18ad7d27d8e0a662a;hb=8ff0fd08d6e1cc97cdb7e94b7cd97dc28c29e674;hp=c4bac1972df323bad0b5d192a494f7a1401e8ffd;hpb=a8a9f2181e2e16d24d812ea1e7a7c8af42f0d2f1;p=bluesky.git diff --git a/bluesky/util.c b/bluesky/util.c index c4bac19..5412963 100644 --- a/bluesky/util.c +++ b/bluesky/util.c @@ -3,14 +3,40 @@ * Copyright (C) 2009 The Regents of the University of California * Written by Michael Vrable * - * TODO: Licensing + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ +#define _GNU_SOURCE #include #include #include #include +#include #include +#include +#include #include "bluesky-private.h" @@ -53,17 +79,6 @@ gboolean bluesky_inode_is_ready(BlueSkyInode *inode) /**** Reference-counted strings. ****/ -void bluesky_mmap_unref(BlueSkyMmap *mmap) -{ - if (mmap == NULL) - return; - - if (g_atomic_int_dec_and_test(&mmap->refcount)) { - munmap((void *)mmap->addr, mmap->len); - g_free(mmap); - } -} - /* Create and return a new reference-counted string. The reference count is * initially one. The newly-returned string takes ownership of the memory * pointed at by data, and will call g_free on it when the reference count @@ -86,12 +101,15 @@ BlueSkyRCStr *bluesky_string_new_from_gstring(GString *s) } /* Create a new BlueSkyRCStr from a memory-mapped buffer. */ -BlueSkyRCStr *bluesky_string_new_from_mmap(BlueSkyMmap *mmap, +BlueSkyRCStr *bluesky_string_new_from_mmap(BlueSkyCacheFile *mmap, int offset, gsize len) { + g_assert(offset + len <= mmap->len); + g_assert(mmap->addr != NULL); + BlueSkyRCStr *string = g_new(BlueSkyRCStr, 1); string->mmap = mmap; - g_atomic_int_inc(&mmap->refcount); + g_atomic_int_inc(&mmap->mapcount); string->data = (char *)mmap->addr + offset; string->len = len; g_atomic_int_set(&string->refcount, 1); @@ -228,3 +246,228 @@ BlueSkyInode *bluesky_list_tail(GList *head) else return (BlueSkyInode *)head->prev->data; } + +/**** Range sets. ****/ + +/* These are a data structure which can track a set of discontiguous integer + * ranges--such as the partitioning of the inode number space or the bytes in a + * log file into objects. This current prototype implementation just tracks + * the starting offset with a hash table and doesn't track the length, but + * should be extended later to track properly. */ + +struct BlueSkyRangeset { + GSequence *seq; +}; + +static gint compare64(gconstpointer a, gconstpointer b, gpointer user_data) +{ + uint64_t x = *(uint64_t *)a; + uint64_t y = *(uint64_t *)b; + + if (x < y) + return -1; + else if (x > y) + return 1; + else + return 0; +} + +BlueSkyRangeset *bluesky_rangeset_new() +{ + BlueSkyRangeset *rangeset = g_new(BlueSkyRangeset, 1); + rangeset->seq = g_sequence_new(g_free); + return rangeset; +} + +void bluesky_rangeset_free(BlueSkyRangeset *rangeset) +{ + g_sequence_free(rangeset->seq); + g_free(rangeset); +} + +gboolean bluesky_rangeset_insert(BlueSkyRangeset *rangeset, + uint64_t start, uint64_t length, + gpointer data) +{ + GSequenceIter *i; + i = g_sequence_search(rangeset->seq, &start, compare64, NULL); + i = g_sequence_iter_prev(i); + + /* TODO: Checks that no other item overlaps. */ + + BlueSkyRangesetItem *item = g_new(BlueSkyRangesetItem, 1); + item->start = start; + item->length = length; + item->data = data; + g_sequence_insert_sorted(rangeset->seq, item, compare64, NULL); + + return TRUE; +} + +const BlueSkyRangesetItem *bluesky_rangeset_lookup(BlueSkyRangeset *rangeset, + uint64_t offset) +{ + GSequenceIter *i; + i = g_sequence_search(rangeset->seq, &offset, compare64, NULL); + i = g_sequence_iter_prev(i); + if (g_sequence_iter_is_end(i)) + return NULL; + + BlueSkyRangesetItem *item = (BlueSkyRangesetItem *)g_sequence_get(i); + if (offset >= item->start && offset < item->start + item->length) + return item; + else + return NULL; +} + +/* Look up the first rangeset item starting at or following the given address. + * Can be used to iterate through a rangeset. */ +const BlueSkyRangesetItem *bluesky_rangeset_lookup_next(BlueSkyRangeset *rangeset, uint64_t offset) +{ + GSequenceIter *i; + i = g_sequence_search(rangeset->seq, &offset, compare64, NULL); + i = g_sequence_iter_prev(i); + if (g_sequence_iter_is_end(i)) + return NULL; + BlueSkyRangesetItem *item = (BlueSkyRangesetItem *)g_sequence_get(i); + if (item->start < offset) { + i = g_sequence_iter_next(i); + if (g_sequence_iter_is_end(i)) + item = NULL; + else + item = (BlueSkyRangesetItem *)g_sequence_get(i); + } + return item; +} + +/* Determine the full extent of a rangeset--the smallest offset covered and the + * length needed to extend to the end of the last item. */ +void bluesky_rangeset_get_extents(BlueSkyRangeset *rangeset, + uint64_t *start, uint64_t *length) +{ + GSequenceIter *i; + BlueSkyRangesetItem *item; + + i = g_sequence_get_begin_iter(rangeset->seq); + if (g_sequence_iter_is_end(i)) { + *start = 0; + *length = 0; + return; + } + + item = (BlueSkyRangesetItem *)g_sequence_get(i); + *start = item->start; + + i = g_sequence_get_end_iter(rangeset->seq); + i = g_sequence_iter_prev(i); + item = (BlueSkyRangesetItem *)g_sequence_get(i); + *length = (item->start + item->length) - *start; +} + +/**** Request response-time tracking. ****/ +/* TODO: Locking */ +typedef struct { + int tid; + bluesky_time_hires timestamp; + char *message; +} RTEvent; + +/* To catch attempts to access to invalid profile structures. */ +#define PROFILE_MAGIC 0x439929d8 + +static FILE *profiling_file = NULL; + +BlueSkyProfile *bluesky_profile_new() +{ + BlueSkyProfile *profile = g_new0(BlueSkyProfile, 1); + profile->lock = g_mutex_new(); + profile->magic = PROFILE_MAGIC; + return profile; +} + +void bluesky_profile_free(BlueSkyProfile *profile) +{ + if (profile->magic != PROFILE_MAGIC) { + g_warning("Access to invalid BlueSkyProfile object!"); + return; + } + while (profile->events != NULL) { + RTEvent *event = (RTEvent *)profile->events->data; + g_free(event->message); + g_free(event); + profile->events = g_list_delete_link(profile->events, profile->events); + } + profile->magic = 0; + g_mutex_free(profile->lock); + g_free(profile->description); + g_free(profile); +} + +void bluesky_profile_add_event(BlueSkyProfile *profile, char *message) +{ + if (profiling_file == NULL) + return; + + g_return_if_fail(profile != NULL); + + if (profile->magic != PROFILE_MAGIC) { + g_warning("Access to invalid BlueSkyProfile object!"); + return; + } + g_mutex_lock(profile->lock); + RTEvent *event = g_new(RTEvent, 1); + event->timestamp = bluesky_now_hires(); + /* FIXME: Non-portable */ + event->tid = syscall(SYS_gettid); + event->message = message; + profile->events = g_list_prepend(profile->events, event); + g_mutex_unlock(profile->lock); +} + +static GStaticMutex profiling_print_lock = G_STATIC_MUTEX_INIT; + +void bluesky_profile_set_output(FILE *stream) +{ + profiling_file = stream; +} + +void bluesky_profile_print(BlueSkyProfile *profile) +{ + FILE *stream = profiling_file; + if (stream == NULL) + return; + + g_return_if_fail(profile != NULL); + + if (profile->magic != PROFILE_MAGIC) { + g_warning("Access to invalid BlueSkyProfile object!"); + return; + } + + g_mutex_lock(profile->lock); + g_static_mutex_lock(&profiling_print_lock); + fprintf(stream, "Event Timeline: %s\n", profile->description); + GList *link = g_list_last(profile->events); + bluesky_time_hires last_time = 0; + while (link != NULL) { + RTEvent *event = (RTEvent *)link->data; + fprintf(stream, " [%d] [%"PRIi64" ns]: %s\n", + event->tid, event->timestamp - last_time, event->message); + last_time = event->timestamp; + link = link->prev; + } + g_static_mutex_unlock(&profiling_print_lock); + g_mutex_unlock(profile->lock); +} + +static GStaticPrivate per_thread_profile = G_STATIC_PRIVATE_INIT; + +BlueSkyProfile *bluesky_profile_get() +{ + return (BlueSkyProfile *)g_static_private_get(&per_thread_profile); +} + +void bluesky_profile_set(BlueSkyProfile *profile) +{ + g_static_private_set(&per_thread_profile, profile, NULL); +}