No issues found
1 /*
2 * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
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
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 * Author: Carlos Garnacho <carlos@lanedo.com>
20 */
21
22 #include "config.h"
23
24 #include "tracker-task-pool.h"
25
26 enum {
27 PROP_0,
28 PROP_LIMIT,
29 PROP_LIMIT_REACHED
30 };
31
32 G_DEFINE_TYPE (TrackerTaskPool, tracker_task_pool, G_TYPE_OBJECT)
33
34 typedef struct _TrackerTaskPoolPrivate TrackerTaskPoolPrivate;
35
36 struct _TrackerTaskPoolPrivate
37 {
38 GHashTable *tasks;
39 guint limit;
40 };
41
42 struct _TrackerTask
43 {
44 GFile *file;
45 gpointer data;
46 GDestroyNotify destroy_notify;
47 gint ref_count;
48 };
49
50 static void
51 tracker_task_pool_finalize (GObject *object)
52 {
53 TrackerTaskPoolPrivate *priv;
54
55 priv = TRACKER_TASK_POOL (object)->priv;
56 g_hash_table_destroy (priv->tasks);
57
58 G_OBJECT_CLASS (tracker_task_pool_parent_class)->finalize (object);
59 }
60
61 static void
62 tracker_task_pool_set_property (GObject *object,
63 guint param_id,
64 const GValue *value,
65 GParamSpec *pspec)
66 {
67 TrackerTaskPool *pool = TRACKER_TASK_POOL (object);
68
69
70 switch (param_id) {
71 case PROP_LIMIT:
72 tracker_task_pool_set_limit (pool,
73 g_value_get_uint (value));
74 break;
75 default:
76 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
77 }
78 }
79
80 static void
81 tracker_task_pool_get_property (GObject *object,
82 guint param_id,
83 GValue *value,
84 GParamSpec *pspec)
85 {
86 TrackerTaskPool *pool = TRACKER_TASK_POOL (object);
87
88 switch (param_id) {
89 case PROP_LIMIT:
90 g_value_set_uint (value,
91 tracker_task_pool_get_limit (pool));
92 break;
93 case PROP_LIMIT_REACHED:
94 g_value_set_boolean (value,
95 tracker_task_pool_limit_reached (pool));
96 break;
97 default:
98 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
99 }
100 }
101
102 static void
103 tracker_task_pool_class_init (TrackerTaskPoolClass *klass)
104 {
105 GObjectClass *object_class = G_OBJECT_CLASS (klass);
106
107 object_class->finalize = tracker_task_pool_finalize;
108 object_class->set_property = tracker_task_pool_set_property;
109 object_class->get_property = tracker_task_pool_get_property;
110
111 g_object_class_install_property (object_class,
112 PROP_LIMIT,
113 g_param_spec_uint ("limit",
114 "Limit",
115 "Task limit",
116 1, G_MAXUINT, 1,
117 G_PARAM_READWRITE));
118 g_object_class_install_property (object_class,
119 PROP_LIMIT_REACHED,
120 g_param_spec_boolean ("limit-reached",
121 "Limit reached",
122 "Task limit reached",
123 FALSE,
124 G_PARAM_READABLE));
125
126 g_type_class_add_private (klass, sizeof (TrackerTaskPoolPrivate));
127 }
128
129 static gboolean
130 file_equal (GFile *file1,
131 GFile *file2)
132 {
133 if (file1 == file2) {
134 return TRUE;
135 } else {
136 return g_file_equal (file1, file2);
137 }
138 }
139
140 static void
141 tracker_task_pool_init (TrackerTaskPool *pool)
142 {
143 TrackerTaskPoolPrivate *priv;
144
145 priv = pool->priv = G_TYPE_INSTANCE_GET_PRIVATE (pool,
146 TRACKER_TYPE_TASK_POOL,
147 TrackerTaskPoolPrivate);
148 priv->tasks = g_hash_table_new_full (g_file_hash,
149 (GEqualFunc) file_equal, NULL,
150 (GDestroyNotify) tracker_task_unref);
151 priv->limit = 0;
152 }
153
154 TrackerTaskPool *
155 tracker_task_pool_new (guint limit)
156 {
157 return g_object_new (TRACKER_TYPE_TASK_POOL,
158 "limit", limit,
159 NULL);
160 }
161
162 void
163 tracker_task_pool_set_limit (TrackerTaskPool *pool,
164 guint limit)
165 {
166 TrackerTaskPoolPrivate *priv;
167 gboolean old_limit_reached;
168
169 g_return_if_fail (TRACKER_IS_TASK_POOL (pool));
170
171 old_limit_reached = tracker_task_pool_limit_reached (pool);
172
173 priv = pool->priv;
174 priv->limit = limit;
175
176 if (old_limit_reached !=
177 tracker_task_pool_limit_reached (pool)) {
178 g_object_notify (G_OBJECT (pool), "limit-reached");
179 }
180 }
181
182 guint
183 tracker_task_pool_get_limit (TrackerTaskPool *pool)
184 {
185 TrackerTaskPoolPrivate *priv;
186
187 g_return_val_if_fail (TRACKER_IS_TASK_POOL (pool), 0);
188
189 priv = pool->priv;
190 return priv->limit;
191 }
192
193 guint
194 tracker_task_pool_get_size (TrackerTaskPool *pool)
195 {
196 TrackerTaskPoolPrivate *priv;
197
198 g_return_val_if_fail (TRACKER_IS_TASK_POOL (pool), 0);
199
200 priv = pool->priv;
201 return g_hash_table_size (priv->tasks);
202 }
203
204 gboolean
205 tracker_task_pool_limit_reached (TrackerTaskPool *pool)
206 {
207 TrackerTaskPoolPrivate *priv;
208
209 g_return_val_if_fail (TRACKER_IS_TASK_POOL (pool), FALSE);
210
211 priv = pool->priv;
212 return (g_hash_table_size (priv->tasks) >= priv->limit);
213 }
214
215 void
216 tracker_task_pool_add (TrackerTaskPool *pool,
217 TrackerTask *task)
218 {
219 TrackerTaskPoolPrivate *priv;
220
221 g_return_if_fail (TRACKER_IS_TASK_POOL (pool));
222
223 priv = pool->priv;
224
225 g_hash_table_insert (priv->tasks,
226 tracker_task_get_file (task),
227 tracker_task_ref (task));
228
229 if (g_hash_table_size (priv->tasks) == priv->limit) {
230 g_object_notify (G_OBJECT (pool), "limit-reached");
231 }
232 }
233
234 gboolean
235 tracker_task_pool_remove (TrackerTaskPool *pool,
236 TrackerTask *task)
237 {
238 TrackerTaskPoolPrivate *priv;
239
240 g_return_val_if_fail (TRACKER_IS_TASK_POOL (pool), FALSE);
241
242 priv = pool->priv;
243
244 if (g_hash_table_remove (priv->tasks,
245 tracker_task_get_file (task))) {
246 if (g_hash_table_size (priv->tasks) == priv->limit - 1) {
247 /* We've gone below the threshold again */
248 g_object_notify (G_OBJECT (pool), "limit-reached");
249 }
250
251 return TRUE;
252 }
253
254 return FALSE;
255 }
256
257 void
258 tracker_task_pool_foreach (TrackerTaskPool *pool,
259 GFunc func,
260 gpointer user_data)
261 {
262 TrackerTaskPoolPrivate *priv;
263 GHashTableIter iter;
264 TrackerTask *task;
265
266 g_return_if_fail (TRACKER_IS_TASK_POOL (pool));
267 g_return_if_fail (func != NULL);
268
269 priv = pool->priv;
270 g_hash_table_iter_init (&iter, priv->tasks);
271
272 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &task)) {
273 (func) (task, user_data);
274 }
275 }
276
277 TrackerTask *
278 tracker_task_pool_find (TrackerTaskPool *pool,
279 GFile *file)
280 {
281 TrackerTaskPoolPrivate *priv;
282
283 g_return_val_if_fail (TRACKER_IS_TASK_POOL (pool), NULL);
284 g_return_val_if_fail (G_IS_FILE (file), NULL);
285
286 priv = pool->priv;
287 return g_hash_table_lookup (priv->tasks, file);
288 }
289
290 /* Task */
291 TrackerTask *
292 tracker_task_new (GFile *file,
293 gpointer data,
294 GDestroyNotify destroy_notify)
295 {
296 TrackerTask *task;
297
298 task = g_slice_new0 (TrackerTask);
299 task->file = g_object_ref (file);
300 task->destroy_notify = destroy_notify;
301 task->data = data;
302 task->ref_count = 1;
303
304 return task;
305 }
306
307 TrackerTask *
308 tracker_task_ref (TrackerTask *task)
309 {
310 g_return_val_if_fail (task != NULL, NULL);
311
312 g_atomic_int_inc (&task->ref_count);
313
314 return task;
315 }
316 void
317 tracker_task_unref (TrackerTask *task)
318 {
319 g_return_if_fail (task != NULL);
320
321 if (g_atomic_int_dec_and_test (&task->ref_count)) {
322 g_object_unref (task->file);
323
324 if (task->data &&
325 task->destroy_notify) {
326 (task->destroy_notify) (task->data);
327 }
328
329 g_slice_free (TrackerTask, task);
330 }
331 }
332
333 GFile *
334 tracker_task_get_file (TrackerTask *task)
335 {
336 g_return_val_if_fail (task != NULL, NULL);
337
338 return task->file;
339 }
340
341 gpointer
342 tracker_task_get_data (TrackerTask *task)
343 {
344 g_return_val_if_fail (task != NULL, NULL);
345
346 return task->data;
347 }