source: bin/varnishd/storage_persistent.c @ e59c96

Revision e59c96, 29.7 KB checked in by Poul-Henning Kamp <phk@…>, 5 years ago (diff)

Various FlexeLint? silencing

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@4235 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2008-2009 Linpro AS
3 * All rights reserved.
4 *
5 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * Persistent storage method
29 *
30 * XXX: Before we start the client or maybe after it stops, we should give the
31 * XXX: stevedores a chance to examine their storage for consistency.
32 */
33
34#include "config.h"
35
36#include "svnid.h"
37SVNID("$Id$")
38
39#include <errno.h>
40#include <math.h>
41#include <stdio.h>
42#include <stddef.h>
43#include <stdint.h>
44#include <stdlib.h>
45#include <string.h>
46#include <sys/param.h>
47#include <sys/mman.h>
48
49#include "cache.h"
50#include "stevedore.h"
51#include "hash_slinger.h"
52#include "vsha256.h"
53
54#include "persistent.h"
55
56#ifndef MAP_NOCORE
57#define MAP_NOCORE 0 /* XXX Linux */
58#endif
59
60#ifndef MAP_NOSYNC
61#define MAP_NOSYNC 0 /* XXX Linux */
62#endif
63
64#define ASSERT_SILO_THREAD(sc) \
65    do {assert(pthread_self() == (sc)->thread);} while (0)
66
67/*
68 * Context for a signature.
69 *
70 * A signature is a sequence of bytes in the silo, signed by a SHA256 hash
71 * which follows the bytes.
72 *
73 * The context structure allows us to append to a signature without
74 * recalculating the entire SHA256 hash.
75 */
76
77struct smp_signctx {
78        struct smp_sign         *ss;
79        struct SHA256Context    ctx;
80        uint32_t                unique;
81        const char              *id;
82};
83
84struct smp_sc;
85
86/* XXX: name confusion with on-media version ? */
87struct smp_seg {
88        unsigned                magic;
89#define SMP_SEG_MAGIC           0x45c61895
90
91        struct smp_sc           *sc;
92        struct lru              *lru;
93
94        VTAILQ_ENTRY(smp_seg)   list;           /* on smp_sc.smp_segments */
95
96        uint64_t                offset;         /* coordinates in silo */
97        uint64_t                length;
98
99        struct smp_segment      segment;        /* Copy of on-disk desc. */
100
101        uint32_t                nalloc;         /* How many live objects */
102        uint32_t                nfixed;         /* How many fixed objects */
103
104        /* Only for open segment */
105        uint32_t                maxobj;         /* Max number of objects */
106        struct smp_object       *objs;          /* objdesc copy */
107        uint64_t                next_addr;      /* next write address */
108
109        struct smp_signctx      ctx[1];
110};
111
112VTAILQ_HEAD(smp_seghead, smp_seg);
113
114struct smp_sc {
115        unsigned                magic;
116#define SMP_SC_MAGIC            0x7b73af0a
117        struct stevedore        *parent;
118
119        unsigned                flags;
120#define SMP_F_LOADED            (1 << 0)
121
122        int                     fd;
123        const char              *filename;
124        off_t                   mediasize;
125        unsigned                granularity;
126        uint32_t                unique;
127
128        uint8_t                 *ptr;
129
130        struct smp_ident        *ident;
131
132        struct smp_seghead      segments;
133        struct smp_seg          *cur_seg;
134        uint64_t                objreserv;
135        pthread_t               thread;
136
137        VTAILQ_ENTRY(smp_sc)    list;
138
139        struct smp_signctx      idn;
140        struct smp_signctx      ban1;
141        struct smp_signctx      ban2;
142        struct smp_signctx      seg1;
143        struct smp_signctx      seg2;
144
145        struct ban              *tailban;
146
147        struct lock             mtx;
148
149        /* Cleaner metrics */
150
151        unsigned                min_nseg;
152        unsigned                aim_nseg;
153        unsigned                max_nseg;
154
155        unsigned                aim_nobj;
156
157        uint64_t                min_segl;
158        uint64_t                aim_segl;
159        uint64_t                max_segl;
160};
161
162/*
163 * silos is unlocked, it only changes during startup when we are
164 * single-threaded
165 */
166static VTAILQ_HEAD(,smp_sc)     silos = VTAILQ_HEAD_INITIALIZER(silos);
167
168/*********************************************************************
169 * SIGNATURE functions
170 * The signature is SHA256 over:
171 *    1. The smp_sign struct up to but not including the length field.
172 *    2. smp_sign->length bytes, starting after the smp_sign structure
173 *    3. The smp-sign->length field.
174 * The signature is stored after the byte-range from step 2.
175 */
176
177#define SIGN_DATA(ctx)  ((void *)((ctx)->ss + 1))
178#define SIGN_END(ctx)   ((void *)((int8_t *)SIGN_DATA(ctx) + (ctx)->ss->length))
179
180/*--------------------------------------------------------------------
181 * Define a signature by location and identifier.
182 */
183
184static void
185smp_def_sign(const struct smp_sc *sc, struct smp_signctx *ctx, uint64_t off, const char *id)
186{
187
188        AZ(off & 7);                    /* Alignment */
189        assert(strlen(id) < sizeof ctx->ss->ident);
190
191        memset(ctx, 0, sizeof ctx);
192        ctx->ss = (void*)(sc->ptr + off);
193        ctx->unique = sc->unique;
194        ctx->id = id;
195}
196
197/*--------------------------------------------------------------------
198 * Check that a signature is good, leave state ready for append
199 */
200static int
201smp_chk_sign(struct smp_signctx *ctx)
202{
203        struct SHA256Context cx;
204        unsigned char sign[SHA256_LEN];
205        int r = 0;
206
207        if (strcmp(ctx->id, ctx->ss->ident))
208                r = 1;
209        else if (ctx->unique != ctx->ss->unique)
210                r = 2;
211        else if ((uintptr_t)ctx->ss != ctx->ss->mapped)
212                r = 3;
213        else {
214                SHA256_Init(&ctx->ctx);
215                SHA256_Update(&ctx->ctx, ctx->ss,
216                    offsetof(struct smp_sign, length));
217                SHA256_Update(&ctx->ctx, SIGN_DATA(ctx), ctx->ss->length);
218                cx = ctx->ctx;
219                SHA256_Update(&cx, &ctx->ss->length, sizeof(ctx->ss->length));
220                SHA256_Final(sign, &cx);
221                if (memcmp(sign, SIGN_END(ctx), sizeof sign))
222                        r = 4;
223        } 
224        if (r) {
225                fprintf(stderr, "CHK(%p %p %s) = %d\n",
226                    ctx, ctx->ss, ctx->ss->ident, r);
227                fprintf(stderr, "%p {%s %x %p %ju}\n",
228                    ctx, ctx->id, ctx->unique, ctx->ss, ctx->ss->length);
229        }
230        return (r);
231}
232
233/*--------------------------------------------------------------------
234 * Append data to a signature
235 */
236static void
237smp_append_sign(struct smp_signctx *ctx, const void *ptr, uint32_t len)
238{
239        struct SHA256Context cx;
240        unsigned char sign[SHA256_LEN];
241
242        if (len != 0) {
243                SHA256_Update(&ctx->ctx, ptr, len);
244                ctx->ss->length += len;
245        }
246        cx = ctx->ctx;
247        SHA256_Update(&cx, &ctx->ss->length, sizeof(ctx->ss->length));
248        SHA256_Final(sign, &cx);
249        memcpy(SIGN_END(ctx), sign, sizeof sign);
250XXXAZ(smp_chk_sign(ctx));
251}
252
253/*--------------------------------------------------------------------
254 * Reset a signature to empty, prepare for appending.
255 */
256
257static void
258smp_reset_sign(struct smp_signctx *ctx)
259{
260
261        memset(ctx->ss, 0, sizeof *ctx->ss);
262        strcpy(ctx->ss->ident, ctx->id);
263        ctx->ss->unique = ctx->unique;
264        ctx->ss->mapped = (uintptr_t)ctx->ss;
265        SHA256_Init(&ctx->ctx);
266        SHA256_Update(&ctx->ctx, ctx->ss,
267            offsetof(struct smp_sign, length));
268        smp_append_sign(ctx, NULL, 0);
269}
270
271/*--------------------------------------------------------------------
272 * Force a write of a signature block to the backing store.
273 */
274
275static void
276smp_sync_sign(const struct smp_signctx *ctx)
277{
278        int i;
279
280        /* XXX: round to pages */
281        i = msync(ctx->ss, ctx->ss->length + SHA256_LEN, MS_SYNC);
282        if (i && 0)
283                fprintf(stderr, "SyncSign(%p %s) = %d %s\n",
284                    ctx->ss, ctx->id, i, strerror(errno));
285}
286
287/*--------------------------------------------------------------------
288 * Create and force a new signature to backing store
289 */
290
291static void
292smp_new_sign(const struct smp_sc *sc, struct smp_signctx *ctx, uint64_t off, const char *id)
293{
294        smp_def_sign(sc, ctx, off, id);
295        smp_reset_sign(ctx);
296        smp_sync_sign(ctx);
297}
298
299/*--------------------------------------------------------------------
300 * Caculate payload of some stuff
301 */
302
303static uint64_t
304smp_stuff_len(const struct smp_sc *sc, unsigned stuff)
305{
306        uint64_t l;
307
308        assert(stuff < SMP_END_STUFF);
309        l = sc->ident->stuff[stuff + 1] - sc->ident->stuff[stuff];
310        l -= SMP_SIGN_SPACE;
311        return (l);
312}
313
314/*--------------------------------------------------------------------
315 * Initialize a Silo with a valid but empty structure.
316 *
317 * XXX: more intelligent sizing of things.
318 */
319
320static void
321smp_newsilo(struct smp_sc *sc)
322{
323        struct smp_ident        *si;
324
325        ASSERT_MGT();
326        assert(strlen(SMP_IDENT_STRING) < sizeof si->ident);
327
328        /* Choose a new random number */
329        sc->unique = random();
330
331        smp_reset_sign(&sc->idn);
332        si = sc->ident;
333
334        memset(si, 0, sizeof *si);
335        strcpy(si->ident, SMP_IDENT_STRING);
336        si->byte_order = 0x12345678;
337        si->size = sizeof *si;
338        si->major_version = 1;
339        si->minor_version = 1;
340        si->unique = sc->unique;
341        si->mediasize = sc->mediasize;
342        si->granularity = sc->granularity;
343
344        si->stuff[SMP_BAN1_STUFF] = sc->granularity;
345        si->stuff[SMP_BAN2_STUFF] = si->stuff[SMP_BAN1_STUFF] + 1024*1024;
346        si->stuff[SMP_SEG1_STUFF] = si->stuff[SMP_BAN2_STUFF] + 1024*1024;
347        si->stuff[SMP_SEG2_STUFF] = si->stuff[SMP_SEG1_STUFF] + 1024*1024;
348        si->stuff[SMP_SPC_STUFF] = si->stuff[SMP_SEG2_STUFF] + 1024*1024;
349        si->stuff[SMP_END_STUFF] = si->mediasize;
350        assert(si->stuff[SMP_SPC_STUFF] < si->stuff[SMP_END_STUFF]);
351
352        smp_new_sign(sc, &sc->ban1, si->stuff[SMP_BAN1_STUFF], "BAN 1");
353        smp_new_sign(sc, &sc->ban2, si->stuff[SMP_BAN2_STUFF], "BAN 2");
354        smp_new_sign(sc, &sc->seg1, si->stuff[SMP_SEG1_STUFF], "SEG 1");
355        smp_new_sign(sc, &sc->seg2, si->stuff[SMP_SEG2_STUFF], "SEG 2");
356
357        smp_append_sign(&sc->idn, si, sizeof *si);
358        smp_sync_sign(&sc->idn);
359}
360
361/*--------------------------------------------------------------------
362 * Check if a silo is valid.
363 */
364
365static int
366smp_valid_silo(struct smp_sc *sc)
367{
368        struct smp_ident        *si;
369        int i, j;
370
371        assert(strlen(SMP_IDENT_STRING) < sizeof si->ident);
372
373        if (smp_chk_sign(&sc->idn))
374                return (1);
375
376        si = sc->ident;
377        if (strcmp(si->ident, SMP_IDENT_STRING))
378                return (2);
379        if (si->byte_order != 0x12345678)
380                return (3);
381        if (si->size != sizeof *si)
382                return (4);
383        if (si->major_version != 1)
384                return (5);
385        if (si->minor_version != 1)
386                return (6);
387        if (si->mediasize != sc->mediasize)
388                return (7);
389        if (si->granularity != sc->granularity)
390                return (8);
391        sc->unique = si->unique;
392
393        /* XXX: Sanity check stuff[6] */
394
395        assert(si->stuff[SMP_BAN1_STUFF] > sizeof *si + SHA256_LEN);
396        assert(si->stuff[SMP_BAN2_STUFF] > si->stuff[SMP_BAN1_STUFF]);
397        assert(si->stuff[SMP_SEG1_STUFF] > si->stuff[SMP_BAN2_STUFF]);
398        assert(si->stuff[SMP_SEG2_STUFF] > si->stuff[SMP_SEG1_STUFF]);
399        assert(si->stuff[SMP_SPC_STUFF] > si->stuff[SMP_SEG2_STUFF]);
400        assert(si->stuff[SMP_END_STUFF] == sc->mediasize);
401
402        assert(smp_stuff_len(sc, SMP_SEG1_STUFF) > 65536);
403        assert(smp_stuff_len(sc, SMP_SEG1_STUFF) ==
404          smp_stuff_len(sc, SMP_SEG2_STUFF));
405
406        assert(smp_stuff_len(sc, SMP_BAN1_STUFF) > 65536);
407        assert(smp_stuff_len(sc, SMP_BAN1_STUFF) ==
408          smp_stuff_len(sc, SMP_BAN2_STUFF));
409
410        smp_def_sign(sc, &sc->ban1, si->stuff[SMP_BAN1_STUFF], "BAN 1");
411        smp_def_sign(sc, &sc->ban2, si->stuff[SMP_BAN2_STUFF], "BAN 2");
412        smp_def_sign(sc, &sc->seg1, si->stuff[SMP_SEG1_STUFF], "SEG 1");
413        smp_def_sign(sc, &sc->seg2, si->stuff[SMP_SEG2_STUFF], "SEG 2");
414
415        /* We must have one valid BAN table */
416        i = smp_chk_sign(&sc->ban1);
417        j = smp_chk_sign(&sc->ban2);
418        if (i && j)
419                return (100 + i * 10 + j);
420
421        /* We must have one valid SEG table */
422        i = smp_chk_sign(&sc->seg1);
423        j = smp_chk_sign(&sc->seg2);
424        if (i && j)
425                return (200 + i * 10 + j);
426        return (0);
427}
428
429/*--------------------------------------------------------------------
430 * Calculate cleaner metrics from silo dimensions
431 */
432
433static void
434smp_metrics(struct smp_sc *sc)
435{
436
437        /*
438         * We do not want to loose too big chunks of the silos
439         * content when we are forced to clean a segment.
440         *
441         * For now insist that a segment covers no more than 1% of the silo.
442         *
443         * XXX: This should possibly depend on the size of the silo so
444         * XXX: trivially small silos do not run into trouble along
445         * XXX: the lines of "one object per silo".
446         */
447
448        sc->min_nseg = 10;
449        sc->max_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->min_nseg;
450
451        fprintf(stderr, "min_nseg = %u, max_segl = %ju\n",
452            sc->min_nseg, (uintmax_t)sc->max_segl);
453
454        /*
455         * The number of segments are limited by the size of the segment
456         * table(s) and from that follows the minimum size of a segmement.
457         */
458
459        sc->max_nseg = smp_stuff_len(sc, SMP_SEG1_STUFF) / sc->min_nseg;
460        sc->min_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->max_nseg;
461
462        while (sc->min_segl < sizeof(struct object)) {
463                sc->max_nseg /= 2;
464                sc->min_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->max_nseg;
465        }
466
467        fprintf(stderr, "max_nseg = %u, min_segl = %ju\n",
468            sc->max_nseg, (uintmax_t)sc->min_segl);
469
470        /*
471         * Set our initial aim point at the exponential average of the
472         * two extremes.
473         *
474         * XXX: This is a pretty arbitrary choice, but having no idea
475         * XXX: object count, size distribution or ttl pattern at this
476         * XXX: point, we have to do something.
477         */
478
479        sc->aim_nseg =
480           (unsigned) exp((log(sc->min_nseg) + log(sc->max_nseg))*.5);
481        sc->aim_segl = smp_stuff_len(sc, SMP_SPC_STUFF) / sc->aim_nseg;
482
483        fprintf(stderr, "aim_nseg = %u, aim_segl = %ju\n",
484            sc->aim_nseg, (uintmax_t)sc->aim_segl);
485
486        /*
487         * Objects per segment
488         *
489         * XXX: calculate size of minimum object (workspace, http etc)
490         */
491
492        sc->aim_nobj = sc->max_segl / 4000;
493
494        fprintf(stderr, "aim_nobj = %u\n", sc->aim_nobj);
495}
496
497/*--------------------------------------------------------------------
498 * Set up persistent storage silo in the master process.
499 */
500
501static void
502smp_init(struct stevedore *parent, int ac, char * const *av)
503{
504        struct smp_sc           *sc;
505        int i;
506       
507        ASSERT_MGT();
508
509        AZ(av[ac]);
510#define SIZOF(foo)       fprintf(stderr, \
511    "sizeof(%s) = %zu = 0x%zx\n", #foo, sizeof(foo), sizeof(foo));
512        SIZOF(struct smp_ident);
513        SIZOF(struct smp_sign);
514        SIZOF(struct smp_segptr);
515        SIZOF(struct smp_object);
516#undef SIZOF
517
518        assert(sizeof(struct smp_ident) == SMP_IDENT_SIZE);
519
520        /* Allocate softc */
521        ALLOC_OBJ(sc, SMP_SC_MAGIC);
522        XXXAN(sc);
523        sc->parent = parent;
524        sc->fd = -1;
525        VTAILQ_INIT(&sc->segments);
526
527        /* Argument processing */
528        if (ac != 2)
529                ARGV_ERR("(-spersistent) wrong number of arguments\n");
530
531        i = STV_GetFile(av[0], &sc->fd, &sc->filename, "-spersistent");
532        if (i == 2)
533                ARGV_ERR("(-spersistent) need filename (not directory)\n");
534
535        sc->granularity = getpagesize();
536        sc->mediasize = STV_FileSize(sc->fd, av[1], &sc->granularity,
537            "-spersistent");
538
539        AZ(ftruncate(sc->fd, sc->mediasize));
540
541        sc->ptr = mmap(NULL, sc->mediasize, PROT_READ|PROT_WRITE,
542            MAP_NOCORE | MAP_NOSYNC | MAP_SHARED, sc->fd, 0);
543
544        if (sc->ptr == MAP_FAILED)
545                ARGV_ERR("(-spersistent) failed to mmap (%s)\n",
546                    strerror(errno));
547
548        smp_def_sign(sc, &sc->idn, 0, "SILO");
549        sc->ident = SIGN_DATA(&sc->idn);
550
551        i = smp_valid_silo(sc);
552        if (i)
553                smp_newsilo(sc);
554        AZ(smp_valid_silo(sc));
555
556        smp_metrics(sc);
557
558        parent->priv = sc;
559
560        /* XXX: only for sendfile I guess... */
561        mgt_child_inherit(sc->fd, "storage_persistent");
562}
563
564
565/*--------------------------------------------------------------------
566 * Write the segmentlist back to the silo.
567 *
568 * We write the first copy, sync it synchronously, then write the
569 * second copy and sync it synchronously.
570 *
571 * Provided the kernel doesn't lie, that means we will always have
572 * at least one valid copy on in the silo.
573 */
574
575static void
576smp_save_seg(const struct smp_sc *sc, struct smp_signctx *ctx)
577{
578        struct smp_segptr *ss;
579        struct smp_seg *sg;
580        uint64_t length;
581
582        smp_reset_sign(ctx);
583        ss = SIGN_DATA(ctx);
584        length = 0;
585        VTAILQ_FOREACH(sg, &sc->segments, list) {
586                assert(sg->offset < sc->mediasize);
587                assert(sg->offset + sg->length <= sc->mediasize);
588                ss->offset = sg->offset;
589                ss->length = sg->length;
590                ss++;
591                length += sizeof *ss;
592        }
593        smp_append_sign(ctx, SIGN_DATA(ctx), length);
594        smp_sync_sign(ctx);
595}
596
597static void
598smp_save_segs(struct smp_sc *sc)
599{
600
601        smp_save_seg(sc, &sc->seg1);
602        smp_save_seg(sc, &sc->seg2);
603}
604
605/*--------------------------------------------------------------------
606 * Fixup an object
607 */
608
609void
610SMP_Fixup(struct sess *sp, struct objhead *oh, struct objcore *oc)
611{
612        struct smp_seg *sg;
613        struct smp_object *so;
614
615        Lck_AssertHeld(&oh->mtx);
616        (void)sp;
617        sg = oc->smp_seg;
618        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
619
620        so = (void*)oc->obj;
621        oc->obj = so->ptr;
622
623        /* XXX: This check should fail gracefully */
624        CHECK_OBJ_NOTNULL(oc->obj, OBJECT_MAGIC);
625
626        oc->obj->smp_object = so;
627
628        AN(oc->flags & OC_F_PERSISTENT);
629        oc->flags &= ~OC_F_PERSISTENT;
630
631        /* refcnt is one because the object is in the hash */
632        oc->obj->refcnt = 1;
633        oc->obj->objcore = oc;
634        oc->objhead = oh;
635        oc->obj->ban = oc->ban;
636
637        sg->nfixed++;
638        sp->wrk->stats.n_object++;
639        sp->wrk->stats.n_vampireobject--;
640}
641
642/*--------------------------------------------------------------------
643 * Add a new ban to all silos
644 */
645
646static void
647smp_appendban(struct smp_sc *sc, struct smp_signctx *ctx, double t0, uint32_t flags, uint32_t len, const char *ban)
648{
649        uint8_t *ptr, *ptr2;
650       
651        (void)sc;
652        ptr = ptr2 = SIGN_END(ctx);
653
654        memcpy(ptr, "BAN", 4);
655        ptr += 4;
656
657        memcpy(ptr, &t0, sizeof t0);
658        ptr += sizeof t0;
659
660        memcpy(ptr, &flags, sizeof flags);
661        ptr += sizeof flags;
662
663        memcpy(ptr, &len, sizeof len);
664        ptr += sizeof len;
665
666        memcpy(ptr, ban, len);
667        ptr += len;
668
669        smp_append_sign(ctx, ptr2, ptr - ptr2);
670}
671
672void
673SMP_NewBan(double t0, const char *ban)
674{
675        struct smp_sc *sc;
676        uint32_t l = strlen(ban) + 1;
677
678        VTAILQ_FOREACH(sc, &silos, list) {
679                smp_appendban(sc, &sc->ban1, t0, 0, l, ban);
680                smp_appendban(sc, &sc->ban2, t0, 0, l, ban);
681        }
682}
683
684/*--------------------------------------------------------------------
685 * Attempt to open and read in a ban list
686 */
687
688static int
689smp_open_bans(struct smp_sc *sc, struct smp_signctx *ctx)
690{
691        uint8_t *ptr, *pe;
692        double t0;
693        uint32_t flags, length;
694        int i, retval = 0;
695
696        ASSERT_CLI();
697        (void)sc;
698        i = smp_chk_sign(ctx); 
699        if (i)
700                return (i);
701        ptr = SIGN_DATA(ctx);
702        pe = ptr + ctx->ss->length;
703
704        while (ptr < pe) {
705                if (memcmp(ptr, "BAN", 4)) {
706                        retval = 1001;
707                        break;
708                }
709                ptr += 4;
710
711                memcpy(&t0, ptr, sizeof t0);
712                ptr += sizeof t0;
713
714                memcpy(&flags, ptr, sizeof flags);
715                ptr += sizeof flags;
716                if (flags != 0) {
717                        retval = 1002;
718                        break;
719                }
720
721                memcpy(&length, ptr, sizeof length);
722                ptr += sizeof length;
723                if (ptr + length > pe) {
724                        retval = 1003;
725                        break;
726                }
727
728                if (ptr[length - 1] != '\0') {
729                        retval = 1004;
730                        break;
731                }
732
733                BAN_Reload(t0, flags, (const char *)ptr);
734
735                ptr += length;
736        }
737        assert(ptr <= pe);
738        return (retval);
739}
740
741/*--------------------------------------------------------------------
742 * Update objects
743 */
744
745void
746SMP_FreeObj(struct object *o)
747{
748        struct smp_seg *sg;
749
750        AN(o->smp_object);
751        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
752        AZ(o->objcore->flags & OC_F_PERSISTENT);
753        sg = o->objcore->smp_seg;
754        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
755
756        o->smp_object->ttl = 0;
757        assert(sg->nalloc > 0);
758        sg->nalloc--;
759        sg->nfixed--;
760
761        /* XXX: check if seg is empty, or leave to thread ? */
762}
763
764void
765SMP_BANchanged(const struct object *o, double t)
766{
767        struct smp_seg *sg;
768
769        AN(o->smp_object);
770        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
771        sg = o->objcore->smp_seg;
772        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
773        CHECK_OBJ_NOTNULL(sg->sc, SMP_SC_MAGIC);
774
775        o->smp_object->ban = t;
776}
777
778void
779SMP_TTLchanged(const struct object *o)
780{
781        struct smp_seg *sg;
782
783        AN(o->smp_object);
784        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
785        sg = o->objcore->smp_seg;
786        CHECK_OBJ_NOTNULL(sg, SMP_SEG_MAGIC);
787        CHECK_OBJ_NOTNULL(sg->sc, SMP_SC_MAGIC);
788
789        o->smp_object->ttl = o->ttl;
790}
791
792/*--------------------------------------------------------------------
793 * Load segments
794 *
795 * The overall objective is to register the existence of an object, based
796 * only on the minimally sized struct smp_object, without causing the
797 * main object to be faulted in.
798 *
799 * XXX: We can test this by mprotecting the main body of the segment
800 * XXX: until the first fixup happens, or even just over this loop,
801 * XXX: However: the requires that the smp_objects starter further
802 * XXX: into the segment than a page so that they do not get hit
803 * XXX: by the protection.
804 */
805
806static void
807smp_load_seg(struct sess *sp, const struct smp_sc *sc, struct smp_seg *sg)
808{
809        void *ptr;
810        struct smp_segment *ss;
811        struct smp_object *so;
812        struct objcore *oc;
813        uint32_t no;
814        double t_now = TIM_real();
815        struct smp_signctx ctx[1];
816
817        ASSERT_SILO_THREAD(sc);
818        (void)sp;
819        AN(sg->offset);
820        smp_def_sign(sc, ctx, sg->offset, "SEGMENT");
821        if (smp_chk_sign(ctx))
822                return;
823        ptr = SIGN_DATA(ctx);
824        ss = ptr;
825        so = (void*)(sc->ptr + ss->objlist);
826        no = ss->nalloc;
827        for (;no > 0; so++,no--) {
828                if (so->ttl < t_now)
829                        continue;
830                HSH_Prealloc(sp);
831                oc = sp->wrk->nobjcore;
832                oc->flags |= OC_F_PERSISTENT | OC_F_LRUDONTMOVE;
833                oc->flags &= ~OC_F_BUSY;
834                oc->obj = (void*)so;
835                oc->smp_seg = sg;
836                oc->ban = BAN_RefBan(oc, so->ban, sc->tailban);
837                memcpy(sp->wrk->nobjhead->digest, so->hash, SHA256_LEN);
838                (void)HSH_Insert(sp);
839                AZ(sp->wrk->nobjcore);
840                EXP_Inject(oc, sg->lru, so->ttl);
841                sg->nalloc++;
842        }
843        WRK_SumStat(sp->wrk);
844}
845
846/*--------------------------------------------------------------------
847 * Attempt to open and read in a segment list
848 */
849
850static int
851smp_open_segs(struct smp_sc *sc, struct smp_signctx *ctx)
852{
853        uint64_t length;
854        struct smp_segptr *ss;
855        struct smp_seg *sg;
856        int i;
857
858        ASSERT_CLI();
859        i = smp_chk_sign(ctx); 
860        if (i)
861                return (i);
862        ss = SIGN_DATA(ctx);
863        length = ctx->ss->length;
864
865        for(; length > 0; length -= sizeof *ss, ss ++) {
866                ALLOC_OBJ(sg, SMP_SEG_MAGIC);
867                AN(sg);
868                sg->lru = LRU_Alloc();
869                sg->offset = ss->offset;
870                sg->length = ss->length;
871                /* XXX: check that they are inside silo */
872                /* XXX: check that they don't overlap */
873                /* XXX: check that they are serial */
874                sg->sc = sc;
875                VTAILQ_INSERT_TAIL(&sc->segments, sg, list);
876        }
877        return (0);
878}
879
880/*--------------------------------------------------------------------
881 * Create a new segment
882 */
883
884static void
885smp_new_seg(struct smp_sc *sc)
886{
887        struct smp_seg *sg, *sg2;
888
889        Lck_AssertHeld(&sc->mtx);
890        ALLOC_OBJ(sg, SMP_SEG_MAGIC);
891        AN(sg);
892
893        sg->maxobj = sc->aim_nobj;
894        sg->objs = malloc(sizeof *sg->objs * sg->maxobj);
895        AN(sg->objs);
896
897        /* XXX: find where it goes in silo */
898
899        sg2 = VTAILQ_LAST(&sc->segments, smp_seghead);
900        if (sg2 == NULL) {
901                sg->offset = sc->ident->stuff[SMP_SPC_STUFF];
902                assert(sc->ident->stuff[SMP_SPC_STUFF] < sc->mediasize);
903        } else {
904                sg->offset = sg2->offset + sg2->length;
905                assert(sg->offset < sc->mediasize);
906        }
907        sg->length = sc->aim_segl;
908        sg->length &= ~7;
909
910        assert(sg->offset + sg->length <= sc->mediasize);
911
912        VTAILQ_INSERT_TAIL(&sc->segments, sg, list);
913
914        /* Neuter the new segment in case there is an old one there */
915        AN(sg->offset);
916        smp_def_sign(sc, sg->ctx, sg->offset, "SEGMENT");
917        smp_reset_sign(sg->ctx);
918        memcpy(SIGN_DATA(sg->ctx), &sg->segment, sizeof sg->segment);
919        smp_append_sign(sg->ctx, &sg->segment, sizeof sg->segment);
920        smp_sync_sign(sg->ctx);
921
922        /* Then add it to the segment list. */
923        /* XXX: could be done cheaper with append ? */
924        smp_save_segs(sc);
925
926        /* Set up our allocation point */
927        sc->cur_seg = sg;
928        sg->next_addr = sg->offset +
929            sizeof (struct smp_sign) +
930            sizeof (struct smp_segment) +
931            SHA256_LEN;
932        memcpy(sc->ptr + sg->next_addr, "HERE", 4);
933        sc->objreserv = sizeof *sg->objs + SHA256_LEN;
934}
935
936/*--------------------------------------------------------------------
937 * Close a segment
938 */
939
940static void
941smp_close_seg(struct smp_sc *sc, struct smp_seg *sg)
942{
943        size_t sz;
944
945        (void)sc;
946
947        Lck_AssertHeld(&sc->mtx);
948
949        /* XXX: if segment is empty, delete instead */
950
951
952        /* Copy the objects into the segment */
953        sz = sizeof *sg->objs * sg->nalloc;
954        assert(sg->next_addr + sz <= sg->offset + sg->length);
955
956        memcpy(sc->ptr + sg->next_addr, sg->objs, sz);
957
958        /* Update the segment header */
959        sg->segment.objlist = sg->next_addr;
960        sg->segment.nalloc = sg->nalloc;
961
962        /* Write it to silo */
963        smp_reset_sign(sg->ctx);
964        memcpy(SIGN_DATA(sg->ctx), &sg->segment, sizeof sg->segment);
965        smp_append_sign(sg->ctx, &sg->segment, sizeof sg->segment);
966        smp_sync_sign(sg->ctx);
967
968        sg->next_addr += sizeof *sg->objs * sg->nalloc;
969        sg->length = sg->next_addr - sg->offset;
970        sg->length |= 15;
971        sg->length++;
972
973        /* Save segment list */
974        smp_save_segs(sc);
975
976}
977
978/*--------------------------------------------------------------------
979 * Silo worker thread
980 */
981
982static void *
983smp_thread(struct sess *sp, void *priv)
984{
985        struct smp_sc   *sc;
986        struct smp_seg *sg;
987
988        (void)sp;
989        CAST_OBJ_NOTNULL(sc, priv, SMP_SC_MAGIC);
990
991        /* First, load all the objects from all segments */
992        VTAILQ_FOREACH(sg, &sc->segments, list)
993                smp_load_seg(sp, sc, sg);
994
995        sc->flags |= SMP_F_LOADED;
996        BAN_Deref(&sc->tailban);
997        sc->tailban = NULL;
998        printf("Silo completely loaded\n");
999        while (1)       
1000                (void)sleep (1);
1001        NEEDLESS_RETURN(NULL);
1002}
1003
1004/*--------------------------------------------------------------------
1005 * Open a silo in the worker process
1006 */
1007
1008static void
1009smp_open(const struct stevedore *st)
1010{
1011        struct smp_sc   *sc;
1012
1013        ASSERT_CLI();
1014
1015        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
1016
1017        Lck_New(&sc->mtx);
1018        Lck_Lock(&sc->mtx);
1019
1020        /* We trust the parent to give us a valid silo, for good measure: */
1021        AZ(smp_valid_silo(sc));
1022
1023        sc->ident = SIGN_DATA(&sc->idn);
1024
1025        /* We attempt ban1 first, and if that fails, try ban2 */
1026        if (smp_open_bans(sc, &sc->ban1))
1027                AZ(smp_open_bans(sc, &sc->ban2));
1028
1029        /* We attempt seg1 first, and if that fails, try seg2 */
1030        if (smp_open_segs(sc, &sc->seg1))
1031                AZ(smp_open_segs(sc, &sc->seg2));
1032
1033        sc->tailban = BAN_TailRef();
1034        AN(sc->tailban);
1035
1036        /* XXX: save segments to ensure consistency between seg1 & seg2 ? */
1037
1038        /* XXX: abandon early segments to make sure we have free space ? */
1039
1040        /* Open a new segment, so we are ready to write */
1041        smp_new_seg(sc);
1042
1043        /* Start the worker silo worker thread, it will load the objects */
1044        WRK_BgThread(&sc->thread, "persistence", smp_thread, sc);
1045
1046        VTAILQ_INSERT_TAIL(&silos, sc, list);
1047        Lck_Unlock(&sc->mtx);
1048}
1049
1050/*--------------------------------------------------------------------
1051 * Close a silo
1052 */
1053
1054static void
1055smp_close(const struct stevedore *st)
1056{
1057        struct smp_sc   *sc;
1058
1059        ASSERT_CLI();
1060
1061        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
1062        Lck_Lock(&sc->mtx);
1063        smp_close_seg(sc, sc->cur_seg);
1064        Lck_Unlock(&sc->mtx);
1065
1066        /* XXX: reap thread */
1067}
1068
1069/*--------------------------------------------------------------------
1070 * Designate object
1071 */
1072
1073static void
1074smp_object(const struct sess *sp)
1075{
1076        struct smp_sc   *sc;
1077        struct smp_seg *sg;
1078        struct smp_object *so;
1079
1080        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
1081        CHECK_OBJ_NOTNULL(sp->obj->objstore, STORAGE_MAGIC);
1082        CHECK_OBJ_NOTNULL(sp->obj->objstore->stevedore, STEVEDORE_MAGIC);
1083        CAST_OBJ_NOTNULL(sc, sp->obj->objstore->priv, SMP_SC_MAGIC);
1084
1085        sp->obj->objcore->flags |= OC_F_LRUDONTMOVE;
1086        Lck_Lock(&sc->mtx);
1087        sg = sc->cur_seg;
1088        sc->objreserv += sizeof *so;
1089        if (sg->nalloc >= sg->maxobj) {
1090                smp_close_seg(sc, sc->cur_seg);
1091                smp_new_seg(sc);
1092                fprintf(stderr, "New Segment\n");
1093                sg = sc->cur_seg;
1094        }
1095        assert(sg->nalloc < sg->maxobj);
1096        so = &sg->objs[sg->nalloc++];
1097        memcpy(so->hash, sp->obj->objcore->objhead->digest, DIGEST_LEN);
1098        so->ttl = sp->obj->ttl;
1099        so->ptr = sp->obj;
1100        so->ban = sp->obj->ban_t;
1101        Lck_Unlock(&sc->mtx);
1102
1103}
1104
1105/*--------------------------------------------------------------------
1106 * Allocate a bite
1107 */
1108
1109static struct storage *
1110smp_alloc(struct stevedore *st, size_t size)
1111{
1112        struct smp_sc *sc;
1113        struct storage *ss;
1114        struct smp_seg *sg;
1115        size_t sz2;
1116
1117        CAST_OBJ_NOTNULL(sc, st->priv, SMP_SC_MAGIC);
1118
1119        Lck_Lock(&sc->mtx);
1120        sg = sc->cur_seg;
1121
1122        AN(sg->next_addr);
1123
1124        /*
1125         * XXX: We do not have a mechanism for deciding which allocations
1126         * XXX: have mandatory size and which can be chopped into smaller
1127         * XXX: allocations.
1128         * XXX: The primary unchoppable allocation is from HSH_NewObject()
1129         * XXX: which needs an object + workspace.
1130         */
1131        sz2 = sizeof (struct object) + 1024;
1132        if (size < sz2)
1133                sz2 = size;
1134
1135        /* If the segment is full, get a new one right away */
1136        if (sg->next_addr + sizeof *ss + sz2 + sc->objreserv >
1137             sg->offset + sg->length) {
1138                smp_close_seg(sc, sc->cur_seg);
1139                smp_new_seg(sc);
1140                sg = sc->cur_seg;
1141        }
1142
1143        assert (sg->next_addr + sizeof *ss + sz2 + sc->objreserv <=
1144            sg->offset + sg->length);
1145
1146        if (sg->next_addr + sizeof *ss + size + sc->objreserv >
1147            sg->offset + sg->length)
1148                size = (sg->offset + sg->length) -
1149                        (sg->next_addr + sizeof *ss + sc->objreserv);
1150
1151        ss = (void *)(sc->ptr + sg->next_addr);
1152
1153        sg->next_addr += size + sizeof *ss;
1154        assert(sg->next_addr <= sg->offset + sg->length);
1155        memcpy(sc->ptr + sg->next_addr, "HERE", 4);
1156        Lck_Unlock(&sc->mtx);
1157
1158        /* Grab and fill a storage structure */
1159        memset(ss, 0, sizeof *ss);
1160        ss->magic = STORAGE_MAGIC;
1161        ss->space = size;
1162        ss->ptr = (void *)(ss + 1);
1163        ss->priv = sc;
1164        ss->stevedore = st;
1165        ss->fd = sc->fd;
1166        ss->where = sg->next_addr + sizeof *ss;
1167        assert((uintmax_t)ss->space == (uintmax_t)size);
1168        assert((char*)ss->ptr > (char*)ss);
1169        assert((char*)ss->ptr + ss->space <= (char*)sc->ptr + sc->mediasize);
1170        return (ss);
1171}
1172
1173static void
1174smp_trim(struct storage *ss, size_t size)
1175{
1176        struct smp_sc *sc;
1177        struct smp_seg *sg;
1178        const char z[4] = { 0, 0, 0, 0};
1179
1180        return;
1181
1182        CAST_OBJ_NOTNULL(sc, ss->priv, SMP_SC_MAGIC);
1183
1184        /* We want 16 bytes alignment */
1185        size |= 0xf;
1186        size += 1;
1187
1188        sg = sc->cur_seg;
1189        if (ss->ptr + ss->space != sg->next_addr + sc->ptr) 
1190                return;
1191
1192        Lck_Lock(&sc->mtx);
1193        sg = sc->cur_seg;
1194        if (ss->ptr + ss->space == sg->next_addr + sc->ptr) {
1195                memcpy(sc->ptr + sg->next_addr, z, 4);
1196                sg->next_addr -= ss->space - size;
1197                ss->space = size;
1198                memcpy(sc->ptr + sg->next_addr, "HERE", 4);
1199        }
1200        Lck_Unlock(&sc->mtx);
1201}
1202
1203/*--------------------------------------------------------------------
1204 * We don't track frees of storage, we track the objects which own them
1205 * instead, when there are no more objects in in the first segment, it
1206 * can be reclaimed.
1207 */
1208
1209static void
1210smp_free(struct storage *st)
1211{
1212
1213        /* XXX */
1214        (void)st;
1215}
1216
1217/*--------------------------------------------------------------------
1218 * Pause until all silos have loaded.
1219 */
1220
1221void
1222SMP_Ready(void)
1223{
1224        struct smp_sc *sc;
1225
1226        ASSERT_CLI();
1227        while (1) {
1228                VTAILQ_FOREACH(sc, &silos, list) {
1229                        if (sc->flags & SMP_F_LOADED)
1230                                continue;
1231                        (void)sleep(1);
1232                        break;
1233                }
1234                if (sc == NULL)
1235                        break;
1236        }
1237}
1238
1239/*--------------------------------------------------------------------*/
1240
1241struct stevedore smp_stevedore = {
1242        .magic  =       STEVEDORE_MAGIC,
1243        .name   =       "persistent",
1244        .init   =       smp_init,
1245        .open   =       smp_open,
1246        .close  =       smp_close,
1247        .alloc  =       smp_alloc,
1248        .object =       smp_object,
1249        .free   =       smp_free,
1250        .trim   =       smp_trim,
1251};
Note: See TracBrowser for help on using the repository browser.