1644.3.8
by Barry.Leslie at PrimeBase
Switched license fro GPL to BSD for source that can be built into other engines. |
1 |
/* Copyright (c) 2010 PrimeBase Technologies GmbH
|
2 |
* All rights reserved.
|
|
3 |
*
|
|
4 |
* Redistribution and use in source and binary forms, with or without
|
|
5 |
* modification, are permitted provided that the following conditions are met:
|
|
6 |
*
|
|
7 |
* * Redistributions of source code must retain the above copyright notice,
|
|
8 |
* this list of conditions and the following disclaimer.
|
|
9 |
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
10 |
* this list of conditions and the following disclaimer in the documentation
|
|
11 |
* and/or other materials provided with the distribution.
|
|
12 |
* * Neither the name of the "PrimeBase Technologies GmbH" nor the names of its
|
|
13 |
* contributors may be used to endorse or promote products derived from this
|
|
14 |
* software without specific prior written permission.
|
|
15 |
*
|
|
16 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
17 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
18 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
19 |
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
20 |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
21 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
22 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
23 |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
24 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
25 |
* POSSIBILITY OF SUCH DAMAGE.
|
|
26 |
*
|
|
27 |
* PrimeBase Media Stream for MySQL and Drizzle
|
|
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
28 |
*
|
29 |
* Original author: Paul McCullagh
|
|
30 |
* Continued development: Barry Leslie
|
|
31 |
* H&G2JCtL
|
|
32 |
*
|
|
33 |
* 2007-06-01
|
|
34 |
*
|
|
35 |
* This file contains the BLOB streaming interface engines that
|
|
36 |
* are streaming enabled.
|
|
37 |
*
|
|
38 |
*/
|
|
1548.2.24
by Barry.Leslie at PrimeBase
Reorganized code while fixing some minor problems. |
39 |
#ifndef __PBMS_H__
|
40 |
#define __PBMS_H__
|
|
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
41 |
|
42 |
#include <stdio.h> |
|
43 |
#include <sys/types.h> |
|
44 |
#include <unistd.h> |
|
45 |
#include <stdlib.h> |
|
46 |
#include <fcntl.h> |
|
47 |
#include <string.h> |
|
48 |
#include <dirent.h> |
|
49 |
#include <signal.h> |
|
50 |
#include <ctype.h> |
|
51 |
#include <errno.h> |
|
52 |
#include <inttypes.h> |
|
1548.2.11
by Barry.Leslie at PrimeBase
Removed libxml reqirement by using a home grown xml parser. |
53 |
#include <stdint.h> |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
54 |
|
55 |
#ifdef USE_PRAGMA_INTERFACE
|
|
56 |
#pragma interface /* gcc class implementation */ |
|
57 |
#endif
|
|
58 |
||
59 |
||
60 |
#define MS_SHARED_MEMORY_MAGIC 0x7E9A120C
|
|
1548.2.11
by Barry.Leslie at PrimeBase
Removed libxml reqirement by using a home grown xml parser. |
61 |
#define MS_ENGINE_VERSION 3
|
62 |
#define MS_CALLBACK_VERSION 6
|
|
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
63 |
#define MS_SHARED_MEMORY_VERSION 2
|
64 |
#define MS_ENGINE_LIST_SIZE 10
|
|
65 |
#define MS_TEMP_FILE_PREFIX "pbms_temp_"
|
|
66 |
||
67 |
#define MS_BLOB_HANDLE_SIZE 300
|
|
68 |
||
69 |
#define SH_MASK ((S_IRUSR | S_IWUSR) | (S_IRGRP | S_IWGRP) | (S_IROTH))
|
|
70 |
||
71 |
#define MS_OK 0
|
|
72 |
#define MS_ERR_ENGINE 1 /* Internal engine error. */ |
|
73 |
#define MS_ERR_UNKNOWN_TABLE 2 /* Returned if the engine cannot open the given table. */ |
|
74 |
#define MS_ERR_NOT_FOUND 3 /* The BLOB cannot be found. */ |
|
75 |
#define MS_ERR_TABLE_LOCKED 4 /* Table is currently locked. */ |
|
76 |
#define MS_ERR_INCORRECT_URL 5
|
|
77 |
#define MS_ERR_AUTH_FAILED 6
|
|
78 |
#define MS_ERR_NOT_IMPLEMENTED 7
|
|
79 |
#define MS_ERR_UNKNOWN_DB 8
|
|
80 |
#define MS_ERR_REMOVING_REPO 9
|
|
81 |
#define MS_ERR_DATABASE_DELETED 10
|
|
82 |
#define MS_ERR_DUPLICATE 11 /* Attempt to insert a duplicate key into a system table. */ |
|
83 |
#define MS_ERR_INVALID_RECORD 12
|
|
84 |
#define MS_ERR_RECOVERY_IN_PROGRESS 13
|
|
85 |
#define MS_ERR_DUPLICATE_DB 14
|
|
86 |
#define MS_ERR_DUPLICATE_DB_ID 15
|
|
87 |
#define MS_ERR_INVALID_OPERATION 16
|
|
88 |
#define MS_ERR_MISSING_CLOUD_REFFERENCE 17
|
|
89 |
#define MS_ERR_SYSTAB_VERSION 18
|
|
90 |
||
91 |
#define MS_LOCK_NONE 0
|
|
92 |
#define MS_LOCK_READONLY 1
|
|
93 |
#define MS_LOCK_READ_WRITE 2
|
|
94 |
||
95 |
#define PBMS_BLOB_URL_SIZE 120
|
|
96 |
||
97 |
#define PBMS_FIELD_COL_SIZE 128
|
|
98 |
#define PBMS_FIELD_COND_SIZE 300
|
|
99 |
||
100 |
#define MS_RESULT_MESSAGE_SIZE 300
|
|
101 |
#define MS_RESULT_STACK_SIZE 200
|
|
102 |
||
103 |
typedef struct PBMSResultRec { |
|
1548.2.27
by Barry.Leslie at PrimeBase
Cleanup for solaris build. |
104 |
uint8_t mr_had_blobs; /* A flag to indicate if the statement had any PBMS blobs. */ |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
105 |
int mr_code; /* Engine specific error code. */ |
106 |
char mr_message[MS_RESULT_MESSAGE_SIZE]; /* Error message, required if non-zero return code. */ |
|
107 |
char mr_stack[MS_RESULT_STACK_SIZE]; /* Trace information about where the error occurred. */ |
|
108 |
} PBMSResultRec, *PBMSResultPtr; |
|
109 |
||
110 |
||
111 |
||
112 |
typedef struct PBMSBlobID { |
|
1548.2.27
by Barry.Leslie at PrimeBase
Cleanup for solaris build. |
113 |
uint32_t bi_db_id; |
114 |
uint64_t bi_blob_size; |
|
115 |
uint64_t bi_blob_id; // or repo file offset if type = REPO |
|
116 |
uint64_t bi_blob_ref_id; |
|
117 |
uint32_t bi_tab_id; // or repo ID if type = REPO |
|
118 |
uint32_t bi_auth_code; |
|
119 |
uint32_t bi_blob_type; |
|
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
120 |
} PBMSBlobIDRec, *PBMSBlobIDPtr; |
121 |
||
1548.2.24
by Barry.Leslie at PrimeBase
Reorganized code while fixing some minor problems. |
122 |
|
123 |
typedef struct MSBlobURL { |
|
124 |
uint8_t bu_type; |
|
125 |
uint32_t bu_db_id; |
|
126 |
uint32_t bu_tab_id; // or repo ID if type = REPO |
|
127 |
uint64_t bu_blob_id; // or repo file offset if type = REPO |
|
128 |
uint32_t bu_auth_code; |
|
129 |
uint32_t bu_server_id; |
|
130 |
uint64_t bu_blob_size; |
|
131 |
uint64_t bu_blob_ref_id; // Unique identifier of the blob reference |
|
132 |
} MSBlobURLRec, *MSBlobURLPtr; |
|
133 |
||
134 |
||
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
135 |
typedef struct PBMSBlobURL { |
136 |
char bu_data[PBMS_BLOB_URL_SIZE]; |
|
137 |
} PBMSBlobURLRec, *PBMSBlobURLPtr; |
|
138 |
||
139 |
typedef struct PBMSEngineRec { |
|
140 |
int ms_version; /* MS_ENGINE_VERSION */ |
|
141 |
int ms_index; /* The index into the engine list. */ |
|
142 |
int ms_removing; /* TRUE (1) if the engine is being removed. */ |
|
143 |
int ms_internal; /* TRUE (1) if the engine is supported directly in the mysq/drizzle handler code . */ |
|
144 |
char ms_engine_name[32]; |
|
145 |
int ms_has_transactions; /* TRUE (1) if the engine supports transactions. */ |
|
146 |
} PBMSEngineRec, *PBMSEnginePtr; |
|
147 |
||
1548.2.24
by Barry.Leslie at PrimeBase
Reorganized code while fixing some minor problems. |
148 |
/* 2 10 1 10 20 10 10 20 20
|
149 |
* Format: "~*"<db_id><'~' || '_'><tab_id>"-"<blob_id>"-"<auth_code>"-"<server_id>"-"<blob_ref_id>"-"<blob_size>
|
|
150 |
*/
|
|
151 |
||
152 |
#ifndef PRIu64
|
|
153 |
#define URL_FMT "~*%u%c%u-%llu-%x-%u-%llu-%llu"
|
|
154 |
#else
|
|
155 |
#define URL_FMT "~*%"PRIu32"%c%"PRIu32"-%"PRIu64"-%x-%"PRIu32"-%"PRIu64"-%"PRIu64""
|
|
156 |
#endif
|
|
157 |
#define MS_URL_TYPE_BLOB '~'
|
|
158 |
#define MS_URL_TYPE_REPO '_'
|
|
159 |
class PBMSBlobURLTools |
|
160 |
{
|
|
161 |
public: |
|
162 |
static bool couldBeURL(const char *blob_url, size_t size, MSBlobURLPtr blob) |
|
163 |
{
|
|
164 |
if (blob_url && (size < PBMS_BLOB_URL_SIZE)) { |
|
1644.3.1
by Barry.Leslie at PrimeBase
Merged in changes from PBMS project. |
165 |
MSBlobURLRec ignored_blob; |
1548.2.24
by Barry.Leslie at PrimeBase
Reorganized code while fixing some minor problems. |
166 |
char buffer[PBMS_BLOB_URL_SIZE+1]; |
167 |
char junk[5]; |
|
168 |
int scanned; |
|
1644.3.1
by Barry.Leslie at PrimeBase
Merged in changes from PBMS project. |
169 |
|
170 |
if (!blob) |
|
171 |
blob = &ignored_blob; |
|
172 |
||
1548.2.24
by Barry.Leslie at PrimeBase
Reorganized code while fixing some minor problems. |
173 |
junk[0] = 0; |
174 |
if (blob_url[size]) { // There is no guarantee that the URL will be null terminated. |
|
175 |
memcpy(buffer, blob_url, size); |
|
176 |
buffer[size] = 0; |
|
177 |
blob_url = buffer; |
|
178 |
}
|
|
179 |
||
180 |
scanned = sscanf(blob_url, URL_FMT"%4s", |
|
181 |
&blob->bu_db_id, |
|
182 |
&blob->bu_type, |
|
183 |
&blob->bu_tab_id, |
|
184 |
&blob->bu_blob_id, |
|
185 |
&blob->bu_auth_code, |
|
186 |
&blob->bu_server_id, |
|
187 |
&blob->bu_blob_ref_id, |
|
188 |
&blob->bu_blob_size, |
|
189 |
junk); |
|
190 |
||
191 |
if ((scanned != 8) || (blob->bu_type != MS_URL_TYPE_BLOB && blob->bu_type != MS_URL_TYPE_REPO)) {// If junk is found at the end this will also result in an invalid URL. |
|
192 |
//printf("Bad URL \"%s\": scanned = %d, junk: %d, %d, %d, %d\n", blob_url, scanned, junk[0], junk[1], junk[2], junk[3]);
|
|
193 |
return false; |
|
194 |
}
|
|
195 |
||
196 |
return true; |
|
197 |
}
|
|
198 |
||
199 |
return false; |
|
200 |
}
|
|
201 |
||
202 |
static bool couldBeURL(const char *blob_url, MSBlobURLPtr blob) |
|
203 |
{
|
|
204 |
return couldBeURL(blob_url, strlen(blob_url), blob); |
|
205 |
}
|
|
206 |
||
207 |
static void buildBlobURL(MSBlobURLPtr blob, PBMSBlobURLPtr url) |
|
208 |
{
|
|
209 |
snprintf(url->bu_data, PBMS_BLOB_URL_SIZE, URL_FMT, blob->bu_db_id, |
|
210 |
blob->bu_type, |
|
211 |
blob->bu_tab_id, |
|
212 |
blob->bu_blob_id, |
|
213 |
blob->bu_auth_code, |
|
214 |
blob->bu_server_id, |
|
215 |
blob->bu_blob_ref_id, |
|
216 |
blob->bu_blob_size); |
|
217 |
}
|
|
218 |
};
|
|
219 |
||
220 |
#ifndef DRIZZLED
|
|
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
221 |
/*
|
222 |
* This function should never be called directly, it is called
|
|
223 |
* by deregisterEngine() below.
|
|
224 |
*/
|
|
225 |
typedef void (*ECRegisterdFunc)(PBMSEnginePtr engine); |
|
226 |
||
227 |
typedef void (*ECDeregisterdFunc)(PBMSEnginePtr engine); |
|
228 |
||
229 |
/*
|
|
230 |
* Call this function to store a BLOB in the repository the BLOB's
|
|
231 |
* URL will be returned. The returned URL buffer is expected to be atleast
|
|
232 |
* PBMS_BLOB_URL_SIZE long.
|
|
233 |
*
|
|
234 |
* The BLOB URL must still be retained or it will automaticly be deleted after a timeout expires.
|
|
235 |
*/
|
|
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
236 |
typedef int (*ECCreateBlobsFunc)(bool built_in, const char *db_name, const char *tab_name, char *blob, size_t blob_len, PBMSBlobURLPtr blob_url, PBMSResultPtr result); |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
237 |
|
238 |
/*
|
|
239 |
* Call this function for each BLOB to be retained. When a BLOB is used, the
|
|
240 |
* URL may be changed. The returned URL buffer is expected to be atleast
|
|
241 |
* PBMS_BLOB_URL_SIZE long.
|
|
242 |
*
|
|
243 |
* The returned URL must be inserted into the row in place of the given
|
|
244 |
* URL.
|
|
245 |
*/
|
|
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
246 |
typedef int (*ECRetainBlobsFunc)(bool built_in, const char *db_name, const char *tab_name, PBMSBlobURLPtr ret_blob_url, char *blob_url, unsigned short col_index, PBMSResultPtr result); |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
247 |
|
248 |
/*
|
|
249 |
* If a row containing a BLOB is deleted, then the BLOBs in the
|
|
250 |
* row must be released.
|
|
251 |
*
|
|
252 |
* Note: if a table is dropped, all the BLOBs referenced by the
|
|
253 |
* table are automatically released.
|
|
254 |
*/
|
|
255 |
typedef int (*ECReleaseBlobFunc)(bool built_in, const char *db_name, const char *tab_name, char *blob_url, PBMSResultPtr result); |
|
256 |
||
257 |
typedef int (*ECDropTable)(bool built_in, const char *db_name, const char *tab_name, PBMSResultPtr result); |
|
258 |
||
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
259 |
typedef int (*ECRenameTable)(bool built_in, const char *db_name, const char *from_table, const char *to_db, const char *to_table, PBMSResultPtr result); |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
260 |
|
261 |
typedef void (*ECCallCompleted)(bool built_in, bool ok); |
|
262 |
||
263 |
typedef struct PBMSCallbacksRec { |
|
264 |
int cb_version; /* MS_CALLBACK_VERSION */ |
|
265 |
ECRegisterdFunc cb_register; |
|
266 |
ECDeregisterdFunc cb_deregister; |
|
267 |
ECCreateBlobsFunc cb_create_blob; |
|
268 |
ECRetainBlobsFunc cb_retain_blob; |
|
269 |
ECReleaseBlobFunc cb_release_blob; |
|
270 |
ECDropTable cb_drop_table; |
|
271 |
ECRenameTable cb_rename_table; |
|
272 |
ECCallCompleted cb_completed; |
|
273 |
} PBMSCallbacksRec, *PBMSCallbacksPtr; |
|
274 |
||
275 |
typedef struct PBMSSharedMemoryRec { |
|
276 |
int sm_magic; /* MS_SHARED_MEMORY_MAGIC */ |
|
277 |
int sm_version; /* MS_SHARED_MEMORY_VERSION */ |
|
278 |
volatile int sm_shutdown_lock; /* "Cheap" lock for shutdown! */ |
|
279 |
PBMSCallbacksPtr sm_callbacks; |
|
280 |
int sm_reserved1[20]; |
|
281 |
void *sm_reserved2[20]; |
|
282 |
int sm_list_size; |
|
283 |
int sm_list_len; |
|
284 |
PBMSEnginePtr sm_engine_list[MS_ENGINE_LIST_SIZE]; |
|
285 |
} PBMSSharedMemoryRec, *PBMSSharedMemoryPtr; |
|
286 |
||
287 |
#ifdef PBMS_API
|
|
288 |
||
289 |
class PBMS_API |
|
290 |
{
|
|
291 |
private: |
|
292 |
const char *temp_prefix[3]; |
|
293 |
bool built_in; |
|
294 |
||
295 |
public: |
|
296 |
PBMS_API(): sharedMemory(NULL) { |
|
297 |
int i = 0; |
|
298 |
temp_prefix[i++] = MS_TEMP_FILE_PREFIX; |
|
299 |
temp_prefix[i++] = NULL; |
|
300 |
||
301 |
}
|
|
302 |
||
303 |
~PBMS_API() { } |
|
304 |
||
305 |
/*
|
|
306 |
* This method is called by the PBMS engine during startup.
|
|
307 |
*/
|
|
308 |
int PBMSStartup(PBMSCallbacksPtr callbacks, PBMSResultPtr result) { |
|
309 |
int err; |
|
310 |
||
311 |
deleteTempFiles(); |
|
312 |
err = getSharedMemory(true, result); |
|
313 |
if (!err) |
|
314 |
sharedMemory->sm_callbacks = callbacks; |
|
315 |
||
316 |
return err; |
|
317 |
}
|
|
318 |
||
319 |
/*
|
|
320 |
* This method is called by the PBMS engine during startup.
|
|
321 |
*/
|
|
322 |
void PBMSShutdown() { |
|
323 |
||
324 |
if (!sharedMemory) |
|
325 |
return; |
|
326 |
||
327 |
lock(); |
|
328 |
sharedMemory->sm_callbacks = NULL; |
|
329 |
||
330 |
bool empty = true; |
|
331 |
for (int i=0; i<sharedMemory->sm_list_len && empty; i++) { |
|
332 |
if (sharedMemory->sm_engine_list[i]) |
|
333 |
empty = false; |
|
334 |
}
|
|
335 |
||
336 |
unlock(); |
|
337 |
||
338 |
if (empty) |
|
339 |
removeSharedMemory(); |
|
340 |
}
|
|
341 |
||
342 |
/*
|
|
343 |
* Register the engine with the Stream Daemon.
|
|
344 |
*/
|
|
345 |
int registerEngine(PBMSEnginePtr the_engine, PBMSResultPtr result) { |
|
346 |
int err; |
|
347 |
||
348 |
deleteTempFiles(); |
|
349 |
||
350 |
// The first engine to register creates the shared memory.
|
|
351 |
if ((err = getSharedMemory(true, result))) |
|
352 |
return err; |
|
353 |
||
354 |
lock(); |
|
355 |
for (int i=0; i<sharedMemory->sm_list_size; i++) { |
|
356 |
if (!sharedMemory->sm_engine_list[i]) { |
|
357 |
PBMSEnginePtr engine; |
|
358 |
engine = (PBMSEnginePtr) malloc(sizeof(PBMSEngineRec)); |
|
359 |
if (!engine) { |
|
360 |
strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Out of memory."); |
|
361 |
err = MS_ERR_ENGINE; |
|
362 |
goto done; |
|
363 |
}
|
|
364 |
memcpy(engine, the_engine, sizeof(PBMSEngineRec)); |
|
365 |
||
366 |
sharedMemory->sm_engine_list[i] = engine; |
|
367 |
engine->ms_index = i; |
|
368 |
if (i >= sharedMemory->sm_list_len) |
|
369 |
sharedMemory->sm_list_len = i+1; |
|
370 |
if (sharedMemory->sm_callbacks) |
|
371 |
sharedMemory->sm_callbacks->cb_register(engine); |
|
372 |
||
373 |
built_in = (engine->ms_internal == 1); |
|
374 |
err = MS_OK; |
|
375 |
goto done; |
|
376 |
}
|
|
377 |
}
|
|
378 |
||
379 |
result->mr_code = 15010; |
|
380 |
strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Too many BLOB streaming engines already registered"); |
|
381 |
*result->mr_stack = 0; |
|
382 |
||
383 |
err = MS_ERR_ENGINE; |
|
384 |
||
385 |
done: |
|
386 |
unlock(); |
|
387 |
return err; |
|
388 |
}
|
|
389 |
||
390 |
void lock() { |
|
391 |
while (sharedMemory->sm_shutdown_lock) |
|
392 |
usleep(10000); |
|
393 |
sharedMemory->sm_shutdown_lock++; |
|
394 |
while (sharedMemory->sm_shutdown_lock != 1) { |
|
395 |
usleep(random() % 10000); |
|
396 |
sharedMemory->sm_shutdown_lock--; |
|
397 |
usleep(10000); |
|
398 |
sharedMemory->sm_shutdown_lock++; |
|
399 |
}
|
|
400 |
}
|
|
401 |
||
402 |
void unlock() { |
|
403 |
sharedMemory->sm_shutdown_lock--; |
|
404 |
}
|
|
405 |
||
406 |
void deregisterEngine(const char *engine_name) { |
|
407 |
PBMSResultRec result; |
|
408 |
int err; |
|
409 |
||
410 |
if ((err = getSharedMemory(false, &result))) |
|
411 |
return; |
|
412 |
||
413 |
lock(); |
|
414 |
||
415 |
bool empty = true; |
|
416 |
for (int i=0; i<sharedMemory->sm_list_len; i++) { |
|
417 |
PBMSEnginePtr engine = sharedMemory->sm_engine_list[i]; |
|
418 |
if (engine) { |
|
419 |
if (strcmp(engine->ms_engine_name, engine_name) == 0) { |
|
420 |
if (sharedMemory->sm_callbacks) |
|
421 |
sharedMemory->sm_callbacks->cb_deregister(engine); |
|
422 |
free(engine); |
|
423 |
sharedMemory->sm_engine_list[i] = NULL; |
|
424 |
}
|
|
425 |
else
|
|
426 |
empty = false; |
|
427 |
}
|
|
428 |
}
|
|
429 |
||
430 |
unlock(); |
|
431 |
||
432 |
if (empty) |
|
433 |
removeSharedMemory(); |
|
434 |
}
|
|
435 |
||
436 |
void removeSharedMemory() |
|
437 |
{
|
|
438 |
const char **prefix = temp_prefix; |
|
439 |
char temp_file[100]; |
|
440 |
||
441 |
// Do not remove the sharfed memory until after
|
|
442 |
// the PBMS engine has shutdown.
|
|
443 |
if (sharedMemory->sm_callbacks) |
|
444 |
return; |
|
445 |
||
446 |
sharedMemory->sm_magic = 0; |
|
447 |
free(sharedMemory); |
|
448 |
sharedMemory = NULL; |
|
449 |
||
450 |
while (*prefix) { |
|
451 |
getTempFileName(temp_file, 100, *prefix, getpid()); |
|
452 |
unlink(temp_file); |
|
453 |
prefix++; |
|
454 |
}
|
|
455 |
}
|
|
456 |
||
457 |
bool isPBMSLoaded() |
|
458 |
{
|
|
459 |
PBMSResultRec result; |
|
460 |
if (getSharedMemory(false, &result)) |
|
461 |
return false; |
|
462 |
||
463 |
return (sharedMemory->sm_callbacks != NULL); |
|
464 |
}
|
|
465 |
||
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
466 |
int retainBlob(const char *db_name, const char *tab_name, PBMSBlobURLPtr ret_blob_url, char *blob_url, size_t blob_size, unsigned short col_index, PBMSResultPtr result) |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
467 |
{
|
468 |
int err; |
|
469 |
char safe_url[PBMS_BLOB_URL_SIZE+1]; |
|
470 |
||
471 |
||
472 |
if ((err = getSharedMemory(false, result))) |
|
473 |
return err; |
|
474 |
||
1644.3.1
by Barry.Leslie at PrimeBase
Merged in changes from PBMS project. |
475 |
if (!PBMSBlobURLTools::couldBeURL(blob_url, blob_size, NULL)) { |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
476 |
|
477 |
if (!sharedMemory->sm_callbacks) { |
|
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
478 |
ret_blob_url->bu_data[0] = 0; |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
479 |
return MS_OK; |
480 |
}
|
|
1548.2.2
by Barry.Leslie at PrimeBase
A lot of minor changes to clean up the code and to get it to build with Drizzle. |
481 |
err = sharedMemory->sm_callbacks->cb_create_blob(built_in, db_name, tab_name, blob_url, blob_size, ret_blob_url, result); |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
482 |
if (err) |
483 |
return err; |
|
484 |
||
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
485 |
blob_url = ret_blob_url->bu_data; |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
486 |
} else { |
487 |
// Make sure the url is a C string:
|
|
488 |
if (blob_url[blob_size]) { |
|
489 |
memcpy(safe_url, blob_url, blob_size); |
|
490 |
safe_url[blob_size] = 0; |
|
491 |
blob_url = safe_url; |
|
492 |
}
|
|
493 |
}
|
|
494 |
||
495 |
||
496 |
if (!sharedMemory->sm_callbacks) { |
|
497 |
result->mr_code = MS_ERR_INCORRECT_URL; |
|
498 |
strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "BLOB streaming daemon (PBMS) not installed"); |
|
499 |
*result->mr_stack = 0; |
|
500 |
return MS_ERR_INCORRECT_URL; |
|
501 |
}
|
|
502 |
||
503 |
return sharedMemory->sm_callbacks->cb_retain_blob(built_in, db_name, tab_name, ret_blob_url, blob_url, col_index, result); |
|
504 |
}
|
|
505 |
||
506 |
int releaseBlob(const char *db_name, const char *tab_name, char *blob_url, size_t blob_size, PBMSResultPtr result) |
|
507 |
{
|
|
508 |
int err; |
|
509 |
char safe_url[PBMS_BLOB_URL_SIZE+1]; |
|
510 |
||
511 |
if ((err = getSharedMemory(false, result))) |
|
512 |
return err; |
|
513 |
||
514 |
if (!sharedMemory->sm_callbacks) |
|
515 |
return MS_OK; |
|
516 |
||
1644.3.1
by Barry.Leslie at PrimeBase
Merged in changes from PBMS project. |
517 |
if (!PBMSBlobURLTools::couldBeURL(blob_url, blob_size, NULL)) |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
518 |
return MS_OK; |
519 |
||
520 |
if (blob_url[blob_size]) { |
|
521 |
memcpy(safe_url, blob_url, blob_size); |
|
522 |
safe_url[blob_size] = 0; |
|
523 |
blob_url = safe_url; |
|
524 |
}
|
|
525 |
||
526 |
return sharedMemory->sm_callbacks->cb_release_blob(built_in, db_name, tab_name, blob_url, result); |
|
527 |
}
|
|
528 |
||
529 |
int dropTable(const char *db_name, const char *tab_name, PBMSResultPtr result) |
|
530 |
{
|
|
531 |
int err; |
|
532 |
||
533 |
if ((err = getSharedMemory(false, result))) |
|
534 |
return err; |
|
535 |
||
536 |
if (!sharedMemory->sm_callbacks) |
|
537 |
return MS_OK; |
|
538 |
||
539 |
return sharedMemory->sm_callbacks->cb_drop_table(built_in, db_name, tab_name, result); |
|
540 |
}
|
|
541 |
||
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
542 |
int renameTable(const char *db_name, const char *from_table, const char *to_db, const char *to_table, PBMSResultPtr result) |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
543 |
{
|
544 |
int err; |
|
545 |
||
546 |
if ((err = getSharedMemory(false, result))) |
|
547 |
return err; |
|
548 |
||
549 |
if (!sharedMemory->sm_callbacks) |
|
550 |
return MS_OK; |
|
551 |
||
1548.2.3
by Barry.Leslie at PrimeBase
Added drizzle event observer class to PBMS as well as a lot of mostly minor changes for drizzle compatability. |
552 |
return sharedMemory->sm_callbacks->cb_rename_table(built_in, db_name, from_table, to_db, to_table, result); |
1548.2.1
by Barry.Leslie at PrimeBase
Added the PBMS daemon plugin. |
553 |
}
|
554 |
||
555 |
void completed(int ok) |
|
556 |
{
|
|
557 |
PBMSResultRec result; |
|
558 |
||
559 |
if (getSharedMemory(false, &result)) |
|
560 |
return; |
|
561 |
||
562 |
if (!sharedMemory->sm_callbacks) |
|
563 |
return; |
|
564 |
||
565 |
sharedMemory->sm_callbacks->cb_completed(built_in, ok); |
|
566 |
}
|
|
567 |
||
568 |
volatile PBMSSharedMemoryPtr sharedMemory; |
|
569 |
||
570 |
private: |
|
571 |
int getSharedMemory(bool create, PBMSResultPtr result) |
|
572 |
{
|
|
573 |
int tmp_f; |
|
574 |
int r; |
|
575 |
char temp_file[100]; |
|
576 |
const char **prefix = temp_prefix; |
|
577 |
||
578 |
if (sharedMemory) |
|
579 |
return MS_OK; |
|
580 |
||
581 |
while (*prefix) { |
|
582 |
getTempFileName(temp_file, 100, *prefix, getpid()); |
|
583 |
tmp_f = open(temp_file, O_RDWR | (create ? O_CREAT : 0), SH_MASK); |
|
584 |
if (tmp_f == -1) |
|
585 |
return setOSResult(errno, "open", temp_file, result); |
|
586 |
||
587 |
r = lseek(tmp_f, 0, SEEK_SET); |
|
588 |
if (r == -1) { |
|
589 |
close(tmp_f); |
|
590 |
return setOSResult(errno, "lseek", temp_file, result); |
|
591 |
}
|
|
592 |
ssize_t tfer; |
|
593 |
char buffer[100]; |
|
594 |
||
595 |
tfer = read(tmp_f, buffer, 100); |
|
596 |
if (tfer == -1) { |
|
597 |
close(tmp_f); |
|
598 |
return setOSResult(errno, "read", temp_file, result); |
|
599 |
}
|
|
600 |
||
601 |
buffer[tfer] = 0; |
|
602 |
sscanf(buffer, "%p", (void**) &sharedMemory); |
|
603 |
if (!sharedMemory || sharedMemory->sm_magic != MS_SHARED_MEMORY_MAGIC) { |
|
604 |
if (!create) |
|
605 |
return MS_OK; |
|
606 |
||
607 |
sharedMemory = (PBMSSharedMemoryPtr) calloc(1, sizeof(PBMSSharedMemoryRec)); |
|
608 |
sharedMemory->sm_magic = MS_SHARED_MEMORY_MAGIC; |
|
609 |
sharedMemory->sm_version = MS_SHARED_MEMORY_VERSION; |
|
610 |
sharedMemory->sm_list_size = MS_ENGINE_LIST_SIZE; |
|
611 |
||
612 |
r = lseek(tmp_f, 0, SEEK_SET); |
|
613 |
if (r == -1) { |
|
614 |
close(tmp_f); |
|
615 |
return setOSResult(errno, "fseek", temp_file, result); |
|
616 |
}
|
|
617 |
||
618 |
snprintf(buffer, 100, "%p", (void*) sharedMemory); |
|
619 |
tfer = write(tmp_f, buffer, strlen(buffer)); |
|
620 |
if (tfer != (ssize_t) strlen(buffer)) { |
|
621 |
close(tmp_f); |
|
622 |
return setOSResult(errno, "write", temp_file, result); |
|
623 |
}
|
|
624 |
r = fsync(tmp_f); |
|
625 |
if (r == -1) { |
|
626 |
close(tmp_f); |
|
627 |
return setOSResult(errno, "fsync", temp_file, result); |
|
628 |
}
|
|
629 |
}
|
|
630 |
else if (sharedMemory->sm_version != MS_SHARED_MEMORY_VERSION) { |
|
631 |
close(tmp_f); |
|
632 |
result->mr_code = -1000; |
|
633 |
*result->mr_stack = 0; |
|
634 |
strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Shared memory version: "); |
|
635 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, sharedMemory->sm_version); |
|
636 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ", does not match engine shared memory version: "); |
|
637 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, MS_SHARED_MEMORY_VERSION); |
|
638 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, "."); |
|
639 |
return MS_ERR_ENGINE; |
|
640 |
}
|
|
641 |
close(tmp_f); |
|
642 |
||
643 |
// For backward compatability we need to create the old versions but we only need to read the current version.
|
|
644 |
if (create) |
|
645 |
prefix++; |
|
646 |
else
|
|
647 |
break; |
|
648 |
}
|
|
649 |
return MS_OK; |
|
650 |
}
|
|
651 |
||
652 |
void strcpy(size_t size, char *to, const char *from) |
|
653 |
{
|
|
654 |
if (size > 0) { |
|
655 |
size--; |
|
656 |
while (*from && size--) |
|
657 |
*to++ = *from++; |
|
658 |
*to = 0; |
|
659 |
}
|
|
660 |
}
|
|
661 |
||
662 |
void strcat(size_t size, char *to, const char *from) |
|
663 |
{
|
|
664 |
while (*to && size--) to++; |
|
665 |
strcpy(size, to, from); |
|
666 |
}
|
|
667 |
||
668 |
void strcat(size_t size, char *to, int val) |
|
669 |
{
|
|
670 |
char buffer[20]; |
|
671 |
||
672 |
snprintf(buffer, 20, "%d", val); |
|
673 |
strcat(size, to, buffer); |
|
674 |
}
|
|
675 |
||
676 |
int setOSResult(int err, const char *func, char *file, PBMSResultPtr result) { |
|
677 |
char *msg; |
|
678 |
||
679 |
result->mr_code = err; |
|
680 |
*result->mr_stack = 0; |
|
681 |
strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, "System call "); |
|
682 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, func); |
|
683 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, "() failed on "); |
|
684 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, file); |
|
685 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ": "); |
|
686 |
||
687 |
#ifdef XT_WIN
|
|
688 |
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, iMessage + strlen(iMessage), MS_RESULT_MESSAGE_SIZE - strlen(iMessage), NULL)) { |
|
689 |
char *ptr; |
|
690 |
||
691 |
ptr = &iMessage[strlen(iMessage)]; |
|
692 |
while (ptr-1 > err_msg) { |
|
693 |
if (*(ptr-1) != '\n' && *(ptr-1) != '\r' && *(ptr-1) != '.') |
|
694 |
break; |
|
695 |
ptr--; |
|
696 |
}
|
|
697 |
*ptr = 0; |
|
698 |
||
699 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, " ("); |
|
700 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, err); |
|
701 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ")"); |
|
702 |
return MS_ERR_ENGINE; |
|
703 |
}
|
|
704 |
#endif
|
|
705 |
||
706 |
msg = strerror(err); |
|
707 |
if (msg) { |
|
708 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, msg); |
|
709 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, " ("); |
|
710 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, err); |
|
711 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, ")"); |
|
712 |
}
|
|
713 |
else { |
|
714 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, "Unknown OS error code "); |
|
715 |
strcat(MS_RESULT_MESSAGE_SIZE, result->mr_message, err); |
|
716 |
}
|
|
717 |
||
718 |
return MS_ERR_ENGINE; |
|
719 |
}
|
|
720 |
||
721 |
void getTempFileName(char *temp_file, int buffer_size, const char * prefix, int pid) |
|
722 |
{
|
|
723 |
snprintf(temp_file, buffer_size, "/tmp/%s%d", prefix, pid); |
|
724 |
}
|
|
725 |
||
726 |
bool startsWith(const char *cstr, const char *w_cstr) |
|
727 |
{
|
|
728 |
while (*cstr && *w_cstr) { |
|
729 |
if (*cstr != *w_cstr) |
|
730 |
return false; |
|
731 |
cstr++; |
|
732 |
w_cstr++; |
|
733 |
}
|
|
734 |
return *cstr || !*w_cstr; |
|
735 |
}
|
|
736 |
||
737 |
void deleteTempFiles() |
|
738 |
{
|
|
739 |
struct dirent entry; |
|
740 |
struct dirent *result; |
|
741 |
DIR *odir; |
|
742 |
int err; |
|
743 |
char temp_file[100]; |
|
744 |
||
745 |
if (!(odir = opendir("/tmp/"))) |
|
746 |
return; |
|
747 |
err = readdir_r(odir, &entry, &result); |
|
748 |
while (!err && result) { |
|
749 |
const char **prefix = temp_prefix; |
|
750 |
||
751 |
while (*prefix) { |
|
752 |
if (startsWith(entry.d_name, *prefix)) { |
|
753 |
int pid = atoi(entry.d_name + strlen(*prefix)); |
|
754 |
||
755 |
/* If the process does not exist: */
|
|
756 |
if (kill(pid, 0) == -1 && errno == ESRCH) { |
|
757 |
getTempFileName(temp_file, 100, *prefix, pid); |
|
758 |
unlink(temp_file); |
|
759 |
}
|
|
760 |
}
|
|
761 |
prefix++; |
|
762 |
}
|
|
763 |
||
764 |
err = readdir_r(odir, &entry, &result); |
|
765 |
}
|
|
766 |
closedir(odir); |
|
767 |
}
|
|
768 |
};
|
|
769 |
#endif // PBMS_API |
|
770 |
||
771 |
/*
|
|
772 |
* The following is a low level API for accessing blobs directly.
|
|
773 |
*/
|
|
774 |
||
775 |
||
776 |
/*
|
|
777 |
* Any threads using the direct blob access API must first register them selves with the
|
|
778 |
* blob streaming engine before using the blob access functions. This is done by calling
|
|
779 |
* PBMSInitBlobStreamingThread(). Call PBMSDeinitBlobStreamingThread() after the thread is
|
|
780 |
* done using the direct blob access API
|
|
781 |
*/
|
|
782 |
||
783 |
/*
|
|
784 |
* PBMSInitBlobStreamingThread(): Returns a pointer to a blob streaming thread.
|
|
785 |
*/
|
|
786 |
extern void *PBMSInitBlobStreamingThread(char *thread_name, PBMSResultPtr result); |
|
787 |
extern void PBMSDeinitBlobStreamingThread(void *v_bs_thread); |
|
788 |
||
789 |
/*
|
|
790 |
* PBMSGetError():Gets the last error reported by a blob streaming thread.
|
|
791 |
*/
|
|
792 |
extern void PBMSGetError(void *v_bs_thread, PBMSResultPtr result); |
|
793 |
||
794 |
/*
|
|
795 |
* PBMSCreateBlob():Creates a new blob in the database of the given size.
|
|
796 |
*/
|
|
797 |
extern bool PBMSCreateBlob(PBMSBlobIDPtr blob_id, char *database_name, u_int64_t size); |
|
798 |
||
799 |
/*
|
|
800 |
* PBMSWriteBlob():Write the data to the blob in one or more chunks. The total size of all the chuncks of
|
|
801 |
* data written to the blob must match the size specified when the blob was created.
|
|
802 |
*/
|
|
803 |
extern bool PBMSWriteBlob(PBMSBlobIDPtr blob_id, char *data, size_t size, size_t offset); |
|
804 |
||
805 |
/*
|
|
806 |
* PBMSReadBlob():Read the blob data out of the blob in one or more chunks.
|
|
807 |
*/
|
|
808 |
extern bool PBMSReadBlob(PBMSBlobIDPtr blob_id, char *buffer, size_t *size, size_t offset); |
|
809 |
||
810 |
/*
|
|
811 |
* PBMSIDToURL():Convert a blob id to a blob URL. The 'url' buffer must be atleast PBMS_BLOB_URL_SIZE bytes in size.
|
|
812 |
*/
|
|
813 |
extern bool PBMSIDToURL(PBMSBlobIDPtr blob_id, char *url); |
|
814 |
||
815 |
/*
|
|
816 |
* PBMSIDToURL():Convert a blob URL to a blob ID.
|
|
817 |
*/
|
|
818 |
extern bool PBMSURLToID(char *url, PBMSBlobIDPtr blob_id); |
|
1548.2.24
by Barry.Leslie at PrimeBase
Reorganized code while fixing some minor problems. |
819 |
#endif //DRIZZLED |
820 |
||
821 |
||
822 |
#endif //__PBMS_H__ |