1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2014-2016 Brazil
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License version 2.1 as published by the Free Software Foundation.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "grn_ctx.h"
20#include "grn_ctx_impl.h"
21#include "grn_request_canceler.h"
22
23typedef struct _grn_request_canceler grn_request_canceler;
24struct _grn_request_canceler {
25 grn_hash *entries;
26 grn_mutex mutex;
27};
28
29typedef struct _grn_request_canceler_entry grn_request_canceler_entry;
30struct _grn_request_canceler_entry {
31 grn_ctx *ctx;
32};
33
34static grn_ctx grn_the_request_canceler_ctx;
35static grn_request_canceler *grn_the_request_canceler = NULL;
36
37grn_bool
38grn_request_canceler_init(void)
39{
40 grn_ctx *ctx = &grn_the_request_canceler_ctx;
41
42 grn_ctx_init(ctx, 0);
43
44 grn_the_request_canceler = GRN_MALLOC(sizeof(grn_request_canceler));
45 if (!grn_the_request_canceler) {
46 ERR(GRN_NO_MEMORY_AVAILABLE,
47 "[request-canceler] failed to allocate the global request canceler");
48 return GRN_FALSE;
49 }
50
51 grn_the_request_canceler->entries =
52 grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE,
53 sizeof(grn_request_canceler_entry), GRN_OBJ_KEY_VAR_SIZE);
54 if (!grn_the_request_canceler->entries) {
55 return GRN_FALSE;
56 }
57 MUTEX_INIT(grn_the_request_canceler->mutex);
58
59 return GRN_TRUE;
60}
61
62void
63grn_request_canceler_register(grn_ctx *ctx,
64 const char *request_id, unsigned int size)
65{
66 MUTEX_LOCK(grn_the_request_canceler->mutex);
67 {
68 grn_hash *entries = grn_the_request_canceler->entries;
69 grn_id id;
70 void *value;
71 id = grn_hash_add(&grn_the_request_canceler_ctx,
72 entries, request_id, size, &value, NULL);
73 if (id) {
74 grn_request_canceler_entry *entry = value;
75 entry->ctx = ctx;
76 }
77 }
78 MUTEX_UNLOCK(grn_the_request_canceler->mutex);
79}
80
81void
82grn_request_canceler_unregister(grn_ctx *ctx,
83 const char *request_id, unsigned int size)
84{
85 MUTEX_LOCK(grn_the_request_canceler->mutex);
86 {
87 grn_hash *entries = grn_the_request_canceler->entries;
88 grn_hash_delete(&grn_the_request_canceler_ctx,
89 entries, request_id, size, NULL);
90 }
91 MUTEX_UNLOCK(grn_the_request_canceler->mutex);
92
93 if (ctx->rc == GRN_CANCEL) {
94 ERRSET(ctx, GRN_LOG_NOTICE, ctx->rc,
95 "[request-canceler] a request is canceled: <%.*s>",
96 size, request_id);
97 }
98}
99
100static grn_bool
101grn_request_canceler_cancel_entry(grn_request_canceler_entry *entry)
102{
103 if (entry->ctx->rc == GRN_SUCCESS) {
104 entry->ctx->rc = GRN_CANCEL;
105 if (entry->ctx->impl->current_request_timer_id) {
106 void *timer_id = entry->ctx->impl->current_request_timer_id;
107 entry->ctx->impl->current_request_timer_id = NULL;
108 grn_request_timer_unregister(timer_id);
109 }
110 return GRN_TRUE;
111 } else {
112 return GRN_FALSE;
113 }
114}
115
116grn_bool
117grn_request_canceler_cancel(const char *request_id, unsigned int size)
118{
119 grn_bool canceled = GRN_FALSE;
120 MUTEX_LOCK(grn_the_request_canceler->mutex);
121 {
122 grn_ctx *ctx = &grn_the_request_canceler_ctx;
123 grn_hash *entries = grn_the_request_canceler->entries;
124 void *value;
125 if (grn_hash_get(ctx, entries, request_id, size, &value)) {
126 grn_request_canceler_entry *entry = value;
127 if (grn_request_canceler_cancel_entry(entry)) {
128 canceled = GRN_TRUE;
129 }
130 }
131 }
132 MUTEX_UNLOCK(grn_the_request_canceler->mutex);
133 return canceled;
134}
135
136grn_bool
137grn_request_canceler_cancel_all(void)
138{
139 grn_bool canceled = GRN_FALSE;
140 MUTEX_LOCK(grn_the_request_canceler->mutex);
141 {
142 grn_ctx *ctx = &grn_the_request_canceler_ctx;
143 grn_hash *entries = grn_the_request_canceler->entries;
144 grn_hash_cursor *cursor;
145
146 cursor = grn_hash_cursor_open(ctx, entries,
147 NULL, 0, NULL, 0,
148 0, -1, 0);
149 if (cursor) {
150 while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
151 void *value;
152 if (grn_hash_cursor_get_value(ctx, cursor, &value) > 0) {
153 grn_request_canceler_entry *entry = value;
154 if (grn_request_canceler_cancel_entry(entry)) {
155 canceled = GRN_TRUE;
156 }
157 }
158 }
159 grn_hash_cursor_close(ctx, cursor);
160 }
161 }
162 MUTEX_UNLOCK(grn_the_request_canceler->mutex);
163 return canceled;
164}
165
166void
167grn_request_canceler_fin(void)
168{
169 grn_ctx *ctx = &grn_the_request_canceler_ctx;
170
171 grn_hash_close(ctx, grn_the_request_canceler->entries);
172 MUTEX_FIN(grn_the_request_canceler->mutex);
173 GRN_FREE(grn_the_request_canceler);
174 grn_the_request_canceler = NULL;
175 grn_ctx_fin(ctx);
176}
177