vinyl-cache/bin/vinyld/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_int.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 3575949
obj_getmethods(const struct objcore *oc)
94
{
95
96 3575949
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
97 3575949
        CHECK_OBJ_NOTNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
98 3575949
        AN(oc->stobj->stevedore->methods);
99 3575949
        return (oc->stobj->stevedore->methods);
100
}
101
102
static struct boc *
103 75733
obj_newboc(void)
104
{
105
        struct boc *boc;
106
107 75733
        ALLOC_OBJ(boc, BOC_MAGIC);
108 75733
        AN(boc);
109 75733
        Lck_New(&boc->mtx, lck_busyobj);
110 75733
        PTOK(pthread_cond_init(&boc->cond, NULL));
111 75733
        boc->refcount = 1;
112 75733
        return (boc);
113
}
114
115
static void
116 75395
obj_deleteboc(struct boc **p)
117
{
118
        struct boc *boc;
119
120 75395
        TAKE_OBJ_NOTNULL(boc, p, BOC_MAGIC);
121 75395
        Lck_Delete(&boc->mtx);
122 75395
        PTOK(pthread_cond_destroy(&boc->cond));
123 75395
        free(boc->vary);
124 75395
        FREE_OBJ(boc);
125 75395
}
126
127
/*====================================================================
128
 * ObjNew()
129
 *
130
 */
131
132
struct objcore *
133 75733
ObjNew(const struct worker *wrk)
134
{
135
        struct objcore *oc;
136
137 75733
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
138
139 75733
        ALLOC_OBJ(oc, OBJCORE_MAGIC);
140 75733
        AN(oc);
141 75733
        wrk->stats->n_objectcore++;
142 75733
        oc->last_lru = NAN;
143 75733
        oc->boc = obj_newboc();
144
145 75733
        return (oc);
146
}
147
148
/*====================================================================
149
 * ObjDestroy()
150
 *
151
 */
152
153
void
154 53439
ObjDestroy(const struct worker *wrk, struct objcore **p)
155
{
156
        struct objcore *oc;
157
158 53439
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
159 53439
        TAKE_OBJ_NOTNULL(oc, p, OBJCORE_MAGIC);
160 53439
        if (oc->boc != NULL)
161 6540
                obj_deleteboc(&oc->boc);
162 53439
        FREE_OBJ(oc);
163 53439
        wrk->stats->n_objectcore--;
164 53439
}
165
166
/*====================================================================
167
 * ObjIterate()
168
 *
169
 */
170
171
int
172 52663
ObjIterate(struct worker *wrk, struct objcore *oc,
173
    void *priv, objiterate_f *func, int final)
