#ifndef __CLOUD_H__ #define __CLOUD_H__ /* Copyright (c) 2009 PrimeBase Technologies GmbH, Germany * * PrimeBase Media Stream for MySQL * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Created by Barry Leslie on 3/20/09. * */ #include #include "CSMd5.h" /* NOTES: * * - TODO: If cl_deleteData() fails then the BLOB deletion must fail and be rescheduled to try again * later. * - TODO: Copying of BLOBs from one database to another needs to be handled. Look for copyBlob() and * resetBlobHead(). There are 3 cases to handle depending on if the databases involved use * cload storage. */ //=============================== class CSS3Protocol; class MSCloudInfo : public CSRefObject { private: static uint32_t gMaxInfoRef; static CSSyncSparseArray *gCloudInfo; friend class MSCloudTable; friend class CloudDB; private: uint32_t cloudRefId; CSString *bucket; CSS3Protocol *s3Prot; public: static void startUp() { new_(gCloudInfo, CSSyncSparseArray(5)); gMaxInfoRef = 0; } static void shutDown() { if (gCloudInfo) { gCloudInfo->clear(); gCloudInfo->release(); gCloudInfo = NULL; } } static MSCloudInfo *getCloudInfo(uint32_t cloudRefId) { MSCloudInfo *info; enter_(); lock_(gCloudInfo); info = (MSCloudInfo *) gCloudInfo->get(cloudRefId); if (!info) { char msg[80]; snprintf(msg, 80, "Cloud info with reference ID %"PRIu32" not found", cloudRefId); CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, msg); } info->retain(); unlock_(gCloudInfo); return_(info); } MSCloudInfo(uint32_t id, const char *server, const char *bucket, const char *publicKey, const char *privateKey ); ~MSCloudInfo(); uint32_t getCloudRefId() { return cloudRefId;} const char *getServer(); const char *getBucket(); const char *getPublicKey(); const char *getPrivateKey(); CSString *getSignature(const char *key, const char *content_type, uint32_t *s3AuthorizationTime); CSString *getDataURL(const char *key, int keep_alive); void send(CSInputStream *input, const char *key, off_t size); void receive(CSOutputStream *output, const char *key); void copy(MSCloudInfo *dst_cloud, const char *dst_key, const char *src_key); void cDelete(const char *key); CSVector *list(const char *key_prefix, uint32_t max = 0); }; typedef struct CloudKey { uint32_t creation_time; uint32_t ref_index; // Just a sequence counter in case 2 blobs have the same creation time. uint32_t cloud_ref; // A reference into the pbms.pbms_cloud table. } CloudKeyRec, *CloudKeyPtr; //=============================== class CloudObjectKey : public CSStringBuffer { uint32_t default_db_id; public: CloudObjectKey(uint32_t id): CSStringBuffer(), default_db_id(id){ } ~CloudObjectKey(){} static const uint32_t base_key_size = 64; // enough space for /// void setObjectKey(const char *object_key) { setLength(base_key_size + strlen(object_key) +1); snprintf(getBuffer(0), length(), "%"PRIu32"/0/%s",default_db_id, object_key); } void setObjectKey(CloudKeyPtr key = NULL, uint32_t backup_id = 0, uint32_t db_id = 0) { if (!db_id) db_id = default_db_id; setLength(base_key_size); if (key) snprintf(getBuffer(0), length(), "%"PRIu32"/%"PRIu32"/%"PRIu32".%"PRIu32".%"PRIu32"", db_id, backup_id, key->cloud_ref, key->creation_time, key->ref_index); else snprintf(getBuffer(0), length(), "%"PRIu32"/%"PRIu32"s/", db_id, backup_id); } static void parseObjectKey(const char *object_key, CloudKeyPtr key, uint32_t *backup_id = NULL, uint32_t *db_id = NULL) { uint32_t v1; if (!backup_id) backup_id = &v1; if (!db_id) db_id = &v1; sscanf(object_key, "%"PRIu32"/%"PRIu32"/%"PRIu32".%"PRIu32".%"PRIu32"", db_id, backup_id, &(key->cloud_ref), &(key->creation_time), &(key->ref_index)); } }; //=============================== class MSBackupInfo; class CloudDB: public CSRefObject { private: static uint32_t gKeyIndex; static CSMutex gCloudKeyLock; uint32_t dfltCloudRefId; uint32_t keep_alive; // The length of time a redirect URL will remain valid. In seconds. uint32_t blob_recovery_no; // This is the backup number from which the recovery should be done. uint32_t blob_db_id; bool isBackup; MSBackupInfo *backupInfo; MSCloudInfo *backupCloud; static const uint32_t base_key_size = 64; // enough space for /// public: CSStringBuffer *clObjectKey; CloudDB(uint32_t db_id); ~CloudDB(); void cl_setDefaultCloudRef(uint32_t dflt) { dfltCloudRefId = dflt;} uint32_t cl_getDefaultCloudRef() { return dfltCloudRefId;} MSCloudInfo *cl_getCloudInfo(uint32_t cloudRefId = 0) { return MSCloudInfo::getCloudInfo((cloudRefId)?cloudRefId:dfltCloudRefId); } void cl_getNewKey(CloudKeyPtr key) { enter_(); lock_(&gCloudKeyLock); key->creation_time = time(NULL); key->ref_index = gKeyIndex++; key->cloud_ref = dfltCloudRefId; unlock_(&gCloudKeyLock); exit_(); } bool cl_mustRecoverBlobs() { return (blob_recovery_no != 0);} void cl_setRecoveryNumber(const char *number) { blob_recovery_no = atol(number); } const char *cl_getRecoveryNumber() { static char number[20]; snprintf(number, 20, "%"PRIu32"", blob_recovery_no); return number; } CSString *cl_getObjectKey(CloudKeyPtr key) { CloudObjectKey *objectKey; enter_(); new_(objectKey, CloudObjectKey(blob_db_id)); push_(objectKey); objectKey->setObjectKey(key); CSString *str = CSString::newString(objectKey->getCString()); release_(objectKey); return_(str); } void cl_setKeepAlive(uint32_t keep_alive_arg) {keep_alive = keep_alive_arg;} void cl_createDB(); void cl_dropDB(); void cl_restoreDB(); uint32_t cl_getNextBackupNumber(uint32_t cloud_ref = 0); bool cl_dbExists(); // setting backup_blob_no to -1 ensures that if the database is dropped no BLOBs will be deleted. void cl_setCloudIsBackup(){ isBackup = true;} void cl_setBackupInfo(MSBackupInfo *info){ backupInfo = info;} MSBackupInfo *cl_getBackupInfo(); void cl_clearBackupInfo(); void cl_backupBLOB(CloudKeyPtr key); void cl_restoreBLOB(CloudKeyPtr key, uint32_t backup_db_id); void cl_putData( CloudKeyPtr key, CSInputStream *stream, off_t size); off_t cl_getData(CloudKeyPtr key, char *data, off_t size); CSString *cl_getDataURL(CloudKeyPtr key); void cl_deleteData(CloudKeyPtr key); CSString *cl_getSignature(CloudKeyPtr key, CSString *content_type, uint32_t *s3AuthorizationTime); }; #endif // __CLOUD_H__