varnish-cache/bin/varnishd/cache/cache_obj.c
0
/*-
1
 * Copyright (c) 2013-2016 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * Lifetime of an objcore:
30
 *      phase 0 - nonexistent
31
 *      phase 1 - created, but no stevedore associated
32
 *      phase 2 - stevedore associated, being filled out
33
 *      phase 3 - stable, no changes happening
34
 *      phase 4 - unavailable, being dismantled
35
 *      phase 5 - stevedore disassociated
36
 *      phase 6 - nonexistent
37
 *
38
 * 0->1 ObjNew()        creates objcore
39
 *
40
 * 1->2 STV_NewObject() associates a stevedore
41
 *
42
 * 2    ObjSetState()   sets state
43
 * 2    ObjWaitState()  waits for particular state
44
 *                      INVALID->REQ_DONE->STREAM->FINISHED->FAILED
45
 *
46
 * 2    ObjGetSpace()   allocates space
47
 * 2    ObjExtend()     commits content
48
 * 2    ObjWaitExtend() waits for content - used to implement ObjIterate())
49
 *
50
 * 2    ObjSetAttr()
51
 * 2      ObjCopyAttr()
52
 * 2      ObjSetFlag()
53
 * 2      ObjSetDouble()
54
 * 2      ObjSetU32()
55
 * 2      ObjSetU64()
56
 *
57
 * 2->3 ObjBocDone()    Boc removed from OC, clean it up
58
 *
59
 * 23   ObjHasAttr()
60
 * 23   ObjGetAttr()
61
 * 23     ObjCheckFlag()
62
 * 23     ObjGetDouble()
63
 * 23     ObjGetU32()
64
 * 23     ObjGetU64()
65
 * 23     ObjGetLen()
66
 * 23     ObjGetXID()
67
 *
68
 * 23   ObjIterate()    ... over body
69
 *
70
 * 23   ObjTouch()      Signal to LRU(-like) facilities
71
 *
72
 * 3->4 HSH_Snipe()     kill if not in use
73
 * 3->4 HSH_Kill()      make unavailable
74
 *
75
 * 234  ObjSlim()       Release body storage (but retain attribute storage)
76
 *
77
 * 4->5 ObjFreeObj()    disassociates stevedore
78
 *
79
 * 5->6 FREE_OBJ()      ...in HSH_DerefObjCore()
80
 */
81
82
#include "config.h"
83
84
#include <stdlib.h>
85
86
#include "cache_varnishd.h"
87
#include "cache_obj.h"
88
#include "cache_objhead.h"
89
#include "vend.h"
90
#include "storage/storage.h"
91
92
static const struct obj_methods *
93 6523829
obj_getmethods(const struct objcore *oc)
94
{
95
96 6523829
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
97 6523829
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
98 6523829
        AN(oc->stobj->stevedore->methods);
99 6523829
        return (oc->stobj->stevedore->methods);
100
}
101
102
static struct boc *
103 130219
obj_newboc(void)
104
{
105
        struct boc *boc;
106
107 130219
        ALLOC_OBJ(boc, BOC_MAGIC);
108 130219
        AN(boc);
109 130219
        Lck_New(&boc->mtx, lck_busyobj);
110 130219
        PTOK(pthread_cond_init(&boc->cond, NULL));
111 130219
        boc->refcount = 1;
112 130219
        return (boc);
113
}
114
115
static void
116 118730
obj_deleteboc(struct boc **p)
117
{
118
        struct boc *boc;
119
120 118730
        TAKE_OBJ_NOTNULL(boc, p, BOC_MAGIC);
121 118730
        Lck_Delete(&boc->mtx);
122 118730
        PTOK(pthread_cond_destroy(&boc->cond));
123 118730
        free(boc->vary);
124 118730
        FREE_OBJ(boc);
125 118730
}
126
127
/*====================================================================
128
 * ObjNew()
129
 *
130
 */
