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-1335  USA
17 */
18 
19 #include "grn_ctx.h"
20 #include "grn_ctx_impl.h"
21 #include "grn_request_canceler.h"
22 
23 typedef struct _grn_request_canceler grn_request_canceler;
24 struct _grn_request_canceler {
25   grn_hash *entries;
26   grn_mutex mutex;
27 };
28 
29 typedef struct _grn_request_canceler_entry grn_request_canceler_entry;
30 struct _grn_request_canceler_entry {
31   grn_ctx *ctx;
32 };
33 
34 static grn_ctx grn_the_request_canceler_ctx;
35 static grn_request_canceler *grn_the_request_canceler = NULL;
36 
37 grn_bool
grn_request_canceler_init(void)38 grn_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 
62 void
grn_request_canceler_register(grn_ctx * ctx,const char * request_id,unsigned int size)63 grn_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 
81 void
grn_request_canceler_unregister(grn_ctx * ctx,const char * request_id,unsigned int size)82 grn_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 
100 static grn_bool
grn_request_canceler_cancel_entry(grn_request_canceler_entry * entry)101 grn_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 
116 grn_bool
grn_request_canceler_cancel(const char * request_id,unsigned int size)117 grn_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 
136 grn_bool
grn_request_canceler_cancel_all(void)137 grn_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 
166 void
grn_request_canceler_fin(void)167 grn_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