varnish-cache/bin/varnishd/storage/storage_malloc.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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
 * Storage method based on malloc(3)
30
 */
31
32
#include "config.h"
33
34
#include "cache/cache_varnishd.h"
35
#include "common/heritage.h"
36
37
#include <stdio.h>
38
#include <stdlib.h>
39
40
#include "storage/storage.h"
41
#include "storage/storage_simple.h"
42
43
#include "vnum.h"
44
45
#include "VSC_sma.h"
46
47
struct sma_sc {
48
        unsigned                magic;
49
#define SMA_SC_MAGIC            0x1ac8a345
50
        struct lock             sma_mtx;
51
        size_t                  sma_max;
52
        size_t                  sma_alloc;
53
        struct VSC_sma          *stats;
54
};
55
56
struct sma {
57
        unsigned                magic;
58
#define SMA_MAGIC               0x69ae9bb9
59
        struct storage          s;
60
        size_t                  sz;
61
        struct sma_sc           *sc;
62
};
63
64
static struct VSC_lck *lck_sma;
65
66
static struct storage * v_matchproto_(sml_alloc_f)
67 3107
sma_alloc(const struct stevedore *st, size_t size)
68
{
69
        struct sma_sc *sma_sc;
70 3107
        struct sma *sma = NULL;
71
        void *p;
72
73 3107
        CAST_OBJ_NOTNULL(sma_sc, st->priv, SMA_SC_MAGIC);
74 3107
        Lck_Lock(&sma_sc->sma_mtx);
75 3107
        sma_sc->stats->c_req++;
76 3107
        if (sma_sc->sma_alloc + size > sma_sc->sma_max) {
77 115
                sma_sc->stats->c_fail++;
78 115
                size = 0;
79
        } else {
80 2992
                sma_sc->sma_alloc += size;
81 2992
                sma_sc->stats->c_bytes += size;
82 2992
                sma_sc->stats->g_alloc++;
83 2992
                sma_sc->stats->g_bytes += size;
84 2992
                if (sma_sc->sma_max != SIZE_MAX)
85 1685
                        sma_sc->stats->g_space -= size;
86
        }
87 3107
        Lck_Unlock(&sma_sc->sma_mtx);
88
89 3107
        if (size == 0)
90 115
                return (NULL);
91
92
        /*
93
         * Do not collaps the sma allocation with sma->s.ptr: it is not
94
         * a good idea.  Not only would it make ->trim impossible,
95
         * performance-wise it would be a catastropy with chunksized
96
         * allocations growing another full page, just to accommodate the sma.
97
         */
98
99 2992
        p = malloc(size);
100 2992
        if (p != NULL) {
101 2992
                ALLOC_OBJ(sma, SMA_MAGIC);
102 2992
                if (sma != NULL)
103 2992
                        sma->s.ptr = p;
104
                else
105 0
                        free(p);
106
        }
107 2992
        if (sma == NULL) {
108 0
                Lck_Lock(&sma_sc->sma_mtx);
109
                /*
110
                 * XXX: Not nice to have counters go backwards, but we do
111
                 * XXX: Not want to pick up the lock twice just for stats.
112
                 */
113 0
                sma_sc->stats->c_fail++;
114 0
                sma_sc->sma_alloc -= size;
115 0
                sma_sc->stats->c_bytes -= size;
116 0
                sma_sc->stats->g_alloc--;
117 0
                sma_sc->stats->g_bytes -= size;
118 0
                if (sma_sc->sma_max != SIZE_MAX)
119 0
                        sma_sc->stats->g_space += size;
120 0
                Lck_Unlock(&sma_sc->sma_mtx);
121 0
                return (NULL);
122
        }
123 2992
        sma->sc = sma_sc;
124 2992
        sma->sz = size;
125 2992
        sma->s.priv = sma;
126 2992
        sma->s.len = 0;
127 2992
        sma->s.space = size;
128 2992
        sma->s.magic = STORAGE_MAGIC;
129 2992
        return (&sma->s);
130
}
131
132
static void v_matchproto_(sml_free_f)
133 1633
sma_free(struct storage *s)
134
{
135
        struct sma_sc *sma_sc;
136
        struct sma *sma;
137
138 1633
        CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
139 1633
        CAST_OBJ_NOTNULL(sma, s->priv, SMA_MAGIC);
140 1633
        sma_sc = sma->sc;
141 1633
        assert(sma->sz == sma->s.space);
142 1633
        Lck_Lock(&sma_sc->sma_mtx);
143 1633
        sma_sc->sma_alloc -= sma->sz;
144 1633
        sma_sc->stats->g_alloc--;
145 1633
        sma_sc->stats->g_bytes -= sma->sz;
146 1633
        sma_sc->stats->c_freed += sma->sz;
147 1633
        if (sma_sc->sma_max != SIZE_MAX)
148 390
                sma_sc->stats->g_space += sma->sz;
149 1633
        Lck_Unlock(&sma_sc->sma_mtx);
150 1633
        free(sma->s.ptr);
151 1633
        free(sma);
152 1633
}
153
154
static VCL_BYTES v_matchproto_(stv_var_used_space)
155 4
sma_used_space(const struct stevedore *st)
156
{
157
        struct sma_sc *sma_sc;
158
159 4
        CAST_OBJ_NOTNULL(sma_sc, st->priv, SMA_SC_MAGIC);
160 4
        return (sma_sc->sma_alloc);
161
}
162
163
static VCL_BYTES v_matchproto_(stv_var_free_space)
164 0
sma_free_space(const struct stevedore *st)
165
{
166
        struct sma_sc *sma_sc;
167
168 0
        CAST_OBJ_NOTNULL(sma_sc, st->priv, SMA_SC_MAGIC);
169 0
        return (sma_sc->sma_max - sma_sc->sma_alloc);
170
}
171
172
static void
173 1240
sma_init(struct stevedore *parent, int ac, char * const *av)
174
{
175
        const char *e;
176
        uintmax_t u;
177
        struct sma_sc *sc;
178
179 1240
        ASSERT_MGT();
180 1240
        ALLOC_OBJ(sc, SMA_SC_MAGIC);
181 1240
        AN(sc);
182 1240
        sc->sma_max = SIZE_MAX;
183 1240
        assert(sc->sma_max == SIZE_MAX);
184 1240
        parent->priv = sc;
185
186 1240
        AZ(av[ac]);
187 1240
        if (ac > 1)
188 0
                ARGV_ERR("(-smalloc) too many arguments\n");
189
190 1240
        if (ac == 0 || *av[0] == '\0')
191 1867
                 return;
192
193 613
        e = VNUM_2bytes(av[0], &u, 0);
194 613
        if (e != NULL)
195 0
                ARGV_ERR("(-smalloc) size \"%s\": %s\n", av[0], e);
196
        if ((u != (uintmax_t)(size_t)u))
197
                ARGV_ERR("(-smalloc) size \"%s\": too big\n", av[0]);
198 613
        if (u < 1024*1024)
199 0
                ARGV_ERR("(-smalloc) size \"%s\": too small, "
200
                         "did you forget to specify M or G?\n", av[0]);
201
202 613
        sc->sma_max = u;
203
}
204
205
static void v_matchproto_(storage_open_f)
206 1197
sma_open(struct stevedore *st)
207
{
208
        struct sma_sc *sma_sc;
209
210 1197
        ASSERT_CLI();
211 1197
        st->lru = LRU_Alloc();
212 1197
        if (lck_sma == NULL)
213 612
                lck_sma = Lck_CreateClass("sma");
214 1197
        CAST_OBJ_NOTNULL(sma_sc, st->priv, SMA_SC_MAGIC);
215 1197
        Lck_New(&sma_sc->sma_mtx, lck_sma);
216 1197
        sma_sc->stats = VSC_sma_New(st->ident);
217 1197
        if (sma_sc->sma_max != SIZE_MAX)
218 584
                sma_sc->stats->g_space = sma_sc->sma_max;
219 1197
}
220
221
const struct stevedore sma_stevedore = {
222
        .magic          =       STEVEDORE_MAGIC,
223
        .name           =       "malloc",
224
        .init           =       sma_init,
225
        .open           =       sma_open,
226
        .sml_alloc      =       sma_alloc,
227
        .sml_free       =       sma_free,
228
        .allocobj       =       SML_allocobj,
229
        .panic          =       SML_panic,
230
        .methods        =       &SML_methods,
231
        .var_free_space =       sma_free_space,
232
        .var_used_space =       sma_used_space,
233
};