131
132
struct objcore *
133 130213
ObjNew(const struct worker *wrk)
134
{
135
        struct objcore *oc;
136
137 130213
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138
139 130213
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
140 130213
        AN(oc);
141 130213
        wrk->stats->n_objectcore++;
142 130213
        oc->last_lru = NAN;
143 130213
        oc->boc = obj_newboc();
144
145 130213
        return (oc);
146
}
147
148
/*====================================================================
149
 * ObjDestroy()
150
 *
151
 */
152
153
void
154 75472
ObjDestroy(const struct worker *wrk, struct objcore **p)
155
{
156
        struct objcore *oc;
157
158 75472
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
159 75472
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
160 75472
        if (oc->boc != NULL)
161 1493
                obj_deleteboc(&oc->boc);
162 75472
        FREE_OBJ(oc);
163 75472
        wrk->stats->n_objectcore--;
164 75472
}
165
166
/*====================================================================
167
 * ObjIterate()
168
 *
169
 */
170
171
int
172 98183
ObjIterate(struct worker *wrk, struct objcore *oc,
173
    void *priv, objiterate_f *func, int final)
174
{
175 98183
        const struct obj_methods *om = obj_getmethods(oc);
176
177 98183
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
178 98183
        AN(func);
179 98183
        AN(om->objiterator);
180 98183
        return (om->objiterator(wrk, oc, priv, func, final));
181
}
182
183
/*====================================================================
184
 * ObjVAI...(): Asynchronous Iteration
185
 *
186
 *
187
 * ObjVAIinit() returns an opaque handle, or NULL if not supported
188
 *
189
 *      A VAI handle must not be used concurrently
190
 *
191
 *      the vai_notify_cb(priv) will be called asynchronously by the storage
192
 *      engine when a -EAGAIN / -ENOBUFS condition is over and ObjVAIlease()
193
 *      can be called again.
194
 *
195
 *      Note:
196
 *      - the callback gets executed by an arbitrary thread
197
 *      - WITH the boc mtx held
198
 *      so it should never block and only do minimal work
199
 *
200
 * ObjVAIlease() fills the vscarab with leases. returns:
201
 *
202
 *      -EAGAIN:  nothing available at the moment, storage will notify, no use to
203
 *                call again until notification
204
 *      -ENOBUFS: caller needs to return leases, storage will notify
205
 *      -EPIPE:   BOS_FAILED for busy object
206
 *      -(errno): other problem, fatal
207
 *
208
 *      >= 0:     number of viovs added (== scarab->capacity - scarab->used)
209
 *
210
 *      struct vscarab:
211
 *
212
 *      the leases can be used by the caller until returned with
213
 *      ObjVAIreturn(). The storage guarantees that the lease member is a
214
 *      multiple of 8 (that is, the lower three bits are zero). These can be
215
 *      used by the caller between lease and return, but must be cleared to
216
 *      zero before returning.
217
 *
218
 * ObjVAIbuffer() allocates temporary buffers, returns:
219
 *
220
 *      -EAGAIN:  allocation can not be fulfilled immediately, storage will notify,
221
 *                no use to call again until notification
222
 *      -EINVAL:  size larger than UINT_MAX requested
223
 *      -(errno): other problem, fatal
224
 *      n:        n > 0, number of viovs filled
225
 *
226
 *      The struct vscarab is used on the way in and out: On the way in, the
227
 *      iov.iov_len members contain the sizes the caller requests, all other
228
 *      members of the struct viovs are expected to be zero initialized.
229
 *
230
 *      The maximum size to be requested is UINT_MAX.
231
 *
232
 *      ObjVAIbuffer() may return sizes larger than requested. The returned n
233
 *      might be smaller than requested.
234
 *
235
 * ObjVAIreturn() returns leases collected in a struct vscaret
236
 *
237
 *      it must be called with a vscaret, which holds an array of lease values
238
 *      received via ObjVAIlease() or ObjVAIbuffer() when the caller can
239
 *      guarantee that they are no longer accessed.
240
 *
241
 *      ObjVAIreturn() may retain leases in the vscaret if the implementation
242
 *      still requires them, iow, the vscaret might not be empty upon return.
243
 *
244
 * ObjVAIfini() finalized iteration
245
 *
246
 *      it must be called when iteration is done, irrespective of error status
247
 */
