Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <venti.h>

char *VtServerLog = "libventi/server";

int ventilogging;
#define log     not_the_log_library_call

static char Eremoved[] = "[removed]";

enum
{       /* defaults */
        LogChunkSize = 8192,
        LogSize = 65536
};

static struct {
        QLock lk;
        VtLog *hash[1024];
} vl;

static uint
hash(char *s)
{
        uint h;
        uchar *p;

        h = 0;
        for(p=(uchar*)s; *p; p++)
                h = h*37 + *p;
        return h;
}

char**
vtlognames(int *pn)
{
        int i, nname, size;
        VtLog *l;
        char **s, *a, *e;
        
        qlock(&vl.lk);
        size = 0;
        nname = 0;
        for(i=0; i<nelem(vl.hash); i++)
        for(l=vl.hash[i]; l; l=l->next){
                nname++;
                size += strlen(l->name)+1;
        }
        
        s = vtmalloc(nname*sizeof(char*)+size);
        a = (char*)(s+nname);
        e = (char*)s+nname*sizeof(char*)+size;

        nname = 0;
        for(i=0; i<nelem(vl.hash); i++)
        for(l=vl.hash[i]; l; l=l->next){
                strcpy(a, l->name);
                s[nname++] = a;
                a += strlen(a)+1;
        }
        *pn = nname;
        assert(a == e);
        qunlock(&vl.lk);

        return s;
}

VtLog*
vtlogopen(char *name, uint size)
{
        uint h;
        int i, nc;
        char *p;
        VtLog *l, *last;

        if(!ventilogging)
                return nil;

        h = hash(name)%nelem(vl.hash);
        qlock(&vl.lk);
        last = nil;
        for(l=vl.hash[h]; l; last=l, l=l->next)
                if(strcmp(l->name, name) == 0){
                        if(last){       /* move to front */
                                last->next = l->next;
                                l->next = vl.hash[h];
                                vl.hash[h] = l;
                        }
                        l->ref++;
                        qunlock(&vl.lk);
                        return l;
                }

        if(size == 0){
                qunlock(&vl.lk);
                return nil;
        }

        /* allocate */
        nc = (size+LogChunkSize-1)/LogChunkSize;
        l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1);
        memset(l, 0, sizeof *l);
        l->chunk = (VtLogChunk*)(l+1);
        l->nchunk = nc;
        l->w = l->chunk;
        p = (char*)(l->chunk+nc);
        for(i=0; i<nc; i++){
                l->chunk[i].p = p;
                l->chunk[i].wp = p;
                p += LogChunkSize;
                l->chunk[i].ep = p;
        }
        strcpy(p, name);
        l->name = p;
        
        /* insert */
        l->next = vl.hash[h];
        vl.hash[h] = l;
        l->ref++;
        
        l->ref++;
        qunlock(&vl.lk);
        return l;
}

void
vtlogclose(VtLog *l)
{
        if(l == nil)
                return;

        qlock(&vl.lk);
        if(--l->ref == 0){
                /* must not be in hash table */
                assert(l->name == Eremoved);
                free(l);
        }else
                assert(l->ref > 0);
        qunlock(&vl.lk);
}

void
vtlogremove(char *name)
{
        uint h;
        VtLog *last, *l;

        h = hash(name)%nelem(vl.hash);
        qlock(&vl.lk);
        last = nil;
        for(l=vl.hash[h]; l; last=l, l=l->next)
                if(strcmp(l->name, name) == 0){
                        if(last)
                                last->next = l->next;
                        else
                                vl.hash[h] = l->next;
                        l->name = Eremoved;
                        l->next = nil;
                        qunlock(&vl.lk);
                        vtlogclose(l);
                        return;
                }
        qunlock(&vl.lk);
}

static int
timefmt(Fmt *fmt)
{
        static uvlong t0;
        uvlong t;

        if(t0 == 0)
                t0 = nsec();
        t = nsec()-t0;
        return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
}

void
vtlogvprint(VtLog *l, char *fmt, va_list arg)
{
        int n;
        char *p;
        VtLogChunk *c;
        static int first = 1;

        if(l == nil)
                return;
                
        if(first){
                fmtinstall('T', timefmt);
                first = 0;
        }
                
        
        qlock(&l->lk);
        c = l->w;
        n = c->ep - c->wp;
        if(n < 512){
                c++;
                if(c == l->chunk+l->nchunk)
                        c = l->chunk;
                c->wp = c->p;
                l->w = c;
        }
        p = vseprint(c->wp, c->ep, fmt, arg);
        if(p)
                c->wp = p;
        qunlock(&l->lk);
}

void
vtlogprint(VtLog *l, char *fmt, ...)
{
        va_list arg;
        
        if(l == nil)
                return;
                
        va_start(arg, fmt);
        vtlogvprint(l, fmt, arg);
        va_end(arg);
}

void
vtlog(char *name, char *fmt, ...)
{
        VtLog *l;
        va_list arg;

        l = vtlogopen(name, LogSize);
        if(l == nil)
                return;
        va_start(arg, fmt);
        vtlogvprint(l, fmt, arg);
        va_end(arg);
        vtlogclose(l);
}

void
vtlogdump(int fd, VtLog *l)
{
        int i;
        VtLogChunk *c;

        if(l == nil)
                return;
                
        c = l->w;
        for(i=0; i<l->nchunk; i++){
                if(++c == l->chunk+l->nchunk)
                        c = l->chunk;
                write(fd, c->p, c->wp-c->p);
        }
}