Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial bucket API

Change-Id: I539edefb5d824815cda4eb6838cc6046eaeaeb43
Reviewed-on: http://review.couchbase.org/22014
Reviewed-by: Mordechai Nunberg <mnunberg@haskalah.org>
Tested-by: Mordechai Nunberg <mnunberg@haskalah.org>
  • Loading branch information...
commit ac4d9a82fc1f4970313fb0a81ccd1c4ff9b41adb 1 parent a133a06
@trondn trondn authored mnunberg committed
View
15 config.m4
@@ -170,5 +170,18 @@ if test "$PHP_COUCHBASE" != "no"; then
dnl PHP_ADD_LIBRARY(stdc++, 1, COUCHBASE_SHARED_LIBADD)
dnl PHP_ADD_LIBRARY(event, 1, COUCHBASE_SHARED_LIBADD)
PHP_SUBST(COUCHBASE_SHARED_LIBADD)
- PHP_NEW_EXTENSION(couchbase, compress.c couchbase.c views.c observe.c ht.c resmgr.c misc.c fastlz/fastlz.c timeout.c, $ext_shared)
+ PHP_NEW_EXTENSION([couchbase],
+ [compress.c \
+ couchbase.c \
+ fastlz/fastlz.c \
+ ht.c \
+ management/buckets.c \
+ management/instance.c \
+ management/management.c \
+ misc.c \
+ observe.c \
+ resmgr.c \
+ timeout.c \
+ views.c ],
+ [$ext_shared])
fi
View
12 config.w32
@@ -7,7 +7,15 @@ if (PHP_COUCHBASE != "no") {
if (CHECK_LIB("libcouchbase.lib", "couchbase", PHP_COUCHBASE) &&
CHECK_HEADER_ADD_INCLUDE("couchbase.h", "CFLAGS_COUCHBASE", PHP_COUCHBASE+ ";" + PHP_PHP_BUILD + "\\include\\libcouchbase")) {
EXTENSION("couchbase", "couchbase.c", PHP_COUCHBASE_SHARED, "");
- ADD_SOURCES(configure_module_dirname, "views.c observe.c ht.c resmgr.c misc.c gettimeofday_win32.c compress.c timeout.c", "couchbase");
- ADD_SOURCES(configure_module_dirname + "\\fastlz", "fastlz.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "compress.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "gettimeofday_win32.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "ht.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "misc.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "observe.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "resmgr.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "timeout.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname, "views.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname + "\\fastlz", "fastlz.c", "couchbase");
+ ADD_SOURCES(configure_module_dirname + "\\management", "buckets.c instance.c management.c", "couchbase");
}
}
View
2  couchbase.c
@@ -4170,6 +4170,8 @@ PHP_MINIT_FUNCTION(couchbase)
zend_declare_property_null(couchbase_ce, ZEND_STRL(COUCHBASE_PROPERTY_HANDLE), ZEND_ACC_PRIVATE TSRMLS_CC);
+ init_couchbase_cluster(module_number TSRMLS_CC);
+
return SUCCESS;
}
/* }}} */
View
16 example/buckets.php
@@ -0,0 +1,16 @@
+<?php
+
+$cb = new CouchbaseClusterManager("localhost", "Administrator", "password");
+
+$cb->createBucket("mybucket", array("type" => "couchbase",
+ "quota" => 256,
+ "replicas" => 1,
+ "enable flush" => 1,
+ "parallel compaction" => true,
+ "auth" => "none",
+ "port" => 11212));
+
+//$cb->modifyBucket("mybucket", array("auth" => "sasl",
+// "password" => "secret",
+// "port" => 11212));
+?>
View
3  internal.h
@@ -60,8 +60,11 @@
#endif
#include "Zend/zend_API.h"
+#include <zend_exceptions.h>
#include "timeout.h"
+#include "management/cluster.h"
+#include "management/exceptions.h"
#endif
View
664 management/buckets.c
@@ -0,0 +1,664 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/**
+ * Usage:
+ *
+ * $cb = new CouchbaseClusterManager("localhost:8091",
+ * "Administrator",
+ * "asdasd");
+ * $cb->createBucket("mybucket", array("type" => "couchbase",
+ * "quota" => 400,
+ * "replicas" => 1,
+ * "enable flush" => 1,
+ * "parallel compaction" => true,
+ * "auth" => "none",
+ * "port" => 11212));
+ *
+ * $cb->modifyBucket("mybucket", array("auth" => "sasl",
+ * "password" => "secret",
+ * "port" => 11212));
+ * $cb->deleteBucket("mybucket");
+ */
+
+#include "internal.h"
+#include "instance.h"
+#include "buckets.h"
+
+struct string {
+ char *buffer;
+ int len;
+};
+
+struct field {
+ struct string value;
+ int present;
+ int allocated;
+};
+
+struct bucket_meta_info {
+ struct field name;
+ struct field auth_type;
+ struct field bucket_type;
+ struct field flush_enabled;
+ struct field parallel_compaction;
+ struct field proxy_port;
+ struct field ram_quota;
+ struct field replica_index;
+ struct field replica_number;
+ struct field sasl_password;
+};
+
+static void init_bucket_meta(struct bucket_meta_info *meta)
+{
+ memset(meta, 0, sizeof(*meta));
+}
+
+static void release_bucket_meta(struct bucket_meta_info *meta)
+{
+ if (meta->name.allocated) {
+ free(meta->name.value.buffer);
+ }
+ if (meta->auth_type.allocated) {
+ free(meta->auth_type.value.buffer);
+ }
+ if (meta->bucket_type.allocated) {
+ free(meta->bucket_type.value.buffer);
+ }
+ if (meta->flush_enabled.allocated) {
+ free(meta->flush_enabled.value.buffer);
+ }
+ if (meta->parallel_compaction.allocated) {
+ free(meta->parallel_compaction.value.buffer);
+ }
+ if (meta->proxy_port.allocated) {
+ free(meta->proxy_port.value.buffer);
+ }
+ if (meta->ram_quota.allocated) {
+ free(meta->ram_quota.value.buffer);
+ }
+ if (meta->replica_index.allocated) {
+ free(meta->replica_index.value.buffer);
+ }
+ if (meta->replica_number.allocated) {
+ free(meta->replica_number.value.buffer);
+ }
+ if (meta->sasl_password.allocated) {
+ free(meta->sasl_password.value.buffer);
+ }
+}
+
+static int append(char *buffer, int offset,
+ const char *key,
+ const struct field *field)
+{
+ if (field->present && field->value.len > 0) {
+ int ii;
+ int r = strlen(key);
+ if (offset != 0) {
+ buffer[offset++] = '&';
+ }
+ memcpy(buffer + offset, key, r);
+ offset += r;
+ buffer[offset++] = '=';
+
+ for (ii = 0; ii < field->value.len; ++ii) {
+ if (isalpha(field->value.buffer[ii]) || isdigit(field->value.buffer[ii])) {
+ buffer[offset++] = field->value.buffer[ii];
+ } else {
+ sprintf(buffer + offset, "%%%02X", field->value.buffer[ii]);
+ offset += 3;
+ }
+ }
+ }
+
+ return offset;
+}
+
+static int meta_to_url(char *buffer, const struct bucket_meta_info *meta)
+{
+ int offset = 0;
+ offset = append(buffer, offset, "name", &meta->name);
+ offset = append(buffer, offset, "authType", &meta->auth_type);
+ offset = append(buffer, offset, "bucketType", &meta->bucket_type);
+ offset = append(buffer, offset, "flushEnabled", &meta->flush_enabled);
+ offset = append(buffer, offset, "parallelDBAndViewCompaction",
+ &meta->parallel_compaction);
+ offset = append(buffer, offset, "proxyPort", &meta->proxy_port);
+ offset = append(buffer, offset, "ramQuotaMB", &meta->ram_quota);
+ offset = append(buffer, offset, "replicaIndex", &meta->replica_index);
+ offset = append(buffer, offset, "replicaNumber", &meta->replica_number);
+ offset = append(buffer, offset, "saslPassword", &meta->sasl_password);
+
+ return offset;
+}
+
+static void update_field(struct field *f, const struct string *v)
+{
+ free(f->value.buffer);
+ f->present = 1;
+ f->allocated = 1;
+ f->value.buffer = malloc(v->len + 1);
+ memcpy(f->value.buffer, v->buffer, v->len);
+ f->value.len = v->len;
+ f->value.buffer[v->len] = '\0';
+}
+
+static int set_value(const struct string *key,
+ const struct string *value,
+ struct bucket_meta_info *meta
+ TSRMLS_DC)
+{
+ char k[64];
+ char *c;
+ if (key->len > (sizeof(k) - 1)) {
+ zend_throw_exception(ccm_illegal_key_exception,
+ "Invalid key specified", 0 TSRMLS_CC);
+ return -1;
+ }
+
+ memcpy(k, key->buffer, key->len);
+ k[key->len] = '\0';
+
+ /**
+ * Allow 'friendlier' names (spaces are not always the most natural)
+ */
+ for (c = k; *c; c++) {
+ if (*c == '_') {
+ *c = ' ';
+ }
+ }
+
+ if (strcmp(k, "name") == 0) {
+ update_field(&meta->name, value);
+ } else if (strcmp(k, "type") == 0) {
+ update_field(&meta->bucket_type, value);
+ } else if (strcmp(k, "auth") == 0) {
+ update_field(&meta->auth_type, value);
+ } else if (strcmp(k, "enable flush") == 0) {
+ update_field(&meta->flush_enabled, value);
+ } else if (strcmp(k, "parallel compaction") == 0) {
+ update_field(&meta->parallel_compaction, value);
+ } else if (strcmp(k, "port") == 0) {
+ update_field(&meta->proxy_port, value);
+ } else if (strcmp(k, "quota") == 0) {
+ update_field(&meta->ram_quota, value);
+ } else if (strcmp(k, "index replicas") == 0) {
+ update_field(&meta->replica_index, value);
+ } else if (strcmp(k, "replicas") == 0) {
+ update_field(&meta->replica_number, value);
+ } else if (strcmp(k, "password") == 0) {
+ update_field(&meta->sasl_password, value);
+ } else {
+ char message[80];
+ sprintf(message, "Unknown key: %s", k);
+ zend_throw_exception(ccm_illegal_key_exception, message, 0 TSRMLS_CC);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int extract_bucket_options(zval *options,
+ struct bucket_meta_info *meta TSRMLS_DC)
+{
+ int rval = 0;
+ for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(options));
+ zend_hash_has_more_elements(Z_ARRVAL_P(options)) == SUCCESS &&
+ rval == 0;
+ zend_hash_move_forward(Z_ARRVAL_P(options))) {
+
+ struct string key;
+ struct string value;
+ ulong idx;
+ int type;
+ zval **ppzval = NULL;
+ zval tmpcopy;
+
+ type = zend_hash_get_current_key_ex(Z_ARRVAL_P(options),
+ &key.buffer, &key.len,
+ &idx, 0, NULL);
+
+ if (type != HASH_KEY_IS_STRING || key.len == 0) {
+ char message[80];
+ sprintf(message, "Got non- (or empty) string value "
+ "for bucket parameters (%d)",
+ type);
+ zend_throw_exception(ccm_exception, message, 0 TSRMLS_CC);
+ return -1;
+ }
+
+ if (zend_hash_get_current_data(Z_ARRVAL_P(options),
+ (void **)&ppzval) == FAILURE) {
+ char message[80];
+ sprintf(message, "Couldn't get value for %*s", key.len,
+ key.buffer);
+ zend_throw_exception(ccm_exception, message, 0 TSRMLS_CC);
+ return -1;
+ }
+
+ tmpcopy = **ppzval;
+ zval_copy_ctor(&tmpcopy);
+ convert_to_string(&tmpcopy);
+ value.buffer = Z_STRVAL(tmpcopy);
+ value.len = Z_STRLEN(tmpcopy);
+ rval = set_value(&key, &value, meta TSRMLS_CC);
+ zval_dtor(&tmpcopy);
+ }
+
+ return rval;
+}
+
+PHP_COUCHBASE_LOCAL
+void ccm_create_bucket_impl(INTERNAL_FUNCTION_PARAMETERS)
+{
+ static const char path[] = "/pools/default/buckets";
+ struct bucket_meta_info meta;
+ zval *res, *options = NULL;
+ char name[64];
+ lcb_t instance;
+ struct lcb_http_ctx ctx = { 0 };
+ lcb_http_cmd_t cmd = { 0 };
+ lcb_error_t rc;
+ char *data;
+ int dlen;
+
+ init_bucket_meta(&meta);
+
+ res = zend_read_property(couchbase_ce, getThis(),
+ ZEND_STRL(COUCHBASE_PROPERTY_HANDLE), 1
+ TSRMLS_CC);
+ if (ZVAL_IS_NULL(res) || IS_RESOURCE != Z_TYPE_P(res)) {
+ zend_throw_exception(ccm_exception, "unintilized couchbase",
+ 0 TSRMLS_CC);
+ return;
+ }
+
+ meta.name.present = 1;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa",
+ &meta.name.value.buffer,
+ &meta.name.value.len,
+ &options) == FAILURE) {
+ return;
+ }
+
+ if (meta.name.value.len >= sizeof(name)) {
+ memcpy(name, meta.name.value.buffer, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ } else {
+ memcpy(name, meta.name.value.buffer, meta.name.value.len);
+ name[meta.name.value.len] = '\0';
+ }
+
+ ZEND_FETCH_RESOURCE2(instance, lcb_t, &res, -1,
+ PHP_COUCHBASE_CLUSTER_RESOURCE,
+ le_couchbase_cluster, le_pcouchbase_cluster);
+
+
+ if (extract_bucket_options(options, &meta TSRMLS_CC) != 0) {
+ /* Exception already thrown */
+ return;
+ }
+
+ data = calloc(4096, 1); // should be more than enough ;) (but fixme)
+ dlen = meta_to_url(data, &meta);
+ cmd.v.v0.path = path;
+ cmd.v.v0.npath = strlen(path);
+ cmd.v.v0.body = data;
+ cmd.v.v0.nbody = dlen;
+ cmd.v.v0.method = LCB_HTTP_METHOD_POST;
+ cmd.v.v0.content_type = "application/x-www-form-urlencoded";
+
+ rc = lcb_make_http_request(instance, &ctx,
+ LCB_HTTP_TYPE_MANAGEMENT, &cmd, NULL);
+
+ free(data);
+
+ release_bucket_meta(&meta);
+
+ if (rc != LCB_SUCCESS || ctx.error != LCB_SUCCESS) {
+ char errmsg[512];
+ if (rc == LCB_SUCCESS) {
+ rc = ctx.error;
+ }
+ snprintf(errmsg, sizeof(errmsg), "Failed to create bucket \"%s\": %s",
+ name, lcb_strerror(instance, rc));
+ zend_throw_exception(ccm_lcb_exception, errmsg, 0 TSRMLS_CC);
+ free(ctx.payload);
+ return ;
+ }
+
+ switch (ctx.status) {
+ case LCB_HTTP_STATUS_OK:
+ case LCB_HTTP_STATUS_ACCEPTED:
+ free(ctx.payload);
+ RETURN_TRUE;
+
+ case LCB_HTTP_STATUS_UNAUTHORIZED:
+ zend_throw_exception(ccm_auth_exception, "Incorrect credentials",
+ 0 TSRMLS_CC);
+ break;
+
+ default:
+ if (ctx.payload == NULL) {
+ char message[200];
+ sprintf(message, "{\"errors\":{\"http response\": %d }}",
+ (int)ctx.status);
+ zend_throw_exception(ccm_server_exception, message, 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(ccm_server_exception, ctx.payload,
+ 0 TSRMLS_CC);
+ }
+ }
+
+ /* exception is already thrown */
+ free(ctx.payload);
+}
+
+PHP_COUCHBASE_LOCAL
+void ccm_delete_bucket_impl(INTERNAL_FUNCTION_PARAMETERS)
+{
+ zval *res, *options = NULL;
+ char *name = NULL;
+ int name_len = 0;
+ lcb_t instance;
+ struct lcb_http_ctx ctx = { 0 };
+ lcb_http_cmd_t cmd = { 0 };
+ lcb_error_t rc;
+ char *path;
+ int plen;
+
+ res = zend_read_property(couchbase_ce, getThis(),
+ ZEND_STRL(COUCHBASE_PROPERTY_HANDLE),
+ 1 TSRMLS_CC);
+ if (ZVAL_IS_NULL(res) || IS_RESOURCE != Z_TYPE_P(res)) {
+ zend_throw_exception(ccm_exception, "unintilized couchbase",
+ 0 TSRMLS_CC);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name,
+ &name_len) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE2(instance, lcb_t, &res, -1,
+ PHP_COUCHBASE_CLUSTER_RESOURCE,
+ le_couchbase_cluster, le_pcouchbase_cluster);
+
+ path = calloc(sizeof("/pools/default/buckets/") + name_len + 1, 1);
+ plen = sprintf(path, "/pools/default/buckets/");
+ memcpy(path + plen, name, name_len);
+ plen += name_len;
+
+ cmd.v.v0.path = path;
+ cmd.v.v0.npath = plen;
+ cmd.v.v0.method = LCB_HTTP_METHOD_DELETE;
+ cmd.v.v0.content_type = "application/x-www-form-urlencoded";
+
+ rc = lcb_make_http_request(instance, &ctx,
+ LCB_HTTP_TYPE_MANAGEMENT, &cmd, NULL);
+ free(path);
+
+ if (rc != LCB_SUCCESS || ctx.error != LCB_SUCCESS) {
+ char errmsg[512];
+ if (rc == LCB_SUCCESS) {
+ rc = ctx.error;
+ }
+ snprintf(errmsg, sizeof(errmsg), "Failed to remove bucket \"%s\": %s",
+ name, lcb_strerror(instance, rc));
+ zend_throw_exception(ccm_lcb_exception, errmsg, 0 TSRMLS_CC);
+ free(ctx.payload);
+ return ;
+ }
+
+ switch (ctx.status) {
+ case LCB_HTTP_STATUS_OK:
+ free(ctx.payload);
+ RETURN_TRUE;
+ ;
+
+ default:
+ if (ctx.payload == NULL) {
+ char message[200];
+ sprintf(message, "{\"errors\":{\"http response\": %d }}",
+ (int)ctx.status);
+ zend_throw_exception(ccm_server_exception, message, 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(ccm_server_exception, ctx.payload,
+ 0 TSRMLS_CC);
+ }
+ }
+
+ free(ctx.payload);
+}
+
+PHP_COUCHBASE_LOCAL
+void ccm_modify_bucket_impl(INTERNAL_FUNCTION_PARAMETERS)
+{
+ char *path;
+ int plen;
+ char name[64];
+ struct bucket_meta_info meta;
+ zval *res, *options = NULL;
+ lcb_t instance;
+ struct lcb_http_ctx ctx = { 0 };
+ lcb_http_cmd_t cmd = { 0 };
+ lcb_error_t rc;
+ char *data;
+ int dlen;
+
+ init_bucket_meta(&meta);
+
+ res = zend_read_property(couchbase_ce, getThis(),
+ ZEND_STRL(COUCHBASE_PROPERTY_HANDLE), 1
+ TSRMLS_CC);
+ if (ZVAL_IS_NULL(res) || IS_RESOURCE != Z_TYPE_P(res)) {
+ zend_throw_exception(ccm_exception, "unintilized couchbase",
+ 0 TSRMLS_CC);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa",
+ &meta.name.value.buffer,
+ &meta.name.value.len,
+ &options) == FAILURE) {
+ return;
+ }
+
+ if (meta.name.value.len >= sizeof(name)) {
+ memcpy(name, meta.name.value.buffer, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ } else {
+ memcpy(name, meta.name.value.buffer, meta.name.value.len);
+ name[meta.name.value.len] = '\0';
+ }
+
+
+ ZEND_FETCH_RESOURCE2(instance, lcb_t, &res, -1,
+ PHP_COUCHBASE_CLUSTER_RESOURCE,
+ le_couchbase_cluster, le_pcouchbase_cluster);
+
+ extract_bucket_options(options, &meta TSRMLS_CC);
+
+ path = calloc(sizeof("/pools/default/buckets/") + meta.name.value.len + 1, 1);
+ plen = sprintf(path, "/pools/default/buckets/");
+ memcpy(path + plen, meta.name.value.buffer, meta.name.value.len);
+ plen += meta.name.value.len;
+
+ data = calloc(4096, 1); // should be more than enough ;) (but fixme)
+ dlen = meta_to_url(data, &meta);
+
+ cmd.v.v0.path = path;
+ cmd.v.v0.npath = plen;
+ cmd.v.v0.body = data;
+ cmd.v.v0.nbody = dlen;
+ cmd.v.v0.method = LCB_HTTP_METHOD_POST;
+
+ cmd.v.v0.method = LCB_HTTP_METHOD_POST;
+ cmd.v.v0.content_type = "application/x-www-form-urlencoded";
+
+ rc = lcb_make_http_request(instance, &ctx,
+ LCB_HTTP_TYPE_MANAGEMENT, &cmd, NULL);
+
+ free(data);
+ free(path);
+
+ release_bucket_meta(&meta);
+
+ if (rc != LCB_SUCCESS || ctx.error != LCB_SUCCESS) {
+ char errmsg[512];
+ if (rc == LCB_SUCCESS) {
+ rc = ctx.error;
+ }
+ snprintf(errmsg, sizeof(errmsg), "Failed to modify bucket \"%s\": %s",
+ name, lcb_strerror(instance, rc));
+ zend_throw_exception(ccm_lcb_exception, errmsg, 0 TSRMLS_CC);
+ free(ctx.payload);
+ return ;
+ }
+
+ switch (ctx.status) {
+ case LCB_HTTP_STATUS_OK:
+ case LCB_HTTP_STATUS_ACCEPTED:
+ free(ctx.payload);
+ RETURN_TRUE;
+ ;
+
+ default:
+ if (ctx.payload == NULL) {
+ char message[200];
+ sprintf(message, "{\"errors\":{\"http response\": %d }}",
+ (int)ctx.status);
+ zend_throw_exception(ccm_server_exception, message, 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(ccm_server_exception, ctx.payload,
+ 0 TSRMLS_CC);
+ }
+ }
+
+ free(ctx.payload);
+}
+
+PHP_COUCHBASE_LOCAL
+void ccm_get_bucket_info_impl(INTERNAL_FUNCTION_PARAMETERS)
+{
+ static const char uri[] = "/pools/default/buckets";
+ char *allocuri = NULL;
+ char *requesturi = (char*)uri;
+ zval *res;
+ char *name;
+ int name_len;
+
+ lcb_t instance;
+ struct lcb_http_ctx ctx = { 0 };
+ lcb_http_cmd_t cmd = { 0 };
+ lcb_error_t rc;
+
+ res = zend_read_property(couchbase_ce, getThis(),
+ ZEND_STRL(COUCHBASE_PROPERTY_HANDLE), 1
+ TSRMLS_CC);
+ if (ZVAL_IS_NULL(res) || IS_RESOURCE != Z_TYPE_P(res)) {
+ zend_throw_exception(ccm_exception, "unintilized couchbase",
+ 0 TSRMLS_CC);
+ return;
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &name,
+ &name_len) == FAILURE) {
+ return;
+ }
+
+ ctx.use_emalloc = 1;
+ ZEND_FETCH_RESOURCE2(instance, lcb_t, &res, -1,
+ PHP_COUCHBASE_CLUSTER_RESOURCE,
+ le_couchbase_cluster, le_pcouchbase_cluster);
+
+
+ if (name != NULL) {
+ allocuri = malloc(strlen(uri) + name_len + 2);
+ if (allocuri == NULL) {
+ zend_throw_exception(ccm_exception, "failed to allocate memory",
+ 0 TSRMLS_CC);
+ return;
+ }
+ sprintf(allocuri, "%s/%*s", uri, name_len, name);
+ requesturi = allocuri;
+ }
+
+ cmd.v.v0.path = requesturi;
+ cmd.v.v0.npath = strlen(requesturi);
+ cmd.v.v0.body = NULL;
+ cmd.v.v0.nbody = 0;
+ cmd.v.v0.method = LCB_HTTP_METHOD_GET;
+ cmd.v.v0.content_type = "application/x-www-form-urlencoded";
+
+ rc = lcb_make_http_request(instance, &ctx,
+ LCB_HTTP_TYPE_MANAGEMENT, &cmd, NULL);
+
+ free(allocuri);
+
+ if (rc != LCB_SUCCESS || ctx.error != LCB_SUCCESS) {
+ char errmsg[512];
+ if (rc == LCB_SUCCESS) {
+ rc = ctx.error;
+ }
+ snprintf(errmsg, sizeof(errmsg),
+ "Failed to get bucket information: %s",
+ lcb_strerror(instance, rc));
+ zend_throw_exception(ccm_lcb_exception, errmsg, 0 TSRMLS_CC);
+ efree(ctx.payload);
+ return ;
+ }
+
+ switch (ctx.status) {
+ case LCB_HTTP_STATUS_OK:
+ case LCB_HTTP_STATUS_ACCEPTED:
+ RETURN_STRING(ctx.payload, 0);
+
+ case LCB_HTTP_STATUS_UNAUTHORIZED:
+ zend_throw_exception(ccm_auth_exception, "Incorrect credentials",
+ 0 TSRMLS_CC);
+ break;
+
+ default:
+ if (ctx.payload == NULL) {
+ char message[200];
+ sprintf(message, "{\"errors\":{\"http response\": %d }}",
+ (int)ctx.status);
+ zend_throw_exception(ccm_server_exception, message, 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(ccm_server_exception, ctx.payload,
+ 0 TSRMLS_CC);
+ }
+ }
+
+ /* exception is already thrown */
+ efree(ctx.payload);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet expandtab sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
43 management/buckets.h
@@ -0,0 +1,43 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+#ifndef MANAGEMENT_BUCKETS_H
+#define MANAGEMENT_BUCKETS_H 1
+
+PHP_COUCHBASE_LOCAL
+extern void ccm_create_bucket_impl(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_COUCHBASE_LOCAL
+extern void ccm_modify_bucket_impl(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_COUCHBASE_LOCAL
+extern void ccm_delete_bucket_impl(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_COUCHBASE_LOCAL
+extern void ccm_get_bucket_info_impl(INTERNAL_FUNCTION_PARAMETERS);
+
+#endif
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet expandtab sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
40 management/cluster.h
@@ -0,0 +1,40 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+#ifndef MANAGEMENT_CLUSTER_H
+#define MANAGEMENT_CLUSTER_H
+
+#define PHP_COUCHBASE_CLUSTER_RESOURCE "CouchbaseCluster"
+#define PHP_COUCHBASE_CLUSTER_PERSISTENT_RESOURCE "Persistent Couchbase Cluster"
+#define COUCHBASE_PROPERTY_HANDLE "_handle"
+
+
+PHP_COUCHBASE_LOCAL
+void init_couchbase_cluster(int module_number TSRMLS_DC);
+
+#endif /* MANAGEMENT_CLUSTER_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet expandtab sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
47 management/exceptions.h
@@ -0,0 +1,47 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+#ifndef MANAGEMENT_EXCEPTIONS_H
+#define MANAGEMENT_EXCEPTIONS_H
+
+PHP_COUCHBASE_LOCAL
+extern zend_class_entry *ccm_exception;
+
+PHP_COUCHBASE_LOCAL
+extern zend_class_entry *ccm_illegal_key_exception;
+
+PHP_COUCHBASE_LOCAL
+extern zend_class_entry *ccm_auth_exception;
+
+PHP_COUCHBASE_LOCAL
+extern zend_class_entry *ccm_lcb_exception;
+
+PHP_COUCHBASE_LOCAL
+extern zend_class_entry *ccm_server_exception;
+
+#endif /* MANAGEMENT_EXCEPTION_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet expandtab sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
246 management/instance.c
@@ -0,0 +1,246 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "internal.h"
+#include "instance.h"
+
+static void lcb_http_callback(lcb_http_request_t request,
+ lcb_t instance,
+ const void *cookie,
+ lcb_error_t error,
+ const lcb_http_resp_t *resp)
+{
+ struct lcb_http_ctx *ctx = (void *)cookie;
+ assert(cookie != NULL);
+ ctx->error = error;
+ ctx->payload = NULL;
+
+ if (resp->version != 0) {
+ /* @todo add an error code I may use */
+ ctx->error = LCB_NOT_SUPPORTED;
+ } else {
+ ctx->status = resp->v.v0.status;
+ if (resp->v.v0.nbytes != 0) {
+ if (ctx->use_emalloc) {
+ ctx->payload = emalloc(resp->v.v0.nbytes + 1);
+ } else {
+ ctx->payload = malloc(resp->v.v0.nbytes + 1);
+ }
+ if (ctx->payload != NULL) {
+ memcpy(ctx->payload, resp->v.v0.bytes, resp->v.v0.nbytes);
+ ctx->payload[resp->v.v0.nbytes] = '\0';
+ }
+ }
+ }
+}
+
+
+PHP_COUCHBASE_LOCAL
+void ccm_create_impl(INTERNAL_FUNCTION_PARAMETERS)
+{
+ char *user = NULL;
+ char *passwd = NULL;
+ int ulen = 0;
+ int plen = 0;
+ zval *hosts = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zss",
+ &hosts, &user, &ulen,
+ &passwd, &plen) == FAILURE) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Failed to parse parameters");
+ RETURN_FALSE;
+ } else {
+ lcb_t handle;
+ lcb_error_t retval;
+ lcb_io_opt_t iops;
+ php_couchbase_res *couchbase_res;
+ php_couchbase_ctx *ctx = NULL;
+ struct lcb_create_st copts = {0};
+ char *allochosts = NULL;
+ char *host = NULL;
+
+ if (ulen == 0 || plen == 0) {
+ zend_throw_exception(ccm_exception,
+ "CouchbaseClusterManager require username/password",
+ 0 TSRMLS_CC);
+ return;
+ }
+
+ if (hosts != NULL) {
+ allochosts = calloc(4096, 1);
+ host = allochosts;
+
+ switch (Z_TYPE_P(hosts)) {
+ case IS_ARRAY:
+ {
+ int nhosts;
+ zval **curzv = NULL;
+ HashTable *hthosts = Z_ARRVAL_P(hosts);
+ HashPosition htpos;
+ int ii;
+ int pos = 0;
+
+ nhosts = zend_hash_num_elements(hthosts);
+
+ zend_hash_internal_pointer_reset_ex(hthosts, &htpos);
+
+ for (ii = 0; ii < nhosts && zend_hash_get_current_data_ex(hthosts, (void **)&curzv, &htpos) == SUCCESS; zend_hash_move_forward_ex(hthosts, &htpos), ii++) {
+ if (!Z_TYPE_PP(curzv) == IS_STRING) {
+ zend_throw_exception(ccm_exception,
+ "Element in the host array is not a string",
+ 0 TSRMLS_CC);
+ free(allochosts);
+ return;
+ }
+ memcpy(allochosts + pos, Z_STRVAL_PP(curzv), Z_STRLEN_PP(curzv));
+ pos += Z_STRLEN_PP(curzv);
+ pos += sprintf(allochosts + pos, ";");
+ }
+ }
+ break;
+
+ case IS_STRING:
+ if (allochosts == NULL) {
+ zend_throw_exception(ccm_exception,
+ "Failed to allocate memory",
+ 0 TSRMLS_CC);
+ return;
+ }
+ memcpy(allochosts, Z_STRVAL_P(hosts), Z_STRLEN_P(hosts));
+ break;
+
+ default:
+ zend_throw_exception(ccm_exception,
+ "hosts should be array or string",
+ 0 TSRMLS_CC);
+ return;
+ }
+ }
+
+ copts.version = 1;
+ copts.v.v1.host = host;
+ copts.v.v1.user = user;
+ copts.v.v1.passwd = passwd;
+ copts.v.v1.type = LCB_TYPE_CLUSTER;
+
+ if (lcb_create(&handle, &copts) != LCB_SUCCESS) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Failed to create libcouchbase instance");
+ free(allochosts);
+ RETURN_FALSE;
+ }
+ free(allochosts);
+
+ // @todo fixme!
+ /* lcb_set_error_callback(handle, php_couchbase_error_callback); */
+ lcb_behavior_set_syncmode(handle, LCB_SYNCHRONOUS);
+ lcb_set_http_complete_callback(handle, lcb_http_callback);
+
+ ZEND_REGISTER_RESOURCE(return_value, handle, le_couchbase_cluster);
+ zend_update_property(couchbase_cluster_ce, getThis(),
+ ZEND_STRL(COUCHBASE_PROPERTY_HANDLE),
+ return_value TSRMLS_CC);
+ }
+}
+
+PHP_COUCHBASE_LOCAL
+void ccm_get_info_impl(INTERNAL_FUNCTION_PARAMETERS)
+{
+ static const char uri[] = "/pools/default";
+ zval *res;
+
+ lcb_t instance;
+ struct lcb_http_ctx ctx = { 0 };
+ lcb_http_cmd_t cmd = { 0 };
+ lcb_error_t rc;
+
+ res = zend_read_property(couchbase_ce, getThis(),
+ ZEND_STRL(COUCHBASE_PROPERTY_HANDLE), 1
+ TSRMLS_CC);
+ if (ZVAL_IS_NULL(res) || IS_RESOURCE != Z_TYPE_P(res)) {
+ zend_throw_exception(ccm_exception, "unintilized couchbase",
+ 0 TSRMLS_CC);
+ return;
+ }
+
+ ctx.use_emalloc = 1;
+ ZEND_FETCH_RESOURCE2(instance, lcb_t, &res, -1,
+ PHP_COUCHBASE_CLUSTER_RESOURCE,
+ le_couchbase_cluster, le_pcouchbase_cluster);
+
+ cmd.v.v0.path = uri;
+ cmd.v.v0.npath = strlen(uri);
+ cmd.v.v0.body = NULL;
+ cmd.v.v0.nbody = 0;
+ cmd.v.v0.method = LCB_HTTP_METHOD_GET;
+ cmd.v.v0.content_type = "application/x-www-form-urlencoded";
+
+ rc = lcb_make_http_request(instance, &ctx,
+ LCB_HTTP_TYPE_MANAGEMENT, &cmd, NULL);
+
+ if (rc != LCB_SUCCESS || ctx.error != LCB_SUCCESS) {
+ char errmsg[512];
+ if (rc == LCB_SUCCESS) {
+ rc = ctx.error;
+ }
+ snprintf(errmsg, sizeof(errmsg),
+ "Failed to get cluster information: %s",
+ lcb_strerror(instance, rc));
+ zend_throw_exception(ccm_lcb_exception, errmsg, 0 TSRMLS_CC);
+ efree(ctx.payload);
+ return ;
+ }
+
+ switch (ctx.status) {
+ case LCB_HTTP_STATUS_OK:
+ case LCB_HTTP_STATUS_ACCEPTED:
+ RETURN_STRING(ctx.payload, 0);
+ abort();
+
+ case LCB_HTTP_STATUS_UNAUTHORIZED:
+ zend_throw_exception(ccm_auth_exception, "Incorrect credentials",
+ 0 TSRMLS_CC);
+ break;
+
+ default:
+ if (ctx.payload == NULL) {
+ char message[200];
+ sprintf(message, "{\"errors\":{\"http response\": %d }}",
+ (int)ctx.status);
+ zend_throw_exception(ccm_server_exception, message, 0 TSRMLS_CC);
+ } else {
+ zend_throw_exception(ccm_server_exception, ctx.payload,
+ 0 TSRMLS_CC);
+ }
+ }
+
+ /* exception is already thrown */
+ efree(ctx.payload);
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet expandtab sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
53 management/instance.h
@@ -0,0 +1,53 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+#ifndef MANAGEMENT_INSTANCE_H
+#define MANAGEMENT_INSTANCE_H 1
+
+PHP_COUCHBASE_LOCAL
+extern void ccm_create_impl(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_COUCHBASE_LOCAL
+extern void ccm_get_info_impl(INTERNAL_FUNCTION_PARAMETERS);
+
+PHP_COUCHBASE_LOCAL
+extern int le_couchbase_cluster;
+
+PHP_COUCHBASE_LOCAL
+extern int le_pcouchbase_cluster;
+
+PHP_COUCHBASE_LOCAL
+zend_class_entry *couchbase_cluster_ce;
+
+struct lcb_http_ctx {
+ lcb_error_t error;
+ lcb_http_status_t status;
+ char *payload;
+ int use_emalloc;
+};
+
+#endif
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet expandtab sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
237 management/management.c
@@ -0,0 +1,237 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright 2012 Couchbase, Inc. |
+ +----------------------------------------------------------------------+
+ | Licensed under the Apache License, Version 2.0 (the "License"); |
+ | you may not use this file except in compliance with the License. |
+ | You may obtain a copy of the License at |
+ | http://www.apache.org/licenses/LICENSE-2.0 |
+ | Unless required by applicable law or agreed to in writing, software |
+ | distributed under the License is distributed on an "AS IS" BASIS, |
+ | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
+ | implied. See the License for the specific language governing |
+ | permissions and limitations under the License. |
+ +----------------------------------------------------------------------+
+ | Author: Trond Norbye <trond.norbye@couchbase.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include "internal.h"
+#include "buckets.h"
+
+#include "cluster.h"
+#include "instance.h"
+#include "buckets.h"
+
+PHP_METHOD(couchbaseclustermanager, __construct);
+PHP_METHOD(couchbaseclustermanager, createBucket);
+PHP_METHOD(couchbaseclustermanager, modifyBucket);
+PHP_METHOD(couchbaseclustermanager, deleteBucket);
+PHP_METHOD(couchbaseclustermanager, getBucketInfo);
+PHP_METHOD(couchbaseclustermanager, getInfo);
+
+PHP_COUCHBASE_LOCAL
+int le_couchbase_cluster;
+PHP_COUCHBASE_LOCAL
+int le_pcouchbase_cluster;
+PHP_COUCHBASE_LOCAL
+zend_class_entry *couchbase_cluster_ce;
+
+PHP_COUCHBASE_LOCAL
+zend_class_entry *ccm_exception;
+
+PHP_COUCHBASE_LOCAL
+zend_class_entry *ccm_illegal_key_exception;
+
+PHP_COUCHBASE_LOCAL
+zend_class_entry *ccm_auth_exception;
+
+PHP_COUCHBASE_LOCAL
+zend_class_entry *ccm_lcb_exception;
+
+PHP_COUCHBASE_LOCAL
+zend_class_entry *ccm_server_exception;
+
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 3)
+ZEND_ARG_INFO(0, host)
+ZEND_ARG_INFO(0, user)
+ZEND_ARG_INFO(0, password)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_create_bucket, 0, 0, 6)
+ZEND_ARG_INFO(0, name)
+ZEND_ARG_INFO(0, type)
+ZEND_ARG_INFO(0, quota)
+ZEND_ARG_INFO(0, replicas)
+ZEND_ARG_INFO(0, auth)
+ZEND_ARG_INFO(0, passwd)
+ZEND_ARG_INFO(0, port)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_modify_bucket, 0, 0, 5)
+ZEND_ARG_INFO(0, name)
+ZEND_ARG_INFO(0, quota)
+ZEND_ARG_INFO(0, replicas)
+ZEND_ARG_INFO(0, auth)
+ZEND_ARG_INFO(0, passwd)
+ZEND_ARG_INFO(0, port)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_delete_bucket, 0, 0, 1)
+ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_get_bucket_info, 0, 0, 0)
+ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO()
+
+static zend_function_entry methods[] = {
+ PHP_ME(couchbaseclustermanager, __construct, arginfo_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(couchbaseclustermanager, createBucket, arginfo_create_bucket, ZEND_ACC_PUBLIC)
+ PHP_ME(couchbaseclustermanager, modifyBucket, arginfo_modify_bucket, ZEND_ACC_PUBLIC)
+ PHP_ME(couchbaseclustermanager, deleteBucket, arginfo_delete_bucket, ZEND_ACC_PUBLIC)
+ PHP_ME(couchbaseclustermanager, getBucketInfo, arginfo_get_bucket_info, ZEND_ACC_PUBLIC)
+ PHP_ME(couchbaseclustermanager, getInfo, NULL, ZEND_ACC_PUBLIC) {
+ NULL, NULL, NULL
+ }
+};
+
+/* {{{ proto CouchbaseClusterManager::__construct(string $host[, string $user[, string $password]]) */
+PHP_METHOD(couchbaseclustermanager, __construct)
+{
+ ccm_create_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto CouchbaseClusterManager::createBucket(string $name, array $meta) */
+PHP_METHOD(couchbaseclustermanager, createBucket)
+{
+ ccm_create_bucket_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto CouchbaseClusterManager::modifyBucket(string $name, array $meta) */
+PHP_METHOD(couchbaseclustermanager, modifyBucket)
+{
+ ccm_modify_bucket_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto Couchbaseclustermanager::deleteBucket(string $name) */
+PHP_METHOD(couchbaseclustermanager, deleteBucket)
+{
+ ccm_delete_bucket_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto Couchbaseclustermanager::getBucketInfo([string $name]) */
+PHP_METHOD(couchbaseclustermanager, getBucketInfo)
+{
+ ccm_get_bucket_info_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+
+/* {{{ proto Couchbaseclustermanager::getInfo(void) */
+PHP_METHOD(couchbaseclustermanager, getInfo)
+{
+ ccm_get_info_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+static void resource_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ lcb_t instance = (lcb_t)rsrc->ptr;
+ if (instance) {
+ lcb_destroy(instance);
+ }
+}
+
+static void persistent_resource_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+}
+
+
+PHP_COUCHBASE_LOCAL
+void init_couchbase_cluster(int module_number TSRMLS_DC)
+{
+ le_couchbase_cluster = zend_register_list_destructors_ex(resource_destructor, NULL,
+ PHP_COUCHBASE_CLUSTER_RESOURCE,
+ module_number);
+ le_pcouchbase_cluster = zend_register_list_destructors_ex(NULL,
+ persistent_resource_destructor,
+ PHP_COUCHBASE_CLUSTER_PERSISTENT_RESOURCE,
+ module_number);
+
+ {
+ zend_class_entry ce;
+ INIT_CLASS_ENTRY(ce, "CouchbaseClusterManager", methods);
+ couchbase_cluster_ce = zend_register_internal_class_ex(&ce, NULL,
+ NULL TSRMLS_CC);
+ }
+
+ /* Initialize Exceptions */
+ {
+ zend_class_entry ce;
+ zend_class_entry *cle;
+
+ INIT_CLASS_ENTRY(ce, "CouchbaseException", NULL);
+
+#if ZEND_MODULE_API_NO >= 20060613
+ cle = (zend_class_entry *)zend_exception_get_default(TSRMLS_C);
+#else
+ cle = (zend_class_entry *)zend_exception_get_default();
+#endif
+
+ ccm_exception = zend_register_internal_class_ex(&ce, cle,
+ NULL TSRMLS_CC);
+ }
+
+ {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "CouchbaseIllegalKeyException", NULL);
+ ccm_illegal_key_exception = zend_register_internal_class_ex(&ce,
+ ccm_exception,
+ NULL TSRMLS_CC);
+ }
+
+ {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "CouchbaseAuthenticationException", NULL);
+ ccm_auth_exception = zend_register_internal_class_ex(&ce,
+ ccm_exception,
+ NULL TSRMLS_CC);
+ }
+
+ {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "CouchbaseLibcouchbaseException", NULL);
+ ccm_lcb_exception = zend_register_internal_class_ex(&ce,
+ ccm_exception,
+ NULL TSRMLS_CC);
+ }
+
+ {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "CouchbaseServerException", NULL);
+ ccm_server_exception = zend_register_internal_class_ex(&ce,
+ ccm_exception,
+ NULL TSRMLS_CC);
+ }
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
View
1  php_couchbase.h
@@ -292,7 +292,6 @@ PHP_COUCHBASE_LOCAL
extern void usleep(unsigned long);
#endif /* WIN32 */
-
/**
* See https://github.com/php-memcached-dev/php-memcached/blob/1416a09d1d0e78cea5fec227744c1fe7b352017b/php_memcached.c#L2728
* - pecl-memcached uses a raw unconverted (i.e. no htonl) for determining the
View
147 tests/Cluster.inc
@@ -0,0 +1,147 @@
+<?php
+
+require_once 'Common.inc';
+
+/**
+ *Basic bucket tests
+ */
+class Cluster extends CouchbaseTestCommon
+{
+ function getClusterInfo($handle) {
+ $str = $handle->getInfo();
+ $this->assertNotNull($str, "Expected the server to return something");
+ $obj = json_decode($str);
+ $this->assertNotNull($obj, "Failed to decode the json output");
+ return $obj;
+ }
+
+ function createHandle() {
+ try {
+ $cb = new CouchbaseClusterManager(COUCHBASE_CONFIG_HOST,
+ COUCHBASE_CONFIG_USER,
+ COUCHBASE_CONFIG_PASSWD);
+ return $cb;
+ } catch (ErrorException $e) {
+ $this->assertEquals(
+ 'CouchbaseClusterManager require username/password',
+ $e->getMessage());
+ $this->markTestSkipped("Test skipped due to missing credentials");
+ }
+ }
+
+ function testGetInfo() {
+ $cb = $this->createHandle();
+ if ($cb == null) {
+ return;
+ }
+ $this->getClusterInfo($cb);
+ }
+
+ function doDeleteBucket($cb, $name) {
+ try {
+ $data = $cb->getBucketInfo($name);
+ } catch (CouchbaseServerException $e) {
+ if (preg_match("/Requested resource not found/", $e->getMessage())) {
+ return;
+ }
+ }
+
+ try {
+ $cb->deleteBucket("php-ext-test-bucket");
+ } catch (ErrorException $e) {
+ $this->assertRegexp('/Some nodes are still deleting bucket/i',
+ $e->getMessage());
+ }
+
+ do {
+ try {
+ $data = $cb->getBucketInfo($name);
+ } catch (CouchbaseServerException $e) {
+ if (preg_match("/Requested resource not found/",
+ $e->getMessage())) {
+ return;
+ }
+ }
+ sleep(1);
+ } while (true);
+ }
+
+
+ function testBucketCreate() {
+ $cb = $this->createHandle();
+ if ($cb == null) {
+ return;
+ }
+
+ $this->doDeleteBucket($cb, "php-ext-test-bucket");
+
+ $info = $this->getClusterInfo($cb);
+ $ram = $info->{"storageTotals"}->{"ram"};
+ $used = $ram->{"quotaUsed"} / 1048576;
+ $total = $ram->{"quotaTotal"} / 1048576;
+ $space = $total - $used;
+
+ if ($space > 100) {
+ $v = $cb->createBucket("php-ext-test-bucket",
+ array(
+ "type" => "couchbase",
+ "quota" => 100,
+ "replicas" => 1,
+ "enable_flush" => 1,
+ "parallel_compaction" => true,
+ "auth" => "sasl",
+ "password" => "foobar"
+ )
+ );
+ $this->assertTrue($v, "Expected to be able to create the bucket");
+ } else {
+ $this->markTestSkipped("Test skipped due to insufficient free space");
+ }
+
+ // Unfortunately the create is async, so we need to let it get
+ // time to create itself.. It should be online when the cluster
+ // populates the vbucket map
+ do {
+ sleep(1);
+ $str = $cb->getBucketInfo("php-ext-test-bucket");
+ $info = json_decode($str);
+ $vbm = $info->{"vBucketServerMap"}->{"vBucketMap"};
+ } while (count($vbm) < 1024);
+
+ // Clean up after ourself
+ $this->doDeleteBucket($cb, "php-ext-test-bucket");
+ }
+
+ function testInvalidParams() {
+ $cb = $this->createHandle();
+ if (!$cb) {
+ return;
+ }
+
+ $this->assertExceptionRegexp(
+ create_function('$cb', '$cb->createBucket(NULL, array());'),
+ array($cb),
+ '/./'
+ );
+
+ $this->assertExceptionRegexp(
+ create_function('$cb',
+ '$cb->createBucket("a_bucket", array("foo"=>"bar"));'),
+ array($cb),
+ '/./'
+ );
+
+ $this->assertExceptionRegexp(
+ create_function(
+ '$cb',
+ '$cb->createBucket('.
+ '"memcached_bucket",'.
+ 'array("type" => "memcached", "replicas" => 4));'
+ ),
+ array($cb),
+ '/./'
+ );
+ }
+}
+
+?>
View
1  tests/TEST_CLASSES
@@ -1,5 +1,6 @@
AppendPrepend
Arithmetic
+Cluster
Compression
Connection
Delay
View
14 tests/phpt/Cluster/BucketCreate.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Cluster - BucketCreate
+
+--SKIPIF--
+<?php
+include dirname(__FILE__)."/../../cbtestframework/cbtest-phpt-loader.inc";
+couchbase_phpt_skipif("Cluster", "testBucketCreate");
+
+--FILE--
+<?php
+include dirname(__FILE__)."/../../cbtestframework/cbtest-phpt-loader.inc";
+couchbase_phpt_runtest("Cluster", "testBucketCreate");
+--EXPECT--
+PHP_COUCHBASE_OK
View
14 tests/phpt/Cluster/GetInfo.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Cluster - GetInfo
+
+--SKIPIF--
+<?php
+include dirname(__FILE__)."/../../cbtestframework/cbtest-phpt-loader.inc";
+couchbase_phpt_skipif("Cluster", "testGetInfo");
+
+--FILE--
+<?php
+include dirname(__FILE__)."/../../cbtestframework/cbtest-phpt-loader.inc";
+couchbase_phpt_runtest("Cluster", "testGetInfo");
+--EXPECT--
+PHP_COUCHBASE_OK
View
14 tests/phpt/Cluster/InvalidParams.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Cluster - InvalidParams
+
+--SKIPIF--
+<?php
+include dirname(__FILE__)."/../../cbtestframework/cbtest-phpt-loader.inc";
+couchbase_phpt_skipif("Cluster", "testInvalidParams");
+
+--FILE--
+<?php
+include dirname(__FILE__)."/../../cbtestframework/cbtest-phpt-loader.inc";
+couchbase_phpt_runtest("Cluster", "testInvalidParams");
+--EXPECT--
+PHP_COUCHBASE_OK
Please sign in to comment.
Something went wrong with that request. Please try again.