248
249
vai_hdl
250 99474
ObjVAIinit(struct worker *wrk, struct objcore *oc, struct ws *ws,
251
    vai_notify_cb *cb, void *cb_priv)
252
{
253 99474
        const struct obj_methods *om = obj_getmethods(oc);
254
255 99474
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
256
257 99474
        if (om->vai_init == NULL)
258 0
                return (NULL);
259 99474
        return (om->vai_init(wrk, oc, ws, cb, cb_priv));
260 99474
}
261
262
int
263 270349
ObjVAIlease(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
264
{
265 270349
        struct vai_hdl_preamble *vaip = vhdl;
266
267 270349
        AN(vaip);
268 270349
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
269 270349
        AN(vaip->vai_lease);
270 270349
        return (vaip->vai_lease(wrk, vhdl, scarab));
271
}
272
273
int
274 640
ObjVAIbuffer(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
275
{
276 640
        struct vai_hdl_preamble *vaip = vhdl;
277
278 640
        AN(vaip);
279 640
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
280 640
        AN(vaip->vai_buffer);
281 640
        return (vaip->vai_buffer(wrk, vhdl, scarab));
282
}
283
284
void
285 120671
ObjVAIreturn(struct worker *wrk, vai_hdl vhdl, struct vscaret *scaret)
286
{
287 120671
        struct vai_hdl_preamble *vaip = vhdl;
288
289 120671
        AN(vaip);
290 120671
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
291 120671
        AN(vaip->vai_return);
292 120671
        vaip->vai_return(wrk, vhdl, scaret);
293 120671
}
294
295
void
296 99465
ObjVAIfini(struct worker *wrk, vai_hdl *vhdlp)
297
{
298 99465
        AN(vhdlp);
299 99465
        struct vai_hdl_preamble *vaip = *vhdlp;
300
301 99465
        AN(vaip);
302 99465
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
303 99465
        AN(vaip->vai_lease);
304 99465
        vaip->vai_fini(wrk, vhdlp);
305 99465
}
306
307
/*====================================================================
308
 * ObjGetSpace()
309
 *
310
 * This function returns a pointer and length of free space.  If there
311
 * is no free space, some will be added first.
312
 *
313
 * The "sz" argument is an input hint of how much space is desired.
314
 * 0 means "unknown", return some default size (maybe fetch_chunksize)
315
 */
316
317
int
318 2322569
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
319
{
320 2322569
        const struct obj_methods *om = obj_getmethods(oc);
321
322 2322569
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
323 2322569
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
324 2322569
        AN(sz);
325 2322569
        AN(ptr);
326 2322569
        assert(*sz >= 0);
327
328 2322569
        AN(om->objgetspace);
329 2322569
        return (om->objgetspace(wrk, oc, sz, ptr));
330
}
331
332
/*====================================================================
333
 * ObjExtend()
334
 *
335
 * This function extends the used part of the object a number of bytes
336
 * into the last space returned by ObjGetSpace()
337
 *
338
 * The final flag must be set on the last call, and it will release any
339
 * surplus space allocated.
340
 */
341
342
static void
343 2264128
obj_extend_condwait(const struct objcore *oc)
344
{
345
346 2264128
        if (oc->boc->transit_buffer == 0)
347 2244369
                return;
348
349 19759
        assert(oc->flags & OC_F_TRANSIENT);
350 21547
        while (!(oc->flags & OC_F_CANCEL) && oc->boc->fetched_so_far >
351 21467
            oc->boc->delivered_so_far + oc->boc->transit_buffer)
352 1788
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
353 2264128
}
354
355
// notify of an extension of the boc or state change
356
357
static void
358 2392889
obj_boc_notify(struct boc *boc)
359
{
360
        struct vai_qe *qe, *next;
361
362 2392889
        PTOK(pthread_cond_broadcast(&boc->cond));
363 2392889
        qe = VSLIST_FIRST(&boc->vai_q_head);
364 2392889
        VSLIST_FIRST(&boc->vai_q_head) = NULL;
365 2446400
        while (qe != NULL) {
366 53511
                CHECK_OBJ(qe, VAI_Q_MAGIC);
367 53511
                AN(qe->flags & VAI_QF_INQUEUE);
368 53511
                qe->flags &= ~VAI_QF_INQUEUE;
369 53511
                next = VSLIST_NEXT(qe, list);
370 53511
                VSLIST_NEXT(qe, list) = NULL;
371 53511
                qe->cb(qe->hdl, qe->priv);
372 53511
                qe = next;
373
        }
374 2392889
}
375
376
void
377 2291576
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l, int final)
378
{
379 2291576
        const struct obj_methods *om = obj_getmethods(oc);
380
381 2291576
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
382 2291576
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
383 2291576
        AN(om->objextend);
384 2291576
        assert(l >= 0);
385
386 2291576
        if (l > 0) {
387 2264130
                Lck_Lock(&oc->boc->mtx);
388 2264130
                obj_extend_condwait(oc);
389 2264130
                om->objextend(wrk, oc, l);
390 2264130
                oc->boc->fetched_so_far += l;
391 2264130
                obj_boc_notify(oc->boc);
392 2264130
                Lck_Unlock(&oc->boc->mtx);
393
394 2264130
                if (oc->boc->transit_buffer > 0)
395 19759
                        wrk->stats->transit_buffered += l;
396 2244371
                else if (oc->flags & OC_F_TRANSIENT)
397 53740
                        wrk->stats->transit_stored += l;
398 2264130
        }
399
400 2291576
        assert(oc->boc->state < BOS_FINISHED);
401 2291576
        if (final && om->objtrimstore != NULL)
402 76479
                om->objtrimstore(wrk, oc);
403 2291576
}
404
405
/*====================================================================
406
 */
407
408
static inline void
409 185996
objSignalFetchLocked(const struct objcore *oc, uint64_t l)
410
{
411 185996
        if (oc->boc->transit_buffer > 0) {
412 37711
                assert(oc->flags & OC_F_TRANSIENT);
413
                /* Signal the new client position */
414 37711
                oc->boc->delivered_so_far = l;
415 37711
                PTOK(pthread_cond_signal(&oc->boc->cond));
416 37711
        }
417 185996
}
418
419
uint64_t
420 0
ObjWaitExtend(const struct worker *wrk, const struct objcore *oc, uint64_t l,
421
    enum boc_state_e *statep)
422
{
423
        enum boc_state_e state;
424
        uint64_t rv;
425
426 0
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
427 0
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
428 0
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
429 0
        Lck_Lock(&oc->boc->mtx);
430 0
        while (1) {
431 0
                rv = oc->boc->fetched_so_far;
432 0
                assert(l <= rv || oc->boc->state == BOS_FAILED);
433 0
                state = oc->boc->state;
434 0
                objSignalFetchLocked(oc, l);
435 0
                if (rv > l || state >= BOS_FINISHED)
436 0
                        break;
437 0
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
438
        }
439 0
        Lck_Unlock(&oc->boc->mtx);
440 0
        if (statep != NULL)
441 0
                *statep = state;
442 0
        return (rv);
443
}
444
445
// get a new extension _or_ register a notification
446
uint64_t
447 185993
ObjVAIGetExtend(struct worker *wrk, const struct objcore *oc, uint64_t l,
448
    enum boc_state_e *statep, struct vai_qe *qe)
449
{
450
        enum boc_state_e state;
451
        uint64_t rv;
452
453 185993
        (void) wrk;
454 185993
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
455 185993
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
456 185993
        CHECK_OBJ_NOTNULL(qe, VAI_Q_MAGIC);
457 185993
        Lck_Lock(&oc->boc->mtx);
458 185993
        rv = oc->boc->fetched_so_far;
459 185993
        assert(l <= rv || oc->boc->state == BOS_FAILED);
460 185993
        state = oc->boc->state;
461 185993
        objSignalFetchLocked(oc, l);
462 185993
        if (l == rv && state < BOS_FINISHED &&
463 103830
            (qe->flags & VAI_QF_INQUEUE) == 0) {
464 53916
                qe->flags |= VAI_QF_INQUEUE;
465 53916
                VSLIST_INSERT_HEAD(&oc->boc->vai_q_head, qe, list);
466 53916
        }
467 185993
        Lck_Unlock(&oc->boc->mtx);
468 185993
        if (statep != NULL)
469 185981
                *statep = state;
470 186029
        return (rv);
471
}
472
473
void
474 31067
ObjVAICancel(struct worker *wrk, struct boc *boc, struct vai_qe *qe)
475
{
476
477 31067
        (void) wrk;
478 31067
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
479 31067
        CHECK_OBJ_NOTNULL(qe, VAI_Q_MAGIC);
480
481 31067
        Lck_Lock(&boc->mtx);
482
        // inefficient, but should be rare
483 31067
        if ((qe->flags & VAI_QF_INQUEUE) != 0)
484 405
                VSLIST_REMOVE(&boc->vai_q_head, qe, vai_qe, list);
485 31067
        qe->flags = 0;
486 31067
        Lck_Unlock(&boc->mtx);
487 31067
}
488
489
/*====================================================================
490
 */
491
492
void
493 215742
ObjSetState(struct worker *wrk, struct objcore *oc, enum boc_state_e next,
494
    unsigned broadcast)
495
{
496
        const struct obj_methods *om;
497
498 215742
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
499 215742
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
500 215742
        assert(next > oc->boc->state);
501
502 215742
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
503 215742
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
504
505 215742
        if (oc->stobj->stevedore != NULL) {
506 123349
                om = oc->stobj->stevedore->methods;
507 123349
                if (om->objsetstate != NULL)
508 0
                        om->objsetstate(wrk, oc, next);
509 123349
        }
510
511 215742
        if (next == BOS_FAILED)
512 2720
                HSH_Fail(wrk, oc);
513 213022
        else if (oc->boc->state < BOS_STREAM && next >= BOS_STREAM)
514 89150
                HSH_Unbusy(wrk, oc);
515
516 215742
        Lck_Lock(&oc->boc->mtx);
517 215742
        oc->boc->state = next;
518 215742
        if (broadcast)
519 128780
                obj_boc_notify(oc->boc);
520 215742
        Lck_Unlock(&oc->boc->mtx);
521 215742
}
522
523
/*====================================================================
524
 */
525
526
enum boc_state_e
527 105963
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
528
{
529
        enum boc_state_e got;
530
531 105963
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
532 105963
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
533
534 105963
        Lck_Lock(&oc->boc->mtx);
535
        /* wake up obj_extend_condwait() */
536 105963
        if (oc->flags & OC_F_CANCEL)
537 14093
                PTOK(pthread_cond_signal(&oc->boc->cond));
538 1215976
        while (1) {
539 1215976
                if (oc->boc->state >= want)
540 105963
                        break;
541 1110013
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
542
        }
543 105963
        got = oc->boc->state;
544 105963
        Lck_Unlock(&oc->boc->mtx);
545
546 105963
        return (got);
547
}
548
549
/*====================================================================
550
 * ObjGetlen()
551
 *
552
 * This is a separate function because it may need locking
553
 */
554
555
uint64_t
556 217922
ObjGetLen(struct worker *wrk, struct objcore *oc)
557
{
558
        uint64_t len;
559
560 217922
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
561
562 217922
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
563 217922
        return (len);
564
}
565
566
/*====================================================================
567
 * ObjSlim()
568
 *
569
 * Free the whatever storage can be freed, without freeing the actual
570
 * object yet.
571
 */
572
573
void
574 56516
ObjSlim(struct worker *wrk, struct objcore *oc)
575
{
576 56516
        const struct obj_methods *om = obj_getmethods(oc);
577
578 56516
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
579
580 56516
        if (om->objslim != NULL)
581 56515
                om->objslim(wrk, oc);
582 56516
}
583
584
/*====================================================================
585
 * Called when the boc used to populate the objcore is going away.
586
 * Useful for releasing any leftovers from Trim.
587
 */
588
589
void
590 117237
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
591
{
592
        const struct obj_methods *m;
593
594 117237
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
595 117237
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
596 117237
        AN(boc);
597 117237
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
598 117237
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
599 117237
        if (oc->stobj->stevedore != NULL) {
600 115120
                m = obj_getmethods(oc);
601 115120
                if (m->objbocdone != NULL)
602 115113
                        m->objbocdone(wrk, oc, *boc);
603 115120
        }
604 117235
        obj_deleteboc(boc);
605 117235
}
606
607
/*====================================================================
608
 */
609
void
610 72701
ObjFreeObj(struct worker *wrk, struct objcore *oc)
611
{
612 72701
        const struct obj_methods *m = obj_getmethods(oc);
613
614 72701
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
615
616 72701
        AN(m->objfree);
617 72701
        m->objfree(wrk, oc);
618 72701
        AZ(oc->stobj->stevedore);
619 72701
}
620
621
/*====================================================================
622
 * ObjHasAttr()
623
 *
624
 * Check if object has this attribute
625
 */
626
627
int
628 315726
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
629
{
630
631 315726
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
632 315726
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
633
634 315726
        if (oc->oa_present)
635 314886
                return (oc->oa_present & (1 << attr));
636
637
        /* resurrected persistent objects don't have oa_present set */
638 840
        return (ObjGetAttr(wrk, oc, attr, NULL) != NULL ? 1 : 0);
639 315726
}
640
641
/*====================================================================
642
 * ObjGetAttr()
643
 *
644
 * Get an attribute of the object.
645
 *
646
 * Returns NULL on unset or zero length attributes and len set to
647
 * zero. Returns Non-NULL otherwise and len is updated with the attributes
648
 * length.
649
 */
650
651
const void *
652 906639
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
653
   ssize_t *len)