174
{
175 52663
        const struct obj_methods *om = obj_getmethods(oc);
176
177 52663
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
178 52663
        AN(func);
179 52663
        AN(om->objiterator);
180 52663
        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
 * ObjVAInotify() notify to resume delivery from a vmod
245
 *
246
 *      Not only a storage engine can encounter a "no data ready at the moment"
247
 *      condition, but also a filter: A filter's .io_lease() function might
248
 *      return -EAGAIN, but then it needs a way to notify when more data is
249
 *      available. This is ObjVAInotify().
250
 *
251
 * ObjVAIfini() finalized iteration
252
 *
253
 *      it must be called when iteration is done, irrespective of error status
254
 */
255
256
vai_hdl
257 53339
ObjVAIinit(struct worker *wrk, struct objcore *oc, struct ws *ws,
258
    vai_notify_cb *cb, void *cb_priv)
259
{
260 53339
        const struct obj_methods *om = obj_getmethods(oc);
261
262 53339
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
263
264 53339
        if (om->vai_init == NULL)
265 0
                return (NULL);
266 53339
        return (om->vai_init(wrk, oc, ws, cb, cb_priv));
267 53339
}
268
269
int
270 175378
ObjVAIlease(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
271
{
272 175378
        struct vai_hdl_preamble *vaip = vhdl;
273
274 175378
        AN(vaip);
275 175378
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
276 175378
        AN(vaip->vai_lease);
277 175378
        return (vaip->vai_lease(wrk, vhdl, scarab));
278
}
279
280
int
281 336
ObjVAIbuffer(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
282
{
283 336
        struct vai_hdl_preamble *vaip = vhdl;
284
        int r;
285
286 336
        AN(vaip);
287 336
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
288 336
        AN(vaip->vai_buffer);
289 336
        r = vaip->vai_buffer(wrk, vhdl, scarab);
290
        // returning no reason for failure is a bug
291 336
        assert(r != 0);
292 336
        return (r);
293
}
294
295
void
296 78087
ObjVAIreturn(struct worker *wrk, vai_hdl vhdl, struct vscaret *scaret)
297
{
298 78087
        struct vai_hdl_preamble *vaip = vhdl;
299
300 78087
        AN(vaip);
301 78087
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
302 78087
        AN(vaip->vai_return);
303 78087
        vaip->vai_return(wrk, vhdl, scaret);
304 78087
}
305
306
void
307 2687
ObjVAInotify(struct worker *wrk, vai_hdl vhdl)
308
{
309 2687
        struct vai_hdl_preamble *vaip = vhdl;
310
311 2687
        AN(vaip);
312 2687
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
313 2687
        AN(vaip->vai_notify);
314 2687
        vaip->vai_notify(wrk, vhdl);
315 2687
}
316
317
void
318 53335
ObjVAIfini(struct worker *wrk, vai_hdl *vhdlp)
319
{
320 53335
        AN(vhdlp);
321 53335
        struct vai_hdl_preamble *vaip = *vhdlp;
322
323 53335
        AN(vaip);
324 53335
        assert(vaip->magic2 == VAI_HDL_PREAMBLE_MAGIC2);
325 53335
        AN(vaip->vai_lease);
326 53335
        vaip->vai_fini(wrk, vhdlp);
327 53335
}
328
329
/*====================================================================
330
 * ObjGetSpace()
331
 *
332
 * This function returns a pointer and length of free space.  If there
333
 * is no free space, some will be added first.
334
 *
335
 * The "sz" argument is an input hint of how much space is desired.
336
 * 0 means "unknown", return some default size (maybe fetch_chunksize)
337
 */
338
339
int
340 1274593
ObjGetSpace(struct worker *wrk, struct objcore *oc, ssize_t *sz, uint8_t **ptr)
341
{
342 1274593
        const struct obj_methods *om = obj_getmethods(oc);
343
344 1274593
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
345 1274593
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
346 1274593
        AN(sz);
347 1274593
        AN(ptr);
348 1274593
        assert(*sz >= 0);
349
350 1274593
        AN(om->objgetspace);
351 1274593
        return (om->objgetspace(wrk, oc, sz, ptr));
352
}
353
354
/*====================================================================
355
 * ObjExtend()
356
 *
357
 * This function extends the used part of the object a number of bytes
358
 * into the last space returned by ObjGetSpace()
359
 *
360
 * The final flag must be set on the last call, and it will release any
361
 * surplus space allocated.
362
 */
363
364
static void
365 1221428
obj_extend_condwait(const struct objcore *oc)
366
{
367
368 1221428
        if (oc->boc->transit_buffer == 0)
369 1211873
                return;
370
371 9555
        assert(oc->flags & OC_F_TRANSIENT);
372 10462
        while (!(oc->flags & OC_F_CANCEL) && oc->boc->fetched_so_far >
373 10441
            oc->boc->delivered_so_far + oc->boc->transit_buffer)
374 907
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
375 1221428
}
376
377
// notify of an extension of the boc or state change
378
379
static void
380 1293252
obj_boc_notify(struct boc *boc)
381
{
382
        struct vai_qe *qe, *next;
383
384 1293252
        PTOK(pthread_cond_broadcast(&boc->cond));
385 1293252
        qe = VSLIST_FIRST(&boc->vai_q_head);
386 1293252
        VSLIST_FIRST(&boc->vai_q_head) = NULL;
387 1336937
        while (qe != NULL) {
388 43685
                CHECK_OBJ(qe, VAI_Q_MAGIC);
389 43685
                AN(qe->flags & VAI_QF_INQUEUE);
390 43685
                qe->flags &= ~VAI_QF_INQUEUE;
391 43685
                next = VSLIST_NEXT(qe, list);
392 43685
                VSLIST_NEXT(qe, list) = NULL;
393 43685
                qe->cb(qe->hdl, qe->priv);
394 43685
                qe = next;
395
        }
396 1293252
}
397
398
void
399 1234264
ObjExtend(struct worker *wrk, struct objcore *oc, ssize_t l, int final)
400
{
401 1234264
        const struct obj_methods *om = obj_getmethods(oc);
402
403 1234264
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
404 1234264
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
405 1234264
        AN(om->objextend);
406 1234264
        assert(l >= 0);
407
408 1234264
        if (l > 0) {
409 1221440
                Lck_Lock(&oc->boc->mtx);
410 1221440
                obj_extend_condwait(oc);
411 1221440
                om->objextend(wrk, oc, l);
412 1221440
                oc->boc->fetched_so_far += l;
413 1221440
                obj_boc_notify(oc->boc);
414 1221440
                Lck_Unlock(&oc->boc->mtx);
415
416 1221440
                if (oc->boc->transit_buffer > 0)
417 9555
                        wrk->stats->transit_buffered += l;
418 1211885
                else if (oc->flags & OC_F_TRANSIENT)
419 61576
                        wrk->stats->transit_stored += l;
420 1221440
        }
421
422 1234264
        assert(oc->boc->state < BOS_FINISHED);
423 1234264
        if (final && om->objtrimstore != NULL)
424 31437
                om->objtrimstore(wrk, oc);
425 1234264
}
426
427
/*====================================================================
428
 */
429
430
static inline void
431 146278
objSignalFetchLocked(const struct objcore *oc, uint64_t l)
432
{
433 146278
        if (oc->boc->transit_buffer > 0) {
434 17872
                assert(oc->flags & OC_F_TRANSIENT);
435
                /* Signal the new client position */
436 17872
                oc->boc->delivered_so_far = l;
437 17872
                PTOK(pthread_cond_signal(&oc->boc->cond));
438 17872
        }
439 146278
}
440
441
uint64_t
442 0
ObjWaitExtend(const struct worker *wrk, const struct objcore *oc, uint64_t l,
443
    enum boc_state_e *statep)
444
{
445
        enum boc_state_e state;
446
        uint64_t rv;
447
448 0
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
449 0
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
450 0
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
451 0
        Lck_Lock(&oc->boc->mtx);
452 0
        while (1) {
453 0
                rv = oc->boc->fetched_so_far;
454 0
                assert(l <= rv || oc->boc->state == BOS_FAILED);
455 0
                state = oc->boc->state;
456 0
                objSignalFetchLocked(oc, l);
457 0
                if (rv > l || state >= BOS_FINISHED)
458 0
                        break;
459 0
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
460
        }
461 0
        Lck_Unlock(&oc->boc->mtx);
462 0
        if (statep != NULL)
463 0
                *statep = state;
464 0
        return (rv);
465
}
466
467
// get a new extension _or_ register a notification
468
uint64_t
469 146281
ObjVAIGetExtend(struct worker *wrk, const struct objcore *oc, uint64_t l,
470
    enum boc_state_e *statep, struct vai_qe *qe)
471
{
472
        enum boc_state_e state;
473
        uint64_t rv;
474
475 146281
        (void) wrk;
476 146281
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
477 146281
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
478 146281
        CHECK_OBJ_NOTNULL(qe, VAI_Q_MAGIC);
479 146281
        Lck_Lock(&oc->boc->mtx);
480 146281
        rv = oc->boc->fetched_so_far;
481 146281
        assert(l <= rv || oc->boc->state == BOS_FAILED);
482 146281
        state = oc->boc->state;
483 146281
        objSignalFetchLocked(oc, l);
484 146281
        if (l == rv && state < BOS_FINISHED &&
485 82566
            (qe->flags & VAI_QF_INQUEUE) == 0) {
486 43912
                qe->flags |= VAI_QF_INQUEUE;
487 43912
                VSLIST_INSERT_HEAD(&oc->boc->vai_q_head, qe, list);
488 43912
        }
489 146281
        Lck_Unlock(&oc->boc->mtx);
490 146281
        if (statep != NULL)
491 146298
                *statep = state;
492 146345
        return (rv);
493
}
494
495
void
496 17070
ObjVAICancel(struct worker *wrk, struct boc *boc, struct vai_qe *qe)
497
{
498
499 17070
        (void) wrk;
500 17070
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
501 17070
        CHECK_OBJ_NOTNULL(qe, VAI_Q_MAGIC);
502
503 17070
        Lck_Lock(&boc->mtx);
504
        // inefficient, but should be rare
505 17070
        if ((qe->flags & VAI_QF_INQUEUE) != 0)
506 231
                VSLIST_REMOVE(&boc->vai_q_head, qe, vai_qe, list);
507 17070
        qe->flags = 0;
508 17070
        Lck_Unlock(&boc->mtx);
509 17070
}
510
511
/*====================================================================
512
 */
513
514
void
515 120703
ObjSetState(struct worker *wrk, struct objcore *oc, enum boc_state_e next,
516
    unsigned broadcast)
517
{
518
        const struct obj_methods *om;
519
520 120703
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
521 120703
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
522 120703
        assert(next > oc->boc->state);
523
524 120703
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
525 120703
        assert(next != BOS_FINISHED || (oc->oa_present & (1 << OA_LEN)));
526
527 120703
        if (oc->stobj->stevedore != NULL) {
528 68938
                om = oc->stobj->stevedore->methods;
529 68938
                if (om->objsetstate != NULL)
530 0
                        om->objsetstate(wrk, oc, next);
531 68938
        }
532
533 120703
        if (next == BOS_FAILED)
534 1470
                HSH_Fail(wrk, oc);
535 119233
        else if (oc->boc->state < BOS_STREAM && next >= BOS_STREAM)
536 50062
                HSH_Unbusy(wrk, oc);
537
538 120703
        Lck_Lock(&oc->boc->mtx);
539 120703
        oc->boc->state = next;
540 120703
        if (broadcast)
541 71832
                obj_boc_notify(oc->boc);
542 120703
        Lck_Unlock(&oc->boc->mtx);
543 120703
}
544
545
/*====================================================================
546
 */
547
548
enum boc_state_e
549 59460
ObjWaitState(const struct objcore *oc, enum boc_state_e want)
550
{
551
        enum boc_state_e got;
552
553 59460
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
554 59460
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
555
556 59460
        Lck_Lock(&oc->boc->mtx);
557
        /* wake up obj_extend_condwait() */
558 59460
        if (oc->flags & OC_F_CANCEL)
559 7952
                PTOK(pthread_cond_signal(&oc->boc->cond));
560 675563
        while (1) {
561 675563
                if (oc->boc->state >= want)
562 59460
                        break;
563 616103
                (void)Lck_CondWait(&oc->boc->cond, &oc->boc->mtx);
564
        }
565 59460
        got = oc->boc->state;
566 59460
        Lck_Unlock(&oc->boc->mtx);
567
568 59460
        return (got);
569
}
570
571
/*====================================================================
572
 * ObjGetlen()
573
 *
574
 * This is a separate function because it may need locking
575
 */
576
577
uint64_t
578 122692
ObjGetLen(struct worker *wrk, struct objcore *oc)
579
{
580
        uint64_t len;
581
582 122692
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
583
584 122692
        AZ(ObjGetU64(wrk, oc, OA_LEN, &len));
585 122692
        return (len);
586
}
587
588
/*====================================================================
589
 * ObjSlim()
590
 *
591
 * Free the whatever storage can be freed, without freeing the actual
592
 * object yet.
593
 */
594
595
void
596 34243
ObjSlim(struct worker *wrk, struct objcore *oc)
597
{
598 34243
        const struct obj_methods *om = obj_getmethods(oc);
599
600 34243
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
601
602 34243
        if (om->objslim != NULL)
603 22342
                om->objslim(wrk, oc);
604 34243
}
605
606
/*====================================================================
607
 * Called when the boc used to populate the objcore is going away.
608
 * Useful for releasing any leftovers from Trim.
609
 */
610
611
void
612 68851
ObjBocDone(struct worker *wrk, struct objcore *oc, struct boc **boc)
613
{
614
        const struct obj_methods *m;
615
616 68851
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
617 68851
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
618 68851
        AN(boc);
619 68851
        CHECK_OBJ_NOTNULL(*boc, BOC_MAGIC);
620 68851
        CHECK_OBJ_ORNULL(oc->stobj->stevedore, STEVEDORE_MAGIC);
621 68851
        if (oc->stobj->stevedore != NULL) {
622 67698
                m = obj_getmethods(oc);
623 67698
                if (m->objbocdone != NULL)
624 55753
                        m->objbocdone(wrk, oc, *boc);
625 67698
        }
626 68851
        obj_deleteboc(boc);
627 68851
}
628
629
/*====================================================================
630
 */
631
void
632 46227
ObjFreeObj(struct worker *wrk, struct objcore *oc)
633
{
634 46227
        const struct obj_methods *m = obj_getmethods(oc);
635
636 46227
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
637
638 46227
        AN(m->objfree);
639 46227
        m->objfree(wrk, oc);
640 46227
        AZ(oc->stobj->stevedore);
641 46227
}
642
643
/*====================================================================
644
 * ObjHasAttr()
645
 *
646
 * Check if object has this attribute
647
 */
648
649
int
650 172180
ObjHasAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr)
651
{
652
653 172180
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
654 172180
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
655
656 172180
        if (oc->oa_present)
657 159880
                return (oc->oa_present & (1 << attr));
658
659
        /* resurrected persistent objects don't have oa_present set */
660 12300
        return (ObjGetAttr(wrk, oc, attr, NULL) != NULL ? 1 : 0);
661 172180
}
662
663
/*====================================================================
664
 * ObjGetAttr()
665
 *
666
 * Get an attribute of the object.
667
 *
668
 * Returns NULL on unset or zero length attributes and len set to
669
 * zero. Returns Non-NULL otherwise and len is updated with the attributes
670
 * length.
671
 */
672
673
const void *
674 511995
ObjGetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
675
   ssize_t *len)
676
{
677 511995
        const struct obj_methods *om = obj_getmethods(oc);
678
679 511995
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
680
681 511995
        AN(om->objgetattr);
682 511995
        return (om->objgetattr(wrk, oc, attr, len));
683
}
684
685
/*====================================================================
686
 * ObjSetAttr()
687
 *
688
 * Setting fixed size attributes always succeeds.
689
 *
690
 * Setting a variable size attribute asserts if the combined size of the
691
 * variable attributes exceeds the total variable attribute space set at
692
 * object creation. If there is space it always succeeds.
693
 *
694
 * Setting an auxiliary attribute can fail.
695
 *
696
 * Resetting any variable asserts if the new length does not match the
697
 * previous length exactly.
698
 *
699
 * If ptr is Non-NULL, it points to the new content which is copied into
700
 * the attribute.  Otherwise the caller will have to do the copying.
701
 *
702
 * Return value is non-NULL on success and NULL on failure. If ptr was
703
 * non-NULL, it is an error to use the returned pointer to set the
704
 * attribute data, it is only a success indicator in that case.
705
 */
706
707
void *
708 227963
ObjSetAttr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
709
    ssize_t len, const void *ptr)
