Add proper per-file copyright notices/licenses and top-level license.
[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  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /* A stacked storage implementation which tries to improve performance by
32  * duplicating GET requests.  Create using a name like "multi:s3" and each GET
33  * request will be translated into two GET requests to the "s3" backend.  The
34  * first to complete will have its results returned. */
35
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <glib.h>
39 #include <string.h>
40
41 #include "bluesky-private.h"
42
43 struct MultiRequest {
44 };
45
46 static gpointer multistore_new(const gchar *path)
47 {
48     BlueSkyStore *base = bluesky_store_new(path);
49     if (base == NULL) {
50         g_warning("Unable to create base store %s for multirequest stacking.",
51                   path);
52     }
53
54     return base;
55 }
56
57 static void multistore_destroy(gpointer store)
58 {
59     bluesky_store_free(store);
60 }
61
62 static void multistore_completion_handler(BlueSkyStoreAsync *async,
63                                           BlueSkyStoreAsync *top_async)
64 {
65     g_mutex_lock(top_async->lock);
66
67     /* This might be the second request to finish; in that case we don't do
68      * anything. */
69     if (top_async->status == ASYNC_RUNNING) {
70         if (top_async->op == STORE_OP_GET) {
71             bluesky_string_unref(top_async->data);
72             top_async->data = async->data;
73             bluesky_string_ref(top_async->data);
74         }
75         top_async->result = async->result;
76         bluesky_store_async_mark_complete(top_async);
77     }
78
79     g_mutex_unlock(top_async->lock);
80     bluesky_store_async_unref(top_async);
81 }
82
83 static void multistore_submit(gpointer store, BlueSkyStoreAsync *async)
84 {
85     BlueSkyStore *base = (BlueSkyStore *)store;
86
87     g_return_if_fail(async->status == ASYNC_NEW);
88     g_return_if_fail(async->op != STORE_OP_NONE);
89
90     switch (async->op) {
91     case STORE_OP_GET:
92         async->status = ASYNC_RUNNING;
93         async->exec_time = bluesky_now_hires();
94         for (int i = 0; i < 2; i++) {
95             BlueSkyStoreAsync *a = bluesky_store_async_new(base);
96             a->op = STORE_OP_GET;
97             a->key = g_strdup(async->key);
98             bluesky_store_async_ref(async);
99             bluesky_store_async_add_notifier(a, (GFunc)multistore_completion_handler, async);
100             bluesky_store_async_submit(a);
101             bluesky_store_async_unref(a);
102         }
103         break;
104
105     case STORE_OP_PUT:
106     {
107         async->status = ASYNC_RUNNING;
108         async->exec_time = bluesky_now_hires();
109
110         bluesky_store_async_ref(async);
111         BlueSkyStoreAsync *a = bluesky_store_async_new(base);
112         a->op = STORE_OP_PUT;
113         a->key = g_strdup(async->key);
114         a->data = async->data;
115         bluesky_string_ref(a->data);
116         bluesky_store_async_add_notifier(a, (GFunc)multistore_completion_handler, async);
117         bluesky_store_async_submit(a);
118         bluesky_store_async_unref(a);
119         break;
120     }
121
122     default:
123         g_warning("Uknown operation type for multistore: %d\n", async->op);
124         bluesky_store_async_mark_complete(async);
125         break;
126     }
127 }
128
129 static char *multistore_lookup_last(gpointer store, const char *prefix)
130 {
131     BlueSkyStore *base = (BlueSkyStore *)store;
132     return bluesky_store_lookup_last(base, prefix);
133 }
134
135 static void multistore_cleanup(gpointer store, BlueSkyStoreAsync *async)
136 {
137 }
138
139 static BlueSkyStoreImplementation store_impl = {
140     .create = multistore_new,
141     .destroy = multistore_destroy,
142     .submit = multistore_submit,
143     .cleanup = multistore_cleanup,
144     .lookup_last = multistore_lookup_last,
145 };
146
147 void bluesky_store_init_multi(void)
148 {
149     bluesky_store_register(&store_impl, "multi");
150 }