Merge "res_calendar: Specialized calendars depend on symbols of general calendar."
[asterisk/asterisk.git] / main / stasis_cache_pattern.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * David M. Lee, II <dlee@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Typical cache pattern for Stasis topics.
22  *
23  * \author David M. Lee, II <dlee@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/astobj2.h"
33 #include "asterisk/stasis_cache_pattern.h"
34
35 struct stasis_cp_all {
36         struct stasis_topic *topic;
37         struct stasis_topic *topic_cached;
38         struct stasis_cache *cache;
39
40         struct stasis_forward *forward_all_to_cached;
41 };
42
43 struct stasis_cp_single {
44         struct stasis_topic *topic;
45         struct stasis_caching_topic *topic_cached;
46
47         struct stasis_forward *forward_topic_to_all;
48         struct stasis_forward *forward_cached_to_all;
49 };
50
51 static void all_dtor(void *obj)
52 {
53         struct stasis_cp_all *all = obj;
54
55         ao2_cleanup(all->topic);
56         all->topic = NULL;
57         ao2_cleanup(all->topic_cached);
58         all->topic_cached = NULL;
59         ao2_cleanup(all->cache);
60         all->cache = NULL;
61         stasis_forward_cancel(all->forward_all_to_cached);
62         all->forward_all_to_cached = NULL;
63 }
64
65 struct stasis_cp_all *stasis_cp_all_create(const char *name,
66         snapshot_get_id id_fn)
67 {
68         char *cached_name = NULL;
69         struct stasis_cp_all *all;
70
71         all = ao2_t_alloc(sizeof(*all), all_dtor, name);
72         if (!all) {
73                 return NULL;
74         }
75
76         ast_asprintf(&cached_name, "%s-cached", name);
77         if (!cached_name) {
78                 ao2_ref(all, -1);
79
80                 return NULL;
81         }
82
83         all->topic = stasis_topic_create(name);
84         all->topic_cached = stasis_topic_create(cached_name);
85         ast_free(cached_name);
86         all->cache = stasis_cache_create(id_fn);
87         all->forward_all_to_cached =
88                 stasis_forward_all(all->topic, all->topic_cached);
89
90         if (!all->topic || !all->topic_cached || !all->cache ||
91                 !all->forward_all_to_cached) {
92                 ao2_ref(all, -1);
93
94                 return NULL;
95         }
96
97         return all;
98 }
99
100 struct stasis_topic *stasis_cp_all_topic(struct stasis_cp_all *all)
101 {
102         if (!all) {
103                 return NULL;
104         }
105         return all->topic;
106 }
107
108 struct stasis_topic *stasis_cp_all_topic_cached(
109         struct stasis_cp_all *all)
110 {
111         if (!all) {
112                 return NULL;
113         }
114         return all->topic_cached;
115 }
116
117 struct stasis_cache *stasis_cp_all_cache(struct stasis_cp_all *all)
118 {
119         if (!all) {
120                 return NULL;
121         }
122         return all->cache;
123 }
124
125 static void one_dtor(void *obj)
126 {
127         struct stasis_cp_single *one = obj;
128
129         /* Should already be unsubscribed */
130         ast_assert(one->topic_cached == NULL);
131         ast_assert(one->forward_topic_to_all == NULL);
132         ast_assert(one->forward_cached_to_all == NULL);
133
134         ao2_cleanup(one->topic);
135         one->topic = NULL;
136 }
137
138 struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all,
139         const char *name)
140 {
141         struct stasis_cp_single *one;
142
143         one = stasis_cp_sink_create(all, name);
144         if (!one) {
145                 return NULL;
146         }
147
148         one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic);
149         one->forward_cached_to_all = stasis_forward_all(
150                 stasis_caching_get_topic(one->topic_cached), all->topic_cached);
151
152         if (!one->forward_topic_to_all || !one->forward_cached_to_all) {
153                 ao2_ref(one, -1);
154
155                 return NULL;
156         }
157
158         return one;
159 }
160
161 struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all,
162         const char *name)
163 {
164         struct stasis_cp_single *one;
165
166         one = ao2_t_alloc(sizeof(*one), one_dtor, name);
167         if (!one) {
168                 return NULL;
169         }
170
171         one->topic = stasis_topic_create(name);
172         if (!one->topic) {
173                 ao2_ref(one, -1);
174
175                 return NULL;
176         }
177
178         one->topic_cached = stasis_caching_topic_create(one->topic, all->cache);
179         if (!one->topic_cached) {
180                 ao2_ref(one, -1);
181
182                 return NULL;
183         }
184
185         return one;
186 }
187
188 void stasis_cp_single_unsubscribe(struct stasis_cp_single *one)
189 {
190         if (!one) {
191                 return;
192         }
193
194         stasis_forward_cancel(one->forward_topic_to_all);
195         one->forward_topic_to_all = NULL;
196         stasis_forward_cancel(one->forward_cached_to_all);
197         one->forward_cached_to_all = NULL;
198         stasis_caching_unsubscribe(one->topic_cached);
199         one->topic_cached = NULL;
200
201         ao2_cleanup(one);
202 }
203
204 struct stasis_topic *stasis_cp_single_topic(struct stasis_cp_single *one)
205 {
206         if (!one) {
207                 return NULL;
208         }
209         return one->topic;
210 }
211
212 struct stasis_topic *stasis_cp_single_topic_cached(
213         struct stasis_cp_single *one)
214 {
215         if (!one) {
216                 return NULL;
217         }
218         return stasis_caching_get_topic(one->topic_cached);
219 }