710
{
711 227963
        const struct obj_methods *om = obj_getmethods(oc);
712
        void *r;
713
714 227963
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
715 227963
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
716
717 227963
        AN(om->objsetattr);
718 227963
        assert((int)attr < 16);
719 227963
        r = om->objsetattr(wrk, oc, attr, len, ptr);
720 227963
        if (r)
721 227951
                oc->oa_present |= (1 << attr);
722 227969
        return (r);
723
}
724
725
/*====================================================================
726
 * ObjTouch()
727
 */
728
729
void
730 73058
ObjTouch(struct worker *wrk, struct objcore *oc, vtim_real now)
731
{
732 73058
        const struct obj_methods *om = obj_getmethods(oc);
733
734 73058
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
735 73058
        if (om->objtouch != NULL)
736 73055
                om->objtouch(wrk, oc, now);
737 73058
}
738
739
/*====================================================================
740
 * Utility functions which work on top of the previous ones
741
 */
742
743
int
744 1323
ObjCopyAttr(struct worker *wrk, struct objcore *oc, struct objcore *ocs,
745
    enum obj_attr attr)
746
{
747
        const void *vps;
748
        void *vpd;
749
        ssize_t l;
750
751 1323
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
752 1323
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
753 1323
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
754 1323
        CHECK_OBJ_NOTNULL(ocs, OBJCORE_MAGIC);
755
756 1323
        vps = ObjGetAttr(wrk, ocs, attr, &l);
757
        // XXX: later we want to have zero-length OA's too
758 1323
        if (vps == NULL || l <= 0)
759 0
                return (-1);
760 1323
        vpd = ObjSetAttr(wrk, oc, attr, l, vps);
761 1323
        if (vpd == NULL)
762 0
                return (-1);
763 1323
        return (0);
764 1323
}
765
766
int
767 50565
ObjSetXID(struct worker *wrk, struct objcore *oc, vxid_t xid)
768
{
769
        uint64_t u;
770
771 50565
        u = VXID(xid);
772 50565
        AZ(ObjSetU64(wrk, oc, OA_VXID, u));
773 50565
        return (0);
774
}
775
776
777
vxid_t
778 64174
ObjGetXID(struct worker *wrk, struct objcore *oc)
779
{
780
        vxid_t u;
781
782 64174
        AZ(ObjGetU64(wrk, oc, OA_VXID, &u.vxid));
783 64174
        return (u);
784
}
785
786
/*--------------------------------------------------------------------
787
 * There is no well-defined byteorder for IEEE-754 double and the
788
 * correct solution (frexp(3) and manual encoding) is more work
789
 * than our (weak) goal of being endian-agnostic requires at this point.
790
 * We give it a shot by memcpy'ing doubles over a uint64_t and then
791
 * BE encode that.
792
 */