654
{
655 906639
        const struct obj_methods *om = obj_getmethods(oc);
656
657 906639
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
658
659 906639
        AN(om->objgetattr);
660 906639
        return (om->objgetattr(wrk, oc, attr, len));
661
}
662
663
/*====================================================================
664
 * ObjSetAttr()
665
 *
666
 * Setting fixed size attributes always succeeds.
667
 *
668
 * Setting a variable size attribute asserts if the combined size of the
669
 * variable attributes exceeds the total variable attribute space set at
670
 * object creation. If there is space it always succeeds.
671
 *
672
 * Setting an auxiliary attribute can fail.
673
 *
674
 * Resetting any variable asserts if the new length does not match the
675
 * previous length exactly.
676
 *
677
 * If ptr is Non-NULL, it points to the new content which is copied into
678
 * the attribute.  Otherwise the caller will have to do the copying.
679
 *
680
 * Return value is non-NULL on success and NULL on failure. If ptr was
681
 * non-NULL, it is an error to use the returned pointer to set the
682
 * attribute data, it is only a success indicator in that case.
683
 */
684
685
void *
686 429450
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
687
    ssize_t len, const void *ptr)
688
{
689 429450
        const struct obj_methods *om = obj_getmethods(oc);
690
        void *r;
691
692 429450
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
693 429450
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
694
695 429450
        AN(om->objsetattr);
696 429450
        assert((int)attr < 16);
697 429450
        r = om->objsetattr(wrk, oc, attr, len, ptr);
698 429450
        if (r)
699 429423
                oc->oa_present |= (1 << attr);
700 429458
        return (r);
701
}
702
703
/*====================================================================
704
 * ObjTouch()
705
 */
