1*403185e4Smartijn /* $OpenBSD: namespace.c,v 1.20 2020/03/05 07:39:25 martijn Exp $ */
25d465952Smartinh
35d465952Smartinh /*
45d465952Smartinh * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
55d465952Smartinh *
65d465952Smartinh * Permission to use, copy, modify, and distribute this software for any
75d465952Smartinh * purpose with or without fee is hereby granted, provided that the above
85d465952Smartinh * copyright notice and this permission notice appear in all copies.
95d465952Smartinh *
105d465952Smartinh * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115d465952Smartinh * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
125d465952Smartinh * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
135d465952Smartinh * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145d465952Smartinh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
155d465952Smartinh * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
165d465952Smartinh * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
175d465952Smartinh */
185d465952Smartinh
195d465952Smartinh #include <sys/types.h>
205d465952Smartinh #include <sys/queue.h>
215d465952Smartinh
225d465952Smartinh #include <assert.h>
23a9ac9ba1Smartinh #include <errno.h>
245d465952Smartinh #include <stdio.h>
255d465952Smartinh #include <stdlib.h>
265d465952Smartinh #include <string.h>
275d465952Smartinh #include <zlib.h>
285d465952Smartinh
295d465952Smartinh #include "ldapd.h"
30fdd30f56Sbenno #include "log.h"
315d465952Smartinh
32*403185e4Smartijn extern char *datadir;
332f9fe121Sjca
345d465952Smartinh /* Maximum number of requests to queue per namespace during compaction.
355d465952Smartinh * After this many requests, we return LDAP_BUSY.
365d465952Smartinh */
375d465952Smartinh #define MAX_REQUEST_QUEUE 10000
385d465952Smartinh
395d465952Smartinh static struct btval *namespace_find(struct namespace *ns, char *dn);
405d465952Smartinh static void namespace_queue_replay(int fd, short event, void *arg);
41898a5208Smartinh static int namespace_set_fd(struct namespace *ns,
42898a5208Smartinh struct btree **bt, int fd, unsigned int flags);
435d465952Smartinh
445d465952Smartinh int
namespace_begin_txn(struct namespace * ns,struct btree_txn ** data_txn,struct btree_txn ** indx_txn,int rdonly)45a9ac9ba1Smartinh namespace_begin_txn(struct namespace *ns, struct btree_txn **data_txn,
46a9ac9ba1Smartinh struct btree_txn **indx_txn, int rdonly)
475d465952Smartinh {
480279e526Smartinh if (ns->data_db == NULL || ns->indx_db == NULL) {
490279e526Smartinh errno = EBUSY; /* namespace is being reopened */
500279e526Smartinh return -1;
510279e526Smartinh }
52a9ac9ba1Smartinh
53a9ac9ba1Smartinh if ((*data_txn = btree_txn_begin(ns->data_db, rdonly)) == NULL ||
54a9ac9ba1Smartinh (*indx_txn = btree_txn_begin(ns->indx_db, rdonly)) == NULL) {
550279e526Smartinh if (errno == ESTALE) {
56a9ac9ba1Smartinh if (*data_txn == NULL)
57a9ac9ba1Smartinh namespace_reopen_data(ns);
58a9ac9ba1Smartinh else
59a9ac9ba1Smartinh namespace_reopen_indx(ns);
600279e526Smartinh errno = EBUSY;
61a9ac9ba1Smartinh }
62a9ac9ba1Smartinh log_warn("failed to open transaction");
63a9ac9ba1Smartinh btree_txn_abort(*data_txn);
64a9ac9ba1Smartinh *data_txn = NULL;
650279e526Smartinh return -1;
665d465952Smartinh }
675d465952Smartinh
680279e526Smartinh return 0;
69a9ac9ba1Smartinh }
70a9ac9ba1Smartinh
71a9ac9ba1Smartinh int
namespace_begin(struct namespace * ns)72a9ac9ba1Smartinh namespace_begin(struct namespace *ns)
73a9ac9ba1Smartinh {
74a9ac9ba1Smartinh return namespace_begin_txn(ns, &ns->data_txn, &ns->indx_txn, 0);
755d465952Smartinh }
765d465952Smartinh
775d465952Smartinh int
namespace_commit(struct namespace * ns)785d465952Smartinh namespace_commit(struct namespace *ns)
795d465952Smartinh {
805d465952Smartinh if (ns->indx_txn != NULL &&
815d465952Smartinh btree_txn_commit(ns->indx_txn) != BT_SUCCESS) {
825d465952Smartinh log_warn("%s(indx): commit failed", ns->suffix);
835d465952Smartinh btree_txn_abort(ns->data_txn);
845d465952Smartinh ns->indx_txn = ns->data_txn = NULL;
855d465952Smartinh return -1;
865d465952Smartinh }
875d465952Smartinh ns->indx_txn = NULL;
885d465952Smartinh
895d465952Smartinh if (ns->data_txn != NULL &&
905d465952Smartinh btree_txn_commit(ns->data_txn) != BT_SUCCESS) {
915d465952Smartinh log_warn("%s(data): commit failed", ns->suffix);
925d465952Smartinh ns->data_txn = NULL;
935d465952Smartinh return -1;
945d465952Smartinh }
955d465952Smartinh ns->data_txn = NULL;
965d465952Smartinh
975d465952Smartinh return 0;
985d465952Smartinh }
995d465952Smartinh
1005d465952Smartinh void
namespace_abort(struct namespace * ns)1015d465952Smartinh namespace_abort(struct namespace *ns)
1025d465952Smartinh {
1035d465952Smartinh btree_txn_abort(ns->data_txn);
1045d465952Smartinh ns->data_txn = NULL;
1055d465952Smartinh
1065d465952Smartinh btree_txn_abort(ns->indx_txn);
1075d465952Smartinh ns->indx_txn = NULL;
1085d465952Smartinh }
1095d465952Smartinh
1105d465952Smartinh int
namespace_open(struct namespace * ns)1115d465952Smartinh namespace_open(struct namespace *ns)
1125d465952Smartinh {
1135d465952Smartinh unsigned int db_flags = 0;
1145d465952Smartinh
1155d465952Smartinh assert(ns);
1165d465952Smartinh assert(ns->suffix);
1175d465952Smartinh
1185d465952Smartinh if (ns->sync == 0)
1195d465952Smartinh db_flags |= BT_NOSYNC;
1205d465952Smartinh
12195af8abfSderaadt if (asprintf(&ns->data_path, "%s/%s_data.db", datadir, ns->suffix) == -1)
1225d465952Smartinh return -1;
1235d465952Smartinh log_info("opening namespace %s", ns->suffix);
1245d465952Smartinh ns->data_db = btree_open(ns->data_path, db_flags | BT_REVERSEKEY, 0644);
1255d465952Smartinh if (ns->data_db == NULL)
1265d465952Smartinh return -1;
1275d465952Smartinh
1285d465952Smartinh btree_set_cache_size(ns->data_db, ns->cache_size);
1295d465952Smartinh
13095af8abfSderaadt if (asprintf(&ns->indx_path, "%s/%s_indx.db", datadir, ns->suffix) == -1)
1315d465952Smartinh return -1;
1325d465952Smartinh ns->indx_db = btree_open(ns->indx_path, db_flags, 0644);
1335d465952Smartinh if (ns->indx_db == NULL)
1345d465952Smartinh return -1;
1355d465952Smartinh
1365d465952Smartinh btree_set_cache_size(ns->indx_db, ns->index_cache_size);
1375d465952Smartinh
1385d465952Smartinh /* prepare request queue scheduler */
1395d465952Smartinh evtimer_set(&ns->ev_queue, namespace_queue_replay, ns);
1405d465952Smartinh
1415d465952Smartinh return 0;
1425d465952Smartinh }
1435d465952Smartinh
144a9ac9ba1Smartinh static int
namespace_reopen(const char * path)145a9ac9ba1Smartinh namespace_reopen(const char *path)
146a9ac9ba1Smartinh {
147a9ac9ba1Smartinh struct open_req req;
148a9ac9ba1Smartinh
149a9ac9ba1Smartinh log_debug("asking parent to open %s", path);
150a9ac9ba1Smartinh
15137f4b933Smmcc memset(&req, 0, sizeof(req));
152a9ac9ba1Smartinh if (strlcpy(req.path, path, sizeof(req.path)) >= sizeof(req.path)) {
153a9ac9ba1Smartinh log_warnx("%s: path truncated", __func__);
154a9ac9ba1Smartinh return -1;
155a9ac9ba1Smartinh }
156a9ac9ba1Smartinh
157bb773af3Smartinh return imsgev_compose(iev_ldapd, IMSG_LDAPD_OPEN, 0, 0, -1, &req,
158a9ac9ba1Smartinh sizeof(req));
159a9ac9ba1Smartinh }
160a9ac9ba1Smartinh
1615d465952Smartinh int
namespace_reopen_data(struct namespace * ns)1625d465952Smartinh namespace_reopen_data(struct namespace *ns)
1635d465952Smartinh {
164a9ac9ba1Smartinh if (ns->data_db != NULL) {
1655d465952Smartinh btree_close(ns->data_db);
166a9ac9ba1Smartinh ns->data_db = NULL;
167a9ac9ba1Smartinh return namespace_reopen(ns->data_path);
168a9ac9ba1Smartinh }
169a9ac9ba1Smartinh return 1;
1705d465952Smartinh }
1715d465952Smartinh
1725d465952Smartinh int
namespace_reopen_indx(struct namespace * ns)1735d465952Smartinh namespace_reopen_indx(struct namespace *ns)
1745d465952Smartinh {
175a9ac9ba1Smartinh if (ns->indx_db != NULL) {
1765d465952Smartinh btree_close(ns->indx_db);
177a9ac9ba1Smartinh ns->indx_db = NULL;
178a9ac9ba1Smartinh return namespace_reopen(ns->indx_path);
179a9ac9ba1Smartinh }
180a9ac9ba1Smartinh return 1;
1815d465952Smartinh }
1825d465952Smartinh
183898a5208Smartinh static int
namespace_set_fd(struct namespace * ns,struct btree ** bt,int fd,unsigned int flags)184898a5208Smartinh namespace_set_fd(struct namespace *ns, struct btree **bt, int fd,
185898a5208Smartinh unsigned int flags)
186898a5208Smartinh {
187898a5208Smartinh log_info("reopening namespace %s (entries)", ns->suffix);
188898a5208Smartinh btree_close(*bt);
189898a5208Smartinh if (ns->sync == 0)
190898a5208Smartinh flags |= BT_NOSYNC;
191898a5208Smartinh *bt = btree_open_fd(fd, flags);
192898a5208Smartinh if (*bt == NULL)
193898a5208Smartinh return -1;
194898a5208Smartinh return 0;
195898a5208Smartinh }
196898a5208Smartinh
197898a5208Smartinh int
namespace_set_data_fd(struct namespace * ns,int fd)198898a5208Smartinh namespace_set_data_fd(struct namespace *ns, int fd)
199898a5208Smartinh {
200898a5208Smartinh return namespace_set_fd(ns, &ns->data_db, fd, BT_REVERSEKEY);
201898a5208Smartinh }
202898a5208Smartinh
203898a5208Smartinh int
namespace_set_indx_fd(struct namespace * ns,int fd)204898a5208Smartinh namespace_set_indx_fd(struct namespace *ns, int fd)
205898a5208Smartinh {
206898a5208Smartinh return namespace_set_fd(ns, &ns->indx_db, fd, 0);
207898a5208Smartinh }
208898a5208Smartinh
2095d465952Smartinh void
namespace_close(struct namespace * ns)2105d465952Smartinh namespace_close(struct namespace *ns)
2115d465952Smartinh {
2125d465952Smartinh struct conn *conn;
2135d465952Smartinh struct search *search, *next;
2145d465952Smartinh struct request *req;
2155d465952Smartinh
2165d465952Smartinh /* Cancel any queued requests for this namespace.
2175d465952Smartinh */
2185d465952Smartinh if (ns->queued_requests > 0) {
2195d465952Smartinh log_warnx("cancelling %u queued requests on namespace %s",
2205d465952Smartinh ns->queued_requests, ns->suffix);
2215d465952Smartinh while ((req = TAILQ_FIRST(&ns->request_queue)) != NULL) {
2225d465952Smartinh TAILQ_REMOVE(&ns->request_queue, req, next);
2235d465952Smartinh ldap_respond(req, LDAP_UNAVAILABLE);
2245d465952Smartinh }
2255d465952Smartinh }
2265d465952Smartinh
2275d465952Smartinh /* Cancel any searches on this namespace.
2285d465952Smartinh */
2295d465952Smartinh TAILQ_FOREACH(conn, &conn_list, next) {
2305d465952Smartinh for (search = TAILQ_FIRST(&conn->searches); search != NULL;
2315d465952Smartinh search = next) {
2325d465952Smartinh next = TAILQ_NEXT(search, next);
2335d465952Smartinh if (search->ns == ns)
2345d465952Smartinh search_close(search);
2355d465952Smartinh }
2365d465952Smartinh }
2375d465952Smartinh
2385d465952Smartinh free(ns->suffix);
2395d465952Smartinh btree_close(ns->data_db);
2405d465952Smartinh btree_close(ns->indx_db);
2415d465952Smartinh if (evtimer_pending(&ns->ev_queue, NULL))
2425d465952Smartinh evtimer_del(&ns->ev_queue);
2435d465952Smartinh free(ns->data_path);
2445d465952Smartinh free(ns->indx_path);
2455d465952Smartinh free(ns);
2465d465952Smartinh }
2475d465952Smartinh
2485d465952Smartinh void
namespace_remove(struct namespace * ns)2495d465952Smartinh namespace_remove(struct namespace *ns)
2505d465952Smartinh {
2515d465952Smartinh TAILQ_REMOVE(&conf->namespaces, ns, next);
2525d465952Smartinh namespace_close(ns);
2535d465952Smartinh }
2545d465952Smartinh
2555d465952Smartinh static struct btval *
namespace_find(struct namespace * ns,char * dn)2565d465952Smartinh namespace_find(struct namespace *ns, char *dn)
2575d465952Smartinh {
2585d465952Smartinh struct btval key;
2595d465952Smartinh static struct btval val;
2605d465952Smartinh
2610279e526Smartinh if (ns->data_db == NULL) {
2620279e526Smartinh errno = EBUSY; /* namespace is being reopened */
2630279e526Smartinh return NULL;
2640279e526Smartinh }
2650279e526Smartinh
26637f4b933Smmcc memset(&key, 0, sizeof(key));
26737f4b933Smmcc memset(&val, 0, sizeof(val));
2685d465952Smartinh
2695d465952Smartinh key.data = dn;
2705d465952Smartinh key.size = strlen(dn);
2715d465952Smartinh
2720279e526Smartinh if (btree_txn_get(ns->data_db, ns->data_txn, &key, &val) != 0) {
2730279e526Smartinh if (errno == ENOENT)
2745d465952Smartinh log_debug("%s: dn not found", dn);
2750279e526Smartinh else
2760279e526Smartinh log_warn("%s", dn);
2770279e526Smartinh
2780279e526Smartinh if (errno == ESTALE)
2790279e526Smartinh namespace_reopen_data(ns);
2800279e526Smartinh
2815d465952Smartinh return NULL;
2825d465952Smartinh }
2835d465952Smartinh
2845d465952Smartinh return &val;
2855d465952Smartinh }
2865d465952Smartinh
2875d465952Smartinh struct ber_element *
namespace_get(struct namespace * ns,char * dn)2885d465952Smartinh namespace_get(struct namespace *ns, char *dn)
2895d465952Smartinh {
2905d465952Smartinh struct ber_element *elm;
2915d465952Smartinh struct btval *val;
2925d465952Smartinh
2935d465952Smartinh if ((val = namespace_find(ns, dn)) == NULL)
2945d465952Smartinh return NULL;
2955d465952Smartinh
2965d465952Smartinh elm = namespace_db2ber(ns, val);
2975d465952Smartinh btval_reset(val);
2985d465952Smartinh return elm;
2995d465952Smartinh }
3005d465952Smartinh
3015d465952Smartinh int
namespace_exists(struct namespace * ns,char * dn)3025d465952Smartinh namespace_exists(struct namespace *ns, char *dn)
3035d465952Smartinh {
3045d465952Smartinh struct btval *val;
3055d465952Smartinh
3065d465952Smartinh if ((val = namespace_find(ns, dn)) == NULL)
3075d465952Smartinh return 0;
3085d465952Smartinh btval_reset(val);
3095d465952Smartinh return 1;
3105d465952Smartinh }
3115d465952Smartinh
3125d465952Smartinh int
namespace_ber2db(struct namespace * ns,struct ber_element * root,struct btval * val)3135d465952Smartinh namespace_ber2db(struct namespace *ns, struct ber_element *root,
3145d465952Smartinh struct btval *val)
3155d465952Smartinh {
316f5f15bc0Smartinh return ber2db(root, val, ns->compression_level);
3175d465952Smartinh }
3185d465952Smartinh
3195d465952Smartinh struct ber_element *
namespace_db2ber(struct namespace * ns,struct btval * val)3205d465952Smartinh namespace_db2ber(struct namespace *ns, struct btval *val)
3215d465952Smartinh {
322f5f15bc0Smartinh return db2ber(val, ns->compression_level);
3235d465952Smartinh }
3245d465952Smartinh
3255d465952Smartinh static int
namespace_put(struct namespace * ns,char * dn,struct ber_element * root,int update)3265d465952Smartinh namespace_put(struct namespace *ns, char *dn, struct ber_element *root,
3275d465952Smartinh int update)
3285d465952Smartinh {
3295d465952Smartinh int rc;
3305d465952Smartinh struct btval key, val;
3315d465952Smartinh
3325d465952Smartinh assert(ns != NULL);
333a9ac9ba1Smartinh assert(ns->data_txn != NULL);
334a9ac9ba1Smartinh assert(ns->indx_txn != NULL);
3355d465952Smartinh
33637f4b933Smmcc memset(&key, 0, sizeof(key));
3375d465952Smartinh key.data = dn;
3385d465952Smartinh key.size = strlen(dn);
3395d465952Smartinh
3405d465952Smartinh if (namespace_ber2db(ns, root, &val) != 0)
3415d465952Smartinh return BT_FAIL;
3425d465952Smartinh
343b91780d1Smartinh rc = btree_txn_put(NULL, ns->data_txn, &key, &val,
3445d465952Smartinh update ? 0 : BT_NOOVERWRITE);
3455d465952Smartinh if (rc != BT_SUCCESS) {
3460279e526Smartinh if (errno == EEXIST)
3475d465952Smartinh log_debug("%s: already exists", dn);
3485d465952Smartinh else
3495d465952Smartinh log_warn("%s", dn);
350a9ac9ba1Smartinh goto done;
3515d465952Smartinh }
3525d465952Smartinh
3535d465952Smartinh /* FIXME: if updating, try harder to just update changed indices.
3545d465952Smartinh */
3550279e526Smartinh if (update && (rc = unindex_entry(ns, &key, root)) != BT_SUCCESS)
356a9ac9ba1Smartinh goto done;
3575d465952Smartinh
358a9ac9ba1Smartinh rc = index_entry(ns, &key, root);
3595d465952Smartinh
360a9ac9ba1Smartinh done:
3615d465952Smartinh btval_reset(&val);
3625d465952Smartinh return rc;
3635d465952Smartinh }
3645d465952Smartinh
3655d465952Smartinh int
namespace_add(struct namespace * ns,char * dn,struct ber_element * root)3665d465952Smartinh namespace_add(struct namespace *ns, char *dn, struct ber_element *root)
3675d465952Smartinh {
3685d465952Smartinh return namespace_put(ns, dn, root, 0);
3695d465952Smartinh }
3705d465952Smartinh
3715d465952Smartinh int
namespace_update(struct namespace * ns,char * dn,struct ber_element * root)3725d465952Smartinh namespace_update(struct namespace *ns, char *dn, struct ber_element *root)
3735d465952Smartinh {
3745d465952Smartinh return namespace_put(ns, dn, root, 1);
3755d465952Smartinh }
3765d465952Smartinh
3775d465952Smartinh int
namespace_del(struct namespace * ns,char * dn)3785d465952Smartinh namespace_del(struct namespace *ns, char *dn)
3795d465952Smartinh {
3805d465952Smartinh int rc;
3815d465952Smartinh struct ber_element *root;
3825d465952Smartinh struct btval key, data;
3835d465952Smartinh
3845d465952Smartinh assert(ns != NULL);
385a9ac9ba1Smartinh assert(ns->indx_txn != NULL);
386a9ac9ba1Smartinh assert(ns->data_txn != NULL);
3875d465952Smartinh
38837f4b933Smmcc memset(&key, 0, sizeof(key));
38937f4b933Smmcc memset(&data, 0, sizeof(data));
3905d465952Smartinh
3915d465952Smartinh key.data = dn;
3925d465952Smartinh key.size = strlen(key.data);
3935d465952Smartinh
394b91780d1Smartinh rc = btree_txn_del(NULL, ns->data_txn, &key, &data);
395a9ac9ba1Smartinh if (rc == BT_SUCCESS && (root = namespace_db2ber(ns, &data)) != NULL)
396a9ac9ba1Smartinh rc = unindex_entry(ns, &key, root);
3975d465952Smartinh
3985d465952Smartinh btval_reset(&data);
3995d465952Smartinh return rc;
4005d465952Smartinh }
4015d465952Smartinh
40238c09006Smartinh int
namespace_has_referrals(struct namespace * ns)40338c09006Smartinh namespace_has_referrals(struct namespace *ns)
40438c09006Smartinh {
40538c09006Smartinh return !SLIST_EMPTY(&ns->referrals);
40638c09006Smartinh }
40738c09006Smartinh
4085d465952Smartinh struct namespace *
namespace_lookup_base(const char * basedn,int include_referrals)40938c09006Smartinh namespace_lookup_base(const char *basedn, int include_referrals)
4105d465952Smartinh {
4115d465952Smartinh size_t blen, slen;
41238c09006Smartinh struct namespace *ns, *matched_ns = NULL;
4135d465952Smartinh
4145d465952Smartinh assert(basedn);
4155d465952Smartinh blen = strlen(basedn);
4165d465952Smartinh
4175d465952Smartinh TAILQ_FOREACH(ns, &conf->namespaces, next) {
4185d465952Smartinh slen = strlen(ns->suffix);
41938c09006Smartinh if ((include_referrals || !namespace_has_referrals(ns)) &&
42038c09006Smartinh blen >= slen &&
42138c09006Smartinh bcmp(basedn + blen - slen, ns->suffix, slen) == 0) {
42238c09006Smartinh /* Match the longest namespace suffix. */
42338c09006Smartinh if (matched_ns == NULL ||
42438c09006Smartinh strlen(ns->suffix) > strlen(matched_ns->suffix))
42538c09006Smartinh matched_ns = ns;
4265d465952Smartinh }
42738c09006Smartinh }
42838c09006Smartinh
42938c09006Smartinh return matched_ns;
43038c09006Smartinh }
43138c09006Smartinh
43238c09006Smartinh struct namespace *
namespace_for_base(const char * basedn)43338c09006Smartinh namespace_for_base(const char *basedn)
43438c09006Smartinh {
43538c09006Smartinh return namespace_lookup_base(basedn, 0);
43638c09006Smartinh }
43738c09006Smartinh
43838c09006Smartinh struct referrals *
namespace_referrals(const char * basedn)43938c09006Smartinh namespace_referrals(const char *basedn)
44038c09006Smartinh {
44138c09006Smartinh struct namespace *ns;
44238c09006Smartinh
44338c09006Smartinh if ((ns = namespace_lookup_base(basedn, 1)) != NULL &&
44438c09006Smartinh namespace_has_referrals(ns))
44538c09006Smartinh return &ns->referrals;
44638c09006Smartinh
44738c09006Smartinh if (!SLIST_EMPTY(&conf->referrals))
44838c09006Smartinh return &conf->referrals;
4495d465952Smartinh
4505d465952Smartinh return NULL;
4515d465952Smartinh }
4525d465952Smartinh
4535d465952Smartinh int
namespace_has_index(struct namespace * ns,const char * attr,enum index_type type)4545d465952Smartinh namespace_has_index(struct namespace *ns, const char *attr,
4555d465952Smartinh enum index_type type)
4565d465952Smartinh {
4575d465952Smartinh struct attr_index *ai;
4585d465952Smartinh
4595d465952Smartinh assert(ns);
4605d465952Smartinh assert(attr);
4615d465952Smartinh TAILQ_FOREACH(ai, &ns->indices, next) {
4625d465952Smartinh if (strcasecmp(attr, ai->attr) == 0 && ai->type == type)
4635d465952Smartinh return 1;
4645d465952Smartinh }
4655d465952Smartinh
4665d465952Smartinh return 0;
4675d465952Smartinh }
4685d465952Smartinh
469a9ac9ba1Smartinh /* Queues modification requests while the namespace is being reopened.
4705d465952Smartinh */
4715d465952Smartinh int
namespace_queue_request(struct namespace * ns,struct request * req)4725d465952Smartinh namespace_queue_request(struct namespace *ns, struct request *req)
4735d465952Smartinh {
4745d465952Smartinh if (ns->queued_requests > MAX_REQUEST_QUEUE) {
475c0785a05Sreyk log_warn("%u requests already queued, sorry",
476c0785a05Sreyk ns->queued_requests);
4775d465952Smartinh return -1;
4785d465952Smartinh }
4795d465952Smartinh
4805d465952Smartinh TAILQ_INSERT_TAIL(&ns->request_queue, req, next);
4815d465952Smartinh ns->queued_requests++;
482a8b81f96Smartinh
483a8b81f96Smartinh if (!evtimer_pending(&ns->ev_queue, NULL))
484a8b81f96Smartinh namespace_queue_schedule(ns, 250000);
485a8b81f96Smartinh
4865d465952Smartinh return 0;
4875d465952Smartinh }
4885d465952Smartinh
4895d465952Smartinh static void
namespace_queue_replay(int fd,short event,void * data)4905d465952Smartinh namespace_queue_replay(int fd, short event, void *data)
4915d465952Smartinh {
4925d465952Smartinh struct namespace *ns = data;
4935d465952Smartinh struct request *req;
4945d465952Smartinh
495a9ac9ba1Smartinh if (ns->data_db == NULL || ns->indx_db == NULL) {
496a9ac9ba1Smartinh log_debug("%s: database is being reopened", ns->suffix);
497a9ac9ba1Smartinh return; /* Database is being reopened. */
498a9ac9ba1Smartinh }
499a9ac9ba1Smartinh
5005d465952Smartinh if ((req = TAILQ_FIRST(&ns->request_queue)) == NULL)
5015d465952Smartinh return;
5025d465952Smartinh TAILQ_REMOVE(&ns->request_queue, req, next);
5035d465952Smartinh
504a9ac9ba1Smartinh log_debug("replaying queued request");
5055d465952Smartinh req->replayed = 1;
5065d465952Smartinh request_dispatch(req);
5075d465952Smartinh ns->queued_requests--;
508a8b81f96Smartinh
509a8b81f96Smartinh if (!evtimer_pending(&ns->ev_queue, NULL))
510a8b81f96Smartinh namespace_queue_schedule(ns, 0);
5115d465952Smartinh }
5125d465952Smartinh
5135d465952Smartinh void
namespace_queue_schedule(struct namespace * ns,unsigned int usec)514a8b81f96Smartinh namespace_queue_schedule(struct namespace *ns, unsigned int usec)
5155d465952Smartinh {
5165d465952Smartinh struct timeval tv;
5175d465952Smartinh
5185d465952Smartinh tv.tv_sec = 0;
519a8b81f96Smartinh tv.tv_usec = usec;
5205d465952Smartinh evtimer_add(&ns->ev_queue, &tv);
5215d465952Smartinh }
5225d465952Smartinh
5235d465952Smartinh /* Cancel all queued requests from the given connection. Drops matching
5245d465952Smartinh * requests from all namespaces without sending a response.
5255d465952Smartinh */
5265d465952Smartinh void
namespace_cancel_conn(struct conn * conn)5275d465952Smartinh namespace_cancel_conn(struct conn *conn)
5285d465952Smartinh {
5295d465952Smartinh struct namespace *ns;
5305d465952Smartinh struct request *req, *next;
5315d465952Smartinh
5325d465952Smartinh TAILQ_FOREACH(ns, &conf->namespaces, next) {
533abcbcc4dSdoug for (req = TAILQ_FIRST(&ns->request_queue); req != NULL;
534abcbcc4dSdoug req = next) {
5355d465952Smartinh next = TAILQ_NEXT(req, next);
5365d465952Smartinh
5375d465952Smartinh if (req->conn == conn) {
5385d465952Smartinh TAILQ_REMOVE(&ns->request_queue, req, next);
5395d465952Smartinh request_free(req);
5405d465952Smartinh }
5415d465952Smartinh }
5425d465952Smartinh }
5435d465952Smartinh }
5445d465952Smartinh
5450d43ad28Sjmatthew int
namespace_conn_queue_count(struct conn * conn)5460d43ad28Sjmatthew namespace_conn_queue_count(struct conn *conn)
5470d43ad28Sjmatthew {
5480d43ad28Sjmatthew struct namespace *ns;
5490d43ad28Sjmatthew struct request *req;
5500d43ad28Sjmatthew int count = 0;
5510d43ad28Sjmatthew
5520d43ad28Sjmatthew TAILQ_FOREACH(ns, &conf->namespaces, next) {
5530d43ad28Sjmatthew TAILQ_FOREACH(req, &ns->request_queue, next) {
5540d43ad28Sjmatthew if (req->conn == conn)
5550d43ad28Sjmatthew count++;
5560d43ad28Sjmatthew }
5570d43ad28Sjmatthew }
5580d43ad28Sjmatthew
5590d43ad28Sjmatthew return count;
5600d43ad28Sjmatthew }
561