793
794
int
795 50565
ObjSetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double t)
796
{
797
        void *vp;
798
        uint64_t u;
799
800 50565
        assert(sizeof t == sizeof u);
801 50565
        vmemcpy(&u, &t, sizeof u);
802 50565
        vp = ObjSetAttr(wrk, oc, a, sizeof u, NULL);
803 50565
        if (vp == NULL)
804 0
                return (-1);
805 50565
        vbe64enc(vp, u);
806 50565
        return (0);
807 50565
}
808
809
int
810 42
ObjGetDouble(struct worker *wrk, struct objcore *oc, enum obj_attr a, double *d)
811
{
812
        const void *vp;
813
        uint64_t u;
814
        ssize_t l;
815
816 42
        assert(sizeof *d == sizeof u);
817 42
        vp = ObjGetAttr(wrk, oc, a, &l);
818 42
        if (vp == NULL)
819 0
                return (-1);
820 42
        if (d != NULL) {
821 42
                assert(l == sizeof u);
822 42
                u = vbe64dec(vp);
823 42
                vmemcpy(d, &u, sizeof *d);
824 42
        }
825 42
        return (0);
826 42
}
827
828
/*--------------------------------------------------------------------
829
 */
830
831
int
832 100965
ObjSetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t t)
833
{
834
        void *vp;
835
836 100965
        vp = ObjSetAttr(wrk, oc, a, sizeof t, NULL);
837 100965
        if (vp == NULL)
838 0
                return (-1);
839 100965
        vbe64enc(vp, t);
840 100965
        return (0);
841 100965
}
842
843
int
844 186929
ObjGetU64(struct worker *wrk, struct objcore *oc, enum obj_attr a, uint64_t *d)
845
{
846
        const void *vp;
847
        ssize_t l;
848
849 186929
        vp = ObjGetAttr(wrk, oc, a, &l);
850 186929
        if (vp == NULL || l != sizeof *d)
851 18
                return (-1);
852 186929
        if (d != NULL)
853 186921
                *d = vbe64dec(vp);
854 186929
        return (0);
855 186921
}
856
857
/*--------------------------------------------------------------------
858
 */