706
707
void
708 132138
ObjTouch(struct worker *wrk, struct objcore *oc, vtim_real now)
709
{
710 132138
        const struct obj_methods *om = obj_getmethods(oc);
711
712 132138
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
713 132138
        if (om->objtouch != NULL)
714 132133
                om->objtouch(wrk, oc, now);
715 132140
}
716
717
/*====================================================================
718
 * Utility functions which work on top of the previous ones
719
 */
720
721
int
722 2440
ObjCopyAttr(struct worker *wrk, struct objcore *oc, struct objcore *ocs,
723
    enum obj_attr attr)
724
{
725
        const void *vps;
726
        void *vpd;
727
        ssize_t l;
728
729 2440
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
730 2440
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
731 2440
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
732 2440
        CHECK_OBJ_NOTNULL(ocs, OBJCORE_MAGIC);
733
734 2440
        vps = ObjGetAttr(wrk, ocs, attr, &l);
735
        // XXX: later we want to have zero-length OA's too
736 2440
        if (vps == NULL || l <= 0)
737 0
                return (-1);
738 2440
        vpd = ObjSetAttr(wrk, oc, attr, l, vps);
739 2440
        if (vpd == NULL)
740 0
                return (-1);
741 2440
        return (0);
742 2440
}
743
744
int
745 90037
ObjSetXID(struct worker *wrk, struct objcore *oc, vxid_t xid)
746
{
747
        uint64_t u;
748
749 90037
        u = VXID(xid);
750 90037
        AZ(ObjSetU64(wrk, oc, OA_VXID, u));
751 90037
        return (0);
752
}
753
754
755
vxid_t
756 118239
ObjGetXID(struct worker *wrk, struct objcore *oc)
757
{
758
        vxid_t u;
759
760 118239
        AZ(ObjGetU64(wrk, oc, OA_VXID, &u.vxid));
761 118239
        return (u);
762
}
763
764
/*--------------------------------------------------------------------
765
 * There is no well-defined byteorder for IEEE-754 double and the
766
 * correct solution (frexp(3) and manual encoding) is more work
767
 * than our (weak) goal of being endian-agnostic requires at this point.
768
 * We give it a shot by memcpy'ing doubles over a uint64_t and then
769
 * BE encode that.
770
 */
