f6009ba48d0584269c43df2a9d2b2bd633fce7d9
[bluesky.git] / bluesky / store-multi.c
1 /* Blue Sky: File Systems in the Cloud
2  *
3  * Copyright (C) 2009  The Regents of the University of California
4  * Written by Michael Vrable <mvrable@cs.ucsd.edu>
5  *
6  * TODO: Licensing
7  */
8
9 /* A stacked storage implementation which tries to improve performance by
10  * duplicating GET requests.  Create using a name like "multi:s3" and each GET
11  * request will be translated into two GET requests to the "s3" backend.  The
12  * first to complete will have its results returned. */
13
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <glib.h>
17 #include <string.h>
18
19 #include "bluesky-private.h"
20
21 struct MultiRequest {
22 };
23
24 static gpointer multistore_new(const gchar *path)
25 {
26     BlueSkyStore *base = bluesky_store_new(path);
27     if (base == NULL) {
28         g_warning("Unable to create base store %s for multirequest stacking.",
29                   path);
30     }
31
32     return base;
33 }
34
35 static void multistore_destroy(gpointer store)
36 {
37     bluesky_store_free(store);
38 }
39
40 static void multistore_completion_handler(BlueSkyStoreAsync *async,
41                                           BlueSkyStoreAsync *top_async)
42 {
43     g_mutex_lock(top_async->lock);
44
45     /* This might be the second request to finish; in that case we don't do
46      * anything. */
47     if (top_async->status == ASYNC_RUNNING) {
48         if (top_async->op == STORE_OP_GET) {
49             bluesky_string_unref(top_async->data);
50             top_async->data = async->data;
51             bluesky_string_ref(top_async->data);
52         }
53         top_async->result = async->result;
54         bluesky_store_async_mark_complete(top_async);
55     }
56
57     g_mutex_unlock(top_async->lock);
58     bluesky_store_async_unref(top_async);
59 }
60
61 static void multistore_submit(gpointer store, BlueSkyStoreAsync *async)
62 {
63     BlueSkyStore *base = (BlueSkyStore *)store;
64
65     g_return_if_fail(async->status == ASYNC_NEW);
66     g_return_if_fail(async->op != STORE_OP_NONE);
67
68     switch (async->op) {
69     case STORE_OP_GET:
70         async->status = ASYNC_RUNNING;
71         async->exec_time = bluesky_now_hires();
72         for (int i = 0; i < 2; i++) {
73             BlueSkyStoreAsync *a = bluesky_store_async_new(base);
74             a->op = STORE_OP_GET;
75             a->key = g_strdup(async->key);
76             bluesky_store_async_ref(async);
77             bluesky_store_async_add_notifier(a, (GFunc)multistore_completion_handler, async);
78             bluesky_store_async_submit(a);
79             bluesky_store_async_unref(a);
80         }
81         break;
82
83     case STORE_OP_PUT:
84     {
85         async->status = ASYNC_RUNNING;
86         async->exec_time = bluesky_now_hires();
87
88         bluesky_store_async_ref(async);
89         BlueSkyStoreAsync *a = bluesky_store_async_new(base);
90         a->op = STORE_OP_PUT;
91         a->key = g_strdup(async->key);
92         a->data = async->data;
93         bluesky_string_ref(a->data);
94         bluesky_store_async_add_notifier(a, (GFunc)multistore_completion_handler, async);
95         bluesky_store_async_submit(a);
96         bluesky_store_async_unref(a);
97         break;
98     }
99
100     default:
101         g_warning("Uknown operation type for multistore: %d\n", async->op);
102         bluesky_store_async_mark_complete(async);
103         break;
104     }
105 }
106
107 static char *multistore_lookup_last(gpointer store, const char *prefix)
108 {
109     BlueSkyStore *base = (BlueSkyStore *)store;
110     return bluesky_store_lookup_last(base, prefix);
111 }
112
113 static void multistore_cleanup(gpointer store, BlueSkyStoreAsync *async)
114 {
115 }
116
117 static BlueSkyStoreImplementation store_impl = {
118     .create = multistore_new,
119     .destroy = multistore_destroy,
120     .submit = multistore_submit,
121     .cleanup = multistore_cleanup,
122     .lookup_last = multistore_lookup_last,
123 };
124
125 void bluesky_store_init_multi(void)
126 {
127     bluesky_store_register(&store_impl, "multi");
128 }