859
860
int
861 164157
ObjCheckFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of)
862
{
863
        const uint8_t *fp;
864
865 164157
        fp = ObjGetAttr(wrk, oc, OA_FLAGS, NULL);
866 164157
        AN(fp);
867 164157
        return ((*fp) & of);
868
}
869
870
void
871 10584
ObjSetFlag(struct worker *wrk, struct objcore *oc, enum obj_flags of, int val)
872
{
873
        uint8_t *fp;
874
875 10584
        fp = ObjSetAttr(wrk, oc, OA_FLAGS, 1, NULL);
876 10584
        AN(fp);
877 10584
        if (val)
878 10542
                (*fp) |= of;
879
        else
880 42
                (*fp) &= ~of;
881 10584
}
882
883
/*====================================================================
884
 * Object event subscription mechanism.
885
 *
886
 * XXX: it is extremely unclear what the locking circumstances are here.
887
 */
888
889
struct oev_entry {
890
        unsigned                        magic;
891
#define OEV_MAGIC                       0xb0b7c5a1
892
        unsigned                        mask;
893
        obj_event_f                     *func;
894
        void                            *priv;
895
        VTAILQ_ENTRY(oev_entry)         list;
896
};
897
898
static VTAILQ_HEAD(,oev_entry)          oev_list;
899
static pthread_rwlock_t                 oev_rwl;
900
static unsigned                         oev_mask;
901
902
/*
903
 * NB: ObjSubscribeEvents() is not atomic:
904
 * oev_mask is checked optimistically in ObjSendEvent()
905
 */