771
772
int
773 90031
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
774
{
775
        void *vp;
776
        uint64_t u;
777
778 90031
        assert(sizeof t == sizeof u);
779 90031
        memcpy(&u, &t, sizeof u);
780 90031
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
781 90031
        if (vp == NULL)
782 0
                return (-1);
783 90031
        vbe64enc(vp, u);
784 90031
        return (0);
785 90031
}
786
787
int
788 80
ObjGetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double *d)
789
{
790
        const void *vp;
791
        uint64_t u;
792
        ssize_t l;
793
794 80
        assert(sizeof *d == sizeof u);
795 80
        vp = ObjGetAttr(wrk, oc, a, &l);
796 80
        if (vp == NULL)
797 0
                return (-1);
798 80
        if (d != NULL) {
799 80
                assert(l == sizeof u);
800 80
                u = vbe64dec(vp);
801 80
                memcpy(d, &u, sizeof *d);
802 80
        }
803 80
        return (0);
804 80
}
805
806
/*--------------------------------------------------------------------
807
 */
808
809
int
810 200433
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
811
{
812
        void *vp;
813
814 200433
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
815 200433
        if (vp == NULL)
816 0
                return (-1);
817 200433
        vbe64enc(vp, t);
818 200433
        return (0);
819 200433
}
820
821
int
822 336280
ObjGetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t *d)
823
{
824
        const void *vp;
825
        ssize_t l;
826
827 336280
        vp = ObjGetAttr(wrk, oc, a, &l);
828 336280
        if (vp == NULL || l != sizeof *d)
829 20
                return (-1);
830 336280
        if (d != NULL)
831 336270
                *d = vbe64dec(vp);
832 336280
        return (0);
833 336262
}
834
835
/*--------------------------------------------------------------------
836
 */
837
838
int
839 294562
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
840
{
841
        const uint8_t *fp;
842
843 294562
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
844 294562
        AN(fp);
845 294562
        return ((*fp) & of);
846
}
847
848
void
849 19956
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
850
{
851
        uint8_t *fp;
852
853 19956
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
854 19956
        AN(fp);
855 19956
        if (val)
856 19876
                (*fp) |= of;
857
        else
858 80
                (*fp) &= ~of;
859 19956
}
860
861
/*====================================================================
862
 * Object event subscription mechanism.
863
 *
864
 * XXX: it is extremely unclear what the locking circumstances are here.
865
 */
866
867
struct oev_entry {
868
        unsigned                        magic;
869
#define OEV_MAGIC                       0xb0b7c5a1
870
        unsigned                        mask;
871
        obj_event_f                     *func;
872
        void                            *priv;
873
        VTAILQ_ENTRY(oev_entry)         list;
874
};
875
876
static VTAILQ_HEAD(,oev_entry)          oev_list;
877
static pthread_rwlock_t                 oev_rwl;
878
static unsigned                         oev_mask;
879
880
/*
881
 * NB: ObjSubscribeEvents() is not atomic:
882
 * oev_mask is checked optimistically in ObjSendEvent()
883
 */
884
uintptr_t
885 1560
ObjSubscribeEvents(obj_event_f *func, void *priv, unsigned mask)
886
{
887
        struct oev_entry *oev;
888
889 1560
        AN(func);
890 1560
        AZ(mask & ~OEV_MASK);
891
892 1560
        ALLOC_OBJ(oev, OEV_MAGIC);
893 1560
        AN(oev);
894 1560
        oev->func = func;
895 1560
        oev->priv = priv;
896 1560
        oev->mask = mask;
897 1560
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
898 1560
        VTAILQ_INSERT_TAIL(&oev_list, oev, list);
899 1560
        oev_mask |= mask;
900 1560
        PTOK(pthread_rwlock_unlock(&oev_rwl));
901 1560
        return ((uintptr_t)oev);
902
}
903
904
void
905 40
ObjUnsubscribeEvents(uintptr_t *handle)
906
{
907 40
        struct oev_entry *oev, *oev2 = NULL;
908 40
        unsigned newmask = 0;
909
910 40
        AN(handle);
911 40
        AN(*handle);
912 40
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
913 80
        VTAILQ_FOREACH(oev, &oev_list, list) {
914 40
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
915 40
                if ((uintptr_t)oev == *handle)
916 40
                        oev2 = oev;
917
                else
918 0
                        newmask |= oev->mask;
919 40
        }
920 40
        AN(oev2);
921 40
        VTAILQ_REMOVE(&oev_list, oev2, list);
922 40
        oev_mask = newmask;
923 40
        AZ(newmask & ~OEV_MASK);
924 40
        PTOK(pthread_rwlock_unlock(&oev_rwl));
925 40
        FREE_OBJ(oev2);
926 40
        *handle = 0;
927 40
}
928
929
void
930 134267
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
931
{
932
        struct oev_entry *oev;
933
934 134267
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
935 134267
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
936 134267
        AN(event & OEV_MASK);
937 134267
        AZ(event & ~OEV_MASK);
938 134267
        if (!(event & oev_mask))
939 130701
                return;
940
941 3566
        PTOK(pthread_rwlock_rdlock(&oev_rwl));
942 7763
        VTAILQ_FOREACH(oev, &oev_list, list) {
943 4203
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
944 4203
                if (event & oev->mask)
945 4200
                        oev->func(wrk, oev->priv, oc, event);
946 4203
        }
947 3560
        PTOK(pthread_rwlock_unlock(&oev_rwl));
948
949 134261
}
950
951
void
952 38029
ObjInit(void)
953
{
954 38029
        VTAILQ_INIT(&oev_list);
955 38029
        PTOK(pthread_rwlock_init(&oev_rwl, NULL));
956 38029
}