906
uintptr_t
907 777
ObjSubscribeEvents(obj_event_f *func, void *priv, unsigned mask)
908
{
909
        struct oev_entry *oev;
910
911 777
        AN(func);
912 777
        AZ(mask & ~OEV_MASK);
913
914 777
        ALLOC_OBJ(oev, OEV_MAGIC);
915 777
        AN(oev);
916 777
        oev->func = func;
917 777
        oev->priv = priv;
918 777
        oev->mask = mask;
919 777
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
920 777
        VTAILQ_INSERT_TAIL(&oev_list, oev, list);
921 777
        oev_mask |= mask;
922 777
        PTOK(pthread_rwlock_unlock(&oev_rwl));
923 777
        return ((uintptr_t)oev);
924
}
925
926
void
927 21
ObjUnsubscribeEvents(uintptr_t *handle)
928
{
929 21
        struct oev_entry *oev, *oev2 = NULL;
930 21
        unsigned newmask = 0;
931
932 21
        AN(handle);
933 21
        AN(*handle);
934 21
        PTOK(pthread_rwlock_wrlock(&oev_rwl));
935 42
        VTAILQ_FOREACH(oev, &oev_list, list) {
936 21
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
937 21
                if ((uintptr_t)oev == *handle)
938 21
                        oev2 = oev;
939
                else
940 0
                        newmask |= oev->mask;
941 21
        }
942 21
        AN(oev2);
943 21
        VTAILQ_REMOVE(&oev_list, oev2, list);
944 21
        oev_mask = newmask;
945 21
        AZ(newmask & ~OEV_MASK);
946 21
        PTOK(pthread_rwlock_unlock(&oev_rwl));
947 21
        FREE_OBJ(oev2);
948 21
        *handle = 0;
949 21
}
950
951
void
952 71202
ObjSendEvent(struct worker *wrk, struct objcore *oc, unsigned event)
953
{
954
        struct oev_entry *oev;
955
956 71202
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
957 71202
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
958 71202
        AN(event & OEV_MASK);
959 71202
        AZ(event & ~OEV_MASK);
960 71202
        if (!(event & oev_mask))
961 69522
                return;
962
963 1680
        PTOK(pthread_rwlock_rdlock(&oev_rwl));
964 3696
        VTAILQ_FOREACH(oev, &oev_list, list) {
965 2016
                CHECK_OBJ_NOTNULL(oev, OEV_MAGIC);
966 2016
                if (event & oev->mask)
967 2016
                        oev->func(wrk, oev->priv, oc, event);
968 2016
        }
969 1680
        PTOK(pthread_rwlock_unlock(&oev_rwl));
970
971 71202
}
972
973
void
974 20888
ObjInit(void)
975
{
976 20888
        VTAILQ_INIT(&oev_list);
977 20888
        PTOK(pthread_rwlock_init(&oev_rwl, NULL));
978 20888
}