Improve parser error messages.
authorBrian Aker <brian@tangent.org>
Sun, 27 Nov 2011 04:07:26 +0000 (20:07 -0800)
committerBrian Aker <brian@tangent.org>
Sun, 27 Nov 2011 04:07:26 +0000 (20:07 -0800)
18 files changed:
clients/memcapable.cc
example/memcached_light.c
example/storage.h
libmemcached/behavior.cc
libmemcached/close_socket.hpp [new file with mode: 0644]
libmemcached/common.h
libmemcached/connect.cc
libmemcached/csl/context.cc
libmemcached/csl/context.h
libmemcached/csl/parser.cc
libmemcached/csl/parser.yy
libmemcached/include.am
libmemcached/io.cc
libmemcachedprotocol/common.h
libtest/string.hpp
tests/libmemcached_world.h
tests/parser.cc
util/string.hpp

index b325413d28808f544046d41a7bf6562ee3224ed1..8bce153a555e44ffa9136d5c8e30f7a6194025bb 100644 (file)
@@ -33,7 +33,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <libmemcached/memcached.h>
+#include <libmemcached-1.0/memcached.h>
+#include <libmemcached/close_socket.hpp>
 #include <libmemcached/memcached/protocol_binary.h>
 #include <libmemcached/byteorder.h>
 #include <clients/utilities.h>
@@ -132,7 +133,7 @@ static memcached_socket_t set_noblock(void)
   if (flags == -1)
   {
     perror("Failed to get socket flags");
-    closesocket(sock);
+    memcached_close_socket(sock);
     return INVALID_SOCKET;
   }
 
@@ -141,7 +142,7 @@ static memcached_socket_t set_noblock(void)
     if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
     {
       perror("Failed to set socket to nonblocking mode");
-      closesocket(sock);
+      memcached_close_socket(sock);
       return INVALID_SOCKET;
     }
   }
index ed89286187ba684bef47bfe7bac2baac04f59ac4..1827437857bdfd144705223bb5581f3a5e0d22bc 100644 (file)
 #include <event.h>
 
 #include <libmemcachedprotocol-0.0/handler.h>
+#include <libmemcached/close_socket.hpp>
 #include <example/byteorder.h>
-#include "storage.h"
-#include "memcached_light.h"
+#include "example/storage.h"
+#include "example/memcached_light.h"
 
 extern memcached_binary_protocol_callback_st interface_v0_impl;
 extern memcached_binary_protocol_callback_st interface_v1_impl;
index 12955846a62d0c8ab09c133d87a01cd2a1aacac0..bd1b878097d9ebcdf0a32f91912cb3962c8ce87c 100644 (file)
@@ -1,6 +1,5 @@
 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
-#ifndef STORAGE_H
-#define STORAGE_H
+#pragma once
 
 struct item {
   uint64_t cas;
@@ -23,5 +22,3 @@ struct item* create_item(const void* key, size_t nkey, const void *data,
 bool delete_item(const void* key, size_t nkey);
 void flush(uint32_t when);
 void release_item(struct item* item);
-
-#endif
index 64456a4b6b9d29dc4351822d9bc731a372619006..bb17f2bdaa7b68014ca38d1a87935e7f10cb028a 100644 (file)
@@ -384,7 +384,7 @@ uint64_t memcached_behavior_get(memcached_st *ptr,
 
         if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, &sock_size, &sock_length) < 0)
         {
-          memcached_set_errno(*ptr, errno, MEMCACHED_AT);
+          memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
           return 0; /* Zero means error */
         }
       }
@@ -420,10 +420,9 @@ uint64_t memcached_behavior_get(memcached_st *ptr,
 
         if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, &sock_size, &sock_length) < 0)
         {
-          memcached_set_errno(*ptr, errno, MEMCACHED_AT);
+          memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
           return 0; /* Zero means error */
         }
-
       }
 
       return (uint64_t) sock_size;
diff --git a/libmemcached/close_socket.hpp b/libmemcached/close_socket.hpp
new file mode 100644 (file)
index 0000000..0d18857
--- /dev/null
@@ -0,0 +1,79 @@
+/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
+ * 
+ *  LibMemcached
+ *
+ *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
+ *  Copyright (C) 2006-2009 Brian Aker
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ *
+ *      * Redistributions of source code must retain the above copyright
+ *  notice, this list of conditions and the following disclaimer.
+ *
+ *      * Redistributions in binary form must reproduce the above
+ *  copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the
+ *  distribution.
+ *
+ *      * The names of its contributors may not be used to endorse or
+ *  promote products derived from this software without specific prior
+ *  written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#pragma once
+
+
+/* To hide the platform differences between MS Windows and Unix, I am
+ * going to use the Microsoft way and #define the Microsoft-specific
+ * functions to the unix way. Microsoft use a separate subsystem for sockets,
+ * but Unix normally just use a filedescriptor on the same functions. It is
+ * a lot easier to map back to the unix way with macros than going the other
+ * way without side effect ;-)
+ */
+#ifdef WIN32
+#include "win32/wrappers.h"
+#define get_socket_errno() WSAGetLastError()
+#else
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+#define closesocket(a) close(a)
+#define get_socket_errno() errno
+#endif
+
+#ifdef __cplusplus
+static inline void memcached_close_socket(int& socket_fd)
+{
+  closesocket(socket_fd);
+  socket_fd= INVALID_SOCKET;
+}
+#endif
+
+#ifndef HAVE_MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+
+#ifndef HAVE_MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+
+#ifndef HAVE_MSG_MORE
+#define MSG_MORE 0
+#endif
+
+
index 477351954e9cae5de2619ac92bd17b7d3f7ee5e2..ba0b4063a068f9443e0a768faa9f16eeee4ed936 100644 (file)
@@ -106,6 +106,7 @@ memcached_return_t memcached_server_execute(memcached_st *ptr,
 #include <libmemcached/string.hpp>
 #include <libmemcached/io.hpp>
 #include <libmemcached/do.hpp>
+#include <libmemcached/close_socket.hpp>
 #endif
 #include <libmemcached/internal.h>
 #include <libmemcached/array.h>
index 3cc8e2451de038a11f19fb04801ba7e069506ed9..6cad60d5ed4f942799d77f1edea8710e5725b1c7 100644 (file)
@@ -64,12 +64,14 @@ static memcached_return_t connect_poll(memcached_server_st *server)
       {
         int err;
         socklen_t len= sizeof (err);
-        (void)getsockopt(server->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-
-        // We check the value to see what happened wth the socket.
-        if (err == 0)
+        if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
         {
-          return MEMCACHED_SUCCESS;
+          // We check the value to see what happened wth the socket.
+          if (err == 0)
+          {
+            return MEMCACHED_SUCCESS;
+          }
+          errno= err;
         }
 
         return memcached_set_errno(*server, err, MEMCACHED_AT);
@@ -99,21 +101,26 @@ static memcached_return_t connect_poll(memcached_server_st *server)
         if (fds[0].revents & POLLERR)
         {
           int err;
-          socklen_t len= sizeof (err);
-          (void)getsockopt(server->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-          memcached_set_errno(*server, (err == 0) ? get_socket_errno() : err, MEMCACHED_AT);
-        }
-        else
-        {
-          memcached_set_errno(*server, get_socket_errno(), MEMCACHED_AT);
+          socklen_t len= sizeof(err);
+          if (getsockopt(server->fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
+          {
+            if (err == 0)
+            {
+              // This should never happen, if it does? Punt.  
+              continue;
+            }
+            errno= err;
+          }
         }
 
+        int local_errno= get_socket_errno(); // We cache in case closesocket() modifies errno
+
         assert_msg(server->fd != INVALID_SOCKET, "poll() was passed an invalid file descriptor");
         (void)closesocket(server->fd);
         server->fd= INVALID_SOCKET;
         server->state= MEMCACHED_SERVER_STATE_NEW;
 
-        return memcached_set_errno(*server, get_socket_errno(), MEMCACHED_AT);
+        return memcached_set_errno(*server, local_errno, MEMCACHED_AT);
       }
     }
   }
index 36ff2587998956708e886bc4c3ad7f89861b5897..1e6e18ae588dae871732473346e4c05a1546e330 100644 (file)
@@ -49,7 +49,13 @@ void Context::abort(const char *error_arg, yytokentype last_token, const char *l
     return;
   }
 
-  memcached_set_parser_error(*memc, MEMCACHED_AT, "%s", last_token_str ? last_token_str : " ");
+  if (last_token_str)
+  {
+    memcached_set_parser_error(*memc, MEMCACHED_AT, "%s", last_token_str);
+    return;
+  }
+
+  memcached_set_parser_error(*memc, MEMCACHED_AT, "unknown parsing error");
 }
 
 void Context::error(const char *error_arg, yytokentype last_token, const char *last_token_str)
@@ -100,3 +106,17 @@ const char *Context::set_hostname(const char *str, size_t size)
   return _hostname;
 }
 
+bool Context::set_hash(memcached_hash_t hash)
+{
+  if (_has_hash)
+  {
+    return false;
+  }
+
+  if ((memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_HASH, hash)) != MEMCACHED_SUCCESS)
+  {
+    return false;
+  }
+
+  return _has_hash= true;
+}
index 94f6813463f364d252a41d4343cedb32ee084e07..77fac219bdd79ed2ecca1fd634af9e76c5ca5935 100644 (file)
@@ -52,7 +52,8 @@ public:
     memc(NULL),
     rc(rc_arg),
     _is_server(false),
-    _end(false)
+    _end(false),
+    _has_hash(false)
   {
     _hostname[0]= 0;
     buf= option_string;
@@ -75,6 +76,8 @@ public:
     _end= true;
   }
 
+  bool set_hash(memcached_hash_t hash);
+
   void set_server()
   {
     _is_server= true;
@@ -85,14 +88,14 @@ public:
     _is_server= false;
   }
 
-  bool is_server()
+  bool is_server() const
   {
     return _is_server;
   }
 
   const char *set_hostname(const char *str, size_t size);
 
-  const char *hostname()
+  const char *hostname() const
   {
     return _hostname;
   }
@@ -122,4 +125,5 @@ private:
   bool _is_server;
   bool _end;
   char _hostname[NI_MAXHOST];
+  bool _has_hash;
 }; 
index 855b6fdd8b2c50bbf9f387de2c341ea59c078aa1..a9fb743a9d853128b3b9bd15afcde555f5ac869c 100644 (file)
@@ -541,12 +541,12 @@ static const yytype_int8 yyrhs[] =
 static const yytype_uint16 yyrline[] =
 {
        0,   172,   172,   173,   177,   179,   181,   183,   188,   193,
-     197,   201,   212,   220,   228,   235,   239,   243,   247,   251,
-     263,   270,   281,   288,   295,   302,   308,   312,   316,   320,
-     324,   328,   332,   336,   340,   344,   348,   352,   359,   363,
-     367,   371,   375,   379,   383,   387,   391,   395,   399,   403,
-     410,   411,   416,   417,   422,   426,   430,   434,   438,   442,
-     446,   450,   454,   461,   465,   472,   476,   480
+     197,   201,   212,   222,   232,   241,   245,   249,   253,   257,
+     269,   282,   295,   302,   309,   318,   324,   328,   332,   336,
+     340,   344,   348,   352,   356,   360,   364,   368,   375,   379,
+     383,   387,   391,   395,   399,   403,   407,   411,   415,   419,
+     426,   427,   432,   433,   438,   442,   446,   450,   454,   458,
+     462,   466,   470,   477,   481,   488,   492,   496
 };
 #endif
 
@@ -1591,7 +1591,7 @@ yyreduce:
 #line 189 "libmemcached/csl/parser.yy"
     {
             context->rc= MEMCACHED_PARSE_USER_ERROR;
-            parser_abort(context, NULL);
+            parser_abort(context, "ERROR called directly");
           }
     break;
 
@@ -1620,7 +1620,7 @@ yyreduce:
     {
             if ((context->rc= memcached_parse_configure_file(*context->memc, (yyvsp[(3) - (3)].string).c_str, (yyvsp[(3) - (3)].string).size)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "Failed to parse configuration file");
             }
           }
     break;
@@ -1632,7 +1632,9 @@ yyreduce:
     {
             if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, (yyvsp[(2) - (4)].server).c_str, (yyvsp[(3) - (4)].number), (yyvsp[(4) - (4)].number))))
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", (yyvsp[(2) - (4)].server).c_str, uint32_t((yyvsp[(3) - (4)].number)));
+              parser_abort(context, buffer);
             }
             context->unset_server();
           }
@@ -1641,11 +1643,13 @@ yyreduce:
   case 13:
 
 /* Line 1806 of yacc.c  */
-#line 221 "libmemcached/csl/parser.yy"
+#line 223 "libmemcached/csl/parser.yy"
     {
             if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, (yyvsp[(2) - (4)].server).c_str, (yyvsp[(3) - (4)].number), (yyvsp[(4) - (4)].number))))
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", (yyvsp[(2) - (4)].server).c_str, uint32_t((yyvsp[(3) - (4)].number)));
+              parser_abort(context, buffer);
             }
             context->unset_server();
           }
@@ -1654,11 +1658,13 @@ yyreduce:
   case 14:
 
 /* Line 1806 of yacc.c  */
-#line 229 "libmemcached/csl/parser.yy"
+#line 233 "libmemcached/csl/parser.yy"
     {
             if (memcached_failed(context->rc= memcached_server_add_unix_socket_with_weight(context->memc, (yyvsp[(2) - (3)].string).c_str, (yyvsp[(3) - (3)].number))))
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Failed to add server: %s", (yyvsp[(2) - (3)].string).c_str);
+              parser_abort(context, buffer);
             }
           }
     break;
@@ -1666,7 +1672,7 @@ yyreduce:
   case 15:
 
 /* Line 1806 of yacc.c  */
-#line 236 "libmemcached/csl/parser.yy"
+#line 242 "libmemcached/csl/parser.yy"
     {
             memcached_set_configuration_file(context->memc, (yyvsp[(2) - (2)].string).c_str, (yyvsp[(2) - (2)].string).size);
           }
@@ -1675,7 +1681,7 @@ yyreduce:
   case 16:
 
 /* Line 1806 of yacc.c  */
-#line 240 "libmemcached/csl/parser.yy"
+#line 246 "libmemcached/csl/parser.yy"
     {
             context->memc->configure.initial_pool_size= (yyvsp[(2) - (2)].number);
           }
@@ -1684,7 +1690,7 @@ yyreduce:
   case 17:
 
 /* Line 1806 of yacc.c  */
-#line 244 "libmemcached/csl/parser.yy"
+#line 250 "libmemcached/csl/parser.yy"
     {
             context->memc->configure.max_pool_size= (yyvsp[(2) - (2)].number);
           }
@@ -1693,7 +1699,7 @@ yyreduce:
   case 19:
 
 /* Line 1806 of yacc.c  */
-#line 252 "libmemcached/csl/parser.yy"
+#line 258 "libmemcached/csl/parser.yy"
     {
             if (memcached_callback_get(context->memc, MEMCACHED_CALLBACK_PREFIX_KEY, NULL))
             {
@@ -1710,8 +1716,14 @@ yyreduce:
   case 20:
 
 /* Line 1806 of yacc.c  */
-#line 264 "libmemcached/csl/parser.yy"
+#line 270 "libmemcached/csl/parser.yy"
     {
+            // Check to see if DISTRIBUTION has already been set
+            if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (2)].distribution))) != MEMCACHED_SUCCESS)
+            {
+              parser_abort(context, "--DISTRIBUTION can only be called once");
+            }
+
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (2)].distribution))) != MEMCACHED_SUCCESS)
             {
               parser_abort(context, memcached_last_error_message(context->memc));;
@@ -1722,15 +1734,17 @@ yyreduce:
   case 21:
 
 /* Line 1806 of yacc.c  */
-#line 271 "libmemcached/csl/parser.yy"
+#line 283 "libmemcached/csl/parser.yy"
     {
+            // Check to see if DISTRIBUTION has already been set
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, (yyvsp[(2) - (4)].distribution))) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "--DISTRIBUTION can only be called once");
             }
+
             if ((context->rc= memcached_behavior_set_distribution_hash(context->memc, (yyvsp[(4) - (4)].hash))) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "Unable to set the hash for the DISTRIBUTION requested");
             }
           }
     break;
@@ -1738,11 +1752,11 @@ yyreduce:
   case 22:
 
 /* Line 1806 of yacc.c  */
-#line 282 "libmemcached/csl/parser.yy"
+#line 296 "libmemcached/csl/parser.yy"
     {
-            if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_HASH, (yyvsp[(2) - (2)].hash))) != MEMCACHED_SUCCESS)
+            if (context->set_hash((yyvsp[(2) - (2)].hash)) == false)
             {
-              parser_abort(context, NULL); 
+              parser_abort(context, "--HASH can only be set once");
             }
           }
     break;
@@ -1750,11 +1764,11 @@ yyreduce:
   case 23:
 
 /* Line 1806 of yacc.c  */
-#line 289 "libmemcached/csl/parser.yy"
+#line 303 "libmemcached/csl/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, (yyvsp[(1) - (2)].behavior), (yyvsp[(2) - (2)].number))) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "Unable to set behavior");
             }
           }
     break;
@@ -1762,11 +1776,13 @@ yyreduce:
   case 24:
 
 /* Line 1806 of yacc.c  */
-#line 296 "libmemcached/csl/parser.yy"
+#line 310 "libmemcached/csl/parser.yy"
     {
             if ((context->rc= memcached_behavior_set(context->memc, (yyvsp[(1) - (1)].behavior), true)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Could not set: %s", libmemcached_string_behavior((yyvsp[(1) - (1)].behavior)));
+              parser_abort(context, buffer);
             }
           }
     break;
@@ -1774,7 +1790,7 @@ yyreduce:
   case 25:
 
 /* Line 1806 of yacc.c  */
-#line 303 "libmemcached/csl/parser.yy"
+#line 319 "libmemcached/csl/parser.yy"
     {
           }
     break;
@@ -1782,7 +1798,7 @@ yyreduce:
   case 26:
 
 /* Line 1806 of yacc.c  */
-#line 309 "libmemcached/csl/parser.yy"
+#line 325 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS;
           }
@@ -1791,7 +1807,7 @@ yyreduce:
   case 27:
 
 /* Line 1806 of yacc.c  */
-#line 313 "libmemcached/csl/parser.yy"
+#line 329 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT;
           }
@@ -1800,7 +1816,7 @@ yyreduce:
   case 28:
 
 /* Line 1806 of yacc.c  */
-#line 317 "libmemcached/csl/parser.yy"
+#line 333 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK;
           }
@@ -1809,7 +1825,7 @@ yyreduce:
   case 29:
 
 /* Line 1806 of yacc.c  */
-#line 321 "libmemcached/csl/parser.yy"
+#line 337 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK;
           }
@@ -1818,7 +1834,7 @@ yyreduce:
   case 30:
 
 /* Line 1806 of yacc.c  */
-#line 325 "libmemcached/csl/parser.yy"
+#line 341 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH;
           }
@@ -1827,7 +1843,7 @@ yyreduce:
   case 31:
 
 /* Line 1806 of yacc.c  */
-#line 329 "libmemcached/csl/parser.yy"
+#line 345 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS;
           }
@@ -1836,7 +1852,7 @@ yyreduce:
   case 32:
 
 /* Line 1806 of yacc.c  */
-#line 333 "libmemcached/csl/parser.yy"
+#line 349 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_POLL_TIMEOUT;
           }
@@ -1845,7 +1861,7 @@ yyreduce:
   case 33:
 
 /* Line 1806 of yacc.c  */
-#line 337 "libmemcached/csl/parser.yy"
+#line 353 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_RCV_TIMEOUT;
           }
@@ -1854,7 +1870,7 @@ yyreduce:
   case 34:
 
 /* Line 1806 of yacc.c  */
-#line 341 "libmemcached/csl/parser.yy"
+#line 357 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_RETRY_TIMEOUT;
           }
@@ -1863,7 +1879,7 @@ yyreduce:
   case 35:
 
 /* Line 1806 of yacc.c  */
-#line 345 "libmemcached/csl/parser.yy"
+#line 361 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SND_TIMEOUT;
           }
@@ -1872,7 +1888,7 @@ yyreduce:
   case 36:
 
 /* Line 1806 of yacc.c  */
-#line 349 "libmemcached/csl/parser.yy"
+#line 365 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE;
           }
@@ -1881,7 +1897,7 @@ yyreduce:
   case 37:
 
 /* Line 1806 of yacc.c  */
-#line 353 "libmemcached/csl/parser.yy"
+#line 369 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE;
           }
@@ -1890,7 +1906,7 @@ yyreduce:
   case 38:
 
 /* Line 1806 of yacc.c  */
-#line 360 "libmemcached/csl/parser.yy"
+#line 376 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_BINARY_PROTOCOL;
           }
@@ -1899,7 +1915,7 @@ yyreduce:
   case 39:
 
 /* Line 1806 of yacc.c  */
-#line 364 "libmemcached/csl/parser.yy"
+#line 380 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_BUFFER_REQUESTS;
           }
@@ -1908,7 +1924,7 @@ yyreduce:
   case 40:
 
 /* Line 1806 of yacc.c  */
-#line 368 "libmemcached/csl/parser.yy"
+#line 384 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY;
           }
@@ -1917,7 +1933,7 @@ yyreduce:
   case 41:
 
 /* Line 1806 of yacc.c  */
-#line 372 "libmemcached/csl/parser.yy"
+#line 388 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_NOREPLY;
           }
@@ -1926,7 +1942,7 @@ yyreduce:
   case 42:
 
 /* Line 1806 of yacc.c  */
-#line 376 "libmemcached/csl/parser.yy"
+#line 392 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ;
           }
@@ -1935,7 +1951,7 @@ yyreduce:
   case 43:
 
 /* Line 1806 of yacc.c  */
-#line 380 "libmemcached/csl/parser.yy"
+#line 396 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SORT_HOSTS;
           }
@@ -1944,7 +1960,7 @@ yyreduce:
   case 44:
 
 /* Line 1806 of yacc.c  */
-#line 384 "libmemcached/csl/parser.yy"
+#line 400 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_SUPPORT_CAS;
           }
@@ -1953,7 +1969,7 @@ yyreduce:
   case 45:
 
 /* Line 1806 of yacc.c  */
-#line 388 "libmemcached/csl/parser.yy"
+#line 404 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_NODELAY;
           }
@@ -1962,7 +1978,7 @@ yyreduce:
   case 46:
 
 /* Line 1806 of yacc.c  */
-#line 392 "libmemcached/csl/parser.yy"
+#line 408 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_KEEPALIVE;
           }
@@ -1971,7 +1987,7 @@ yyreduce:
   case 47:
 
 /* Line 1806 of yacc.c  */
-#line 396 "libmemcached/csl/parser.yy"
+#line 412 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_TCP_KEEPIDLE;
           }
@@ -1980,7 +1996,7 @@ yyreduce:
   case 48:
 
 /* Line 1806 of yacc.c  */
-#line 400 "libmemcached/csl/parser.yy"
+#line 416 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_USE_UDP;
           }
@@ -1989,7 +2005,7 @@ yyreduce:
   case 49:
 
 /* Line 1806 of yacc.c  */
-#line 404 "libmemcached/csl/parser.yy"
+#line 420 "libmemcached/csl/parser.yy"
     {
             (yyval.behavior)= MEMCACHED_BEHAVIOR_VERIFY_KEY;
           }
@@ -1998,35 +2014,35 @@ yyreduce:
   case 50:
 
 /* Line 1806 of yacc.c  */
-#line 410 "libmemcached/csl/parser.yy"
+#line 426 "libmemcached/csl/parser.yy"
     { (yyval.number)= MEMCACHED_DEFAULT_PORT;}
     break;
 
   case 51:
 
 /* Line 1806 of yacc.c  */
-#line 412 "libmemcached/csl/parser.yy"
+#line 428 "libmemcached/csl/parser.yy"
     { }
     break;
 
   case 52:
 
 /* Line 1806 of yacc.c  */
-#line 416 "libmemcached/csl/parser.yy"
+#line 432 "libmemcached/csl/parser.yy"
     { (yyval.number)= 1; }
     break;
 
   case 53:
 
 /* Line 1806 of yacc.c  */
-#line 418 "libmemcached/csl/parser.yy"
+#line 434 "libmemcached/csl/parser.yy"
     { }
     break;
 
   case 54:
 
 /* Line 1806 of yacc.c  */
-#line 423 "libmemcached/csl/parser.yy"
+#line 439 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_MD5;
           }
@@ -2035,7 +2051,7 @@ yyreduce:
   case 55:
 
 /* Line 1806 of yacc.c  */
-#line 427 "libmemcached/csl/parser.yy"
+#line 443 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_CRC;
           }
@@ -2044,7 +2060,7 @@ yyreduce:
   case 56:
 
 /* Line 1806 of yacc.c  */
-#line 431 "libmemcached/csl/parser.yy"
+#line 447 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1_64;
           }
@@ -2053,7 +2069,7 @@ yyreduce:
   case 57:
 
 /* Line 1806 of yacc.c  */
-#line 435 "libmemcached/csl/parser.yy"
+#line 451 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1A_64;
           }
@@ -2062,7 +2078,7 @@ yyreduce:
   case 58:
 
 /* Line 1806 of yacc.c  */
-#line 439 "libmemcached/csl/parser.yy"
+#line 455 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1_32;
           }
@@ -2071,7 +2087,7 @@ yyreduce:
   case 59:
 
 /* Line 1806 of yacc.c  */
-#line 443 "libmemcached/csl/parser.yy"
+#line 459 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_FNV1A_32;
           }
@@ -2080,7 +2096,7 @@ yyreduce:
   case 60:
 
 /* Line 1806 of yacc.c  */
-#line 447 "libmemcached/csl/parser.yy"
+#line 463 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_HSIEH;
           }
@@ -2089,7 +2105,7 @@ yyreduce:
   case 61:
 
 /* Line 1806 of yacc.c  */
-#line 451 "libmemcached/csl/parser.yy"
+#line 467 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_MURMUR;
           }
@@ -2098,7 +2114,7 @@ yyreduce:
   case 62:
 
 /* Line 1806 of yacc.c  */
-#line 455 "libmemcached/csl/parser.yy"
+#line 471 "libmemcached/csl/parser.yy"
     {
             (yyval.hash)= MEMCACHED_HASH_JENKINS;
           }
@@ -2107,7 +2123,7 @@ yyreduce:
   case 63:
 
 /* Line 1806 of yacc.c  */
-#line 462 "libmemcached/csl/parser.yy"
+#line 478 "libmemcached/csl/parser.yy"
     {
             (yyval.string)= (yyvsp[(1) - (1)].string);
           }
@@ -2116,7 +2132,7 @@ yyreduce:
   case 64:
 
 /* Line 1806 of yacc.c  */
-#line 466 "libmemcached/csl/parser.yy"
+#line 482 "libmemcached/csl/parser.yy"
     {
             (yyval.string)= (yyvsp[(1) - (1)].string);
           }
@@ -2125,7 +2141,7 @@ yyreduce:
   case 65:
 
 /* Line 1806 of yacc.c  */
-#line 473 "libmemcached/csl/parser.yy"
+#line 489 "libmemcached/csl/parser.yy"
     {
             (yyval.distribution)= MEMCACHED_DISTRIBUTION_CONSISTENT;
           }
@@ -2134,7 +2150,7 @@ yyreduce:
   case 66:
 
 /* Line 1806 of yacc.c  */
-#line 477 "libmemcached/csl/parser.yy"
+#line 493 "libmemcached/csl/parser.yy"
     {
             (yyval.distribution)= MEMCACHED_DISTRIBUTION_MODULA;
           }
@@ -2143,7 +2159,7 @@ yyreduce:
   case 67:
 
 /* Line 1806 of yacc.c  */
-#line 481 "libmemcached/csl/parser.yy"
+#line 497 "libmemcached/csl/parser.yy"
     {
             (yyval.distribution)= MEMCACHED_DISTRIBUTION_RANDOM;
           }
@@ -2152,7 +2168,7 @@ yyreduce:
 
 
 /* Line 1806 of yacc.c  */
-#line 2156 "libmemcached/csl/parser.cc"
+#line 2172 "libmemcached/csl/parser.cc"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -2383,7 +2399,7 @@ yyreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 486 "libmemcached/csl/parser.yy"
+#line 502 "libmemcached/csl/parser.yy"
  
 
 void Context::start() 
index 332d323e823b9c915568c1afd91326f0432d52e4..48d4d4e925ee2fc457f7c9cebbf9d364cbe03115 100644 (file)
@@ -188,7 +188,7 @@ statement:
         | ERROR
           {
             context->rc= MEMCACHED_PARSE_USER_ERROR;
-            parser_abort(context, NULL);
+            parser_abort(context, "ERROR called directly");
           }
         | RESET
           {
@@ -202,7 +202,7 @@ statement:
           {
             if ((context->rc= memcached_parse_configure_file(*context->memc, $3.c_str, $3.size)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "Failed to parse configuration file");
             }
           }
         ;
@@ -213,7 +213,9 @@ expression:
           {
             if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, $2.c_str, $3, $4)))
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", $2.c_str, uint32_t($3));
+              parser_abort(context, buffer);
             }
             context->unset_server();
           }
@@ -221,7 +223,9 @@ expression:
           {
             if (memcached_failed(context->rc= memcached_server_add_with_weight(context->memc, $2.c_str, $3, $4)))
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Failed to add server: %s:%u", $2.c_str, uint32_t($3));
+              parser_abort(context, buffer);
             }
             context->unset_server();
           }
@@ -229,7 +233,9 @@ expression:
           {
             if (memcached_failed(context->rc= memcached_server_add_unix_socket_with_weight(context->memc, $2.c_str, $3)))
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Failed to add server: %s", $2.c_str);
+              parser_abort(context, buffer);
             }
           }
         | CONFIGURE_FILE string
@@ -262,6 +268,12 @@ behaviors:
           }
         | DISTRIBUTION distribution
           {
+            // Check to see if DISTRIBUTION has already been set
+            if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
+            {
+              parser_abort(context, "--DISTRIBUTION can only be called once");
+            }
+
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
             {
               parser_abort(context, memcached_last_error_message(context->memc));;
@@ -269,34 +281,38 @@ behaviors:
           }
         | DISTRIBUTION distribution ',' hash
           {
+            // Check to see if DISTRIBUTION has already been set
             if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_DISTRIBUTION, $2)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "--DISTRIBUTION can only be called once");
             }
+
             if ((context->rc= memcached_behavior_set_distribution_hash(context->memc, $4)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "Unable to set the hash for the DISTRIBUTION requested");
             }
           }
         | HASH hash
           {
-            if ((context->rc= memcached_behavior_set(context->memc, MEMCACHED_BEHAVIOR_HASH, $2)) != MEMCACHED_SUCCESS)
+            if (context->set_hash($2) == false)
             {
-              parser_abort(context, NULL); 
+              parser_abort(context, "--HASH can only be set once");
             }
           }
         | behavior_number NUMBER
           {
             if ((context->rc= memcached_behavior_set(context->memc, $1, $2)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              parser_abort(context, "Unable to set behavior");
             }
           }
         | behavior_boolean
           {
             if ((context->rc= memcached_behavior_set(context->memc, $1, true)) != MEMCACHED_SUCCESS)
             {
-              parser_abort(context, NULL);
+              char buffer[1024];
+              snprintf(buffer, sizeof(buffer), "Could not set: %s", libmemcached_string_behavior($1));
+              parser_abort(context, buffer);
             }
           }
         |  USER_DATA
index e09b8a67348ee9711777688f26277f44b5989635..0da3de330d7a06db80b005131ba7dbfb457a3465 100644 (file)
@@ -22,6 +22,7 @@ noinst_HEADERS+= \
                 libmemcached/byteorder.h \
                 libmemcached/common.h \
                 libmemcached/continuum.hpp \
+                libmemcached/close_socket.hpp \
                 libmemcached/do.hpp \
                 libmemcached/error.hpp \
                 libmemcached/initialize_query.h \
index 8642c18755b8f13c0b1959e89a44418c47a0ff57..85e5ed42b82460a69d6c6b364b0af682ed189919 100644 (file)
@@ -268,16 +268,23 @@ static memcached_return_t io_wait(memcached_server_write_instance_st ptr,
         {
           int err;
           socklen_t len= sizeof (err);
-          (void)getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len);
-          memcached_set_errno(*ptr, (err == 0) ? get_socket_errno() : err, MEMCACHED_AT);
+          if (getsockopt(ptr->fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0)
+          {
+            if (err == 0)
+            {
+              continue;
+            }
+            errno= err;
+          }
         }
         else
         {
           memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
         }
+        int local_errno= get_socket_errno(); // We cache in case memcached_quit_server() modifies errno
         memcached_quit_server(ptr, true);
 
-        return memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
+        return memcached_set_errno(*ptr, local_errno, MEMCACHED_AT);
       }
     }
   }
index 398e7ee2d238153804181a22be2bbb0c829b6fc7..2e3e7c6d2072691daa0b3eecdb9fd81728128870 100644 (file)
@@ -45,6 +45,7 @@
 #include <libmemcachedprotocol-0.0/handler.h>
 #include <libmemcachedprotocol/cache.h>
 #include <libmemcached/byteorder.h>
+#include <libmemcached/close_socket.hpp>
 
 /*
  * I don't really need the following two functions as function pointers
index 8c3d50c151f21406cfcaf06a4b2a3284344a964b..c79fef26182088ba1722f2897ce146f41b97cf90 100644 (file)
@@ -25,6 +25,7 @@
 #include "util/string.hpp"
 
 #define test_literal_param util_literal_param
+#define test_literal_compare_param util_literal_compare_param
 #define test_literal_param_size util_literal_param_size
 #define test_string_make_from_cstr util_string_make_from_cstr
 #define test_array_length util_array_length
index 7936a524826818b009cbbe5e6ac67b7506071203..09000c36f56ddd19af86f28c17fe4eb51ccbe466 100644 (file)
@@ -249,7 +249,17 @@ static test_return_t _runner_default(libmemcached_test_callback_fn func, libmemc
   {
     test_true(container);
     test_true(container->memc);
-    return func(container->memc);
+    test_return_t ret;
+    try {
+      ret= func(container->memc);
+    }
+    catch (std::exception& e)
+    {
+      Error << e.what();
+      return TEST_FAILURE;
+    }
+
+    return ret;
   }
 
   return TEST_SUCCESS;
index d514c45f55ff0f78634d420474ed564417eea02c..92ee95476fd6216b47c42fc816077f5ffeea2d55 100644 (file)
@@ -223,7 +223,9 @@ scanner_variable_t hash_strings[]= {
   { ARRAY,  make_scanner_string("--HASH=CRC"), scanner_string_null, NULL },
   { ARRAY,  make_scanner_string("--HASH=FNV1A_32"), scanner_string_null, NULL },
   { ARRAY,  make_scanner_string("--HASH=FNV1_32"), scanner_string_null, NULL },
+#if 0
   { ARRAY,  make_scanner_string("--HASH=JENKINS"), scanner_string_null, NULL },
+#endif
   { ARRAY,  make_scanner_string("--HASH=MD5"), scanner_string_null, NULL },
   { NIL, scanner_string_null, scanner_string_null, NULL}
 };
@@ -234,10 +236,10 @@ static test_return_t _test_option(scanner_variable_t *scanner, bool test_true_op
   for (scanner_variable_t *ptr= scanner; ptr->type != NIL; ptr++)
   {
     memcached_st *memc= memcached(ptr->option.c_str, ptr->option.size);
-    
-    // The case that it should have parsed, but it didn't. We will inspect
-    // for an error with libmemcached_check_configuration()
-    if (not memc and test_true_opt)
+
+    // The case that it should have parsed, but it didn't. We will inspect for
+    // an error with libmemcached_check_configuration()
+    if (memc == NULL and test_true_opt)
     {
       char buffer[2048];
       bool success= libmemcached_check_configuration(ptr->option.c_str, ptr->option.size, buffer, sizeof(buffer));
@@ -246,6 +248,7 @@ static test_return_t _test_option(scanner_variable_t *scanner, bool test_true_op
       temp+= " with option string:";
       temp+= ptr->option.c_str;
       test_true_got(success, temp.c_str());
+      Error << "Failed for " << temp;
 
       return TEST_FAILURE; // The line above should fail since memc should be null
     }
@@ -333,11 +336,9 @@ test_return_t test_namespace_keyword(memcached_st*)
 
 test_return_t memcached_create_with_options_with_filename(memcached_st*)
 {
-  if (access(SUPPORT_EXAMPLE_CNF, R_OK))
-    return TEST_SKIPPED;
+  test_skip(0, access(SUPPORT_EXAMPLE_CNF, R_OK));
 
-  memcached_st *memc_ptr;
-  memc_ptr= memcached(test_literal_param("--CONFIGURE-FILE=\"support/example.cnf\""));
+  memcached_st *memc_ptr= memcached(test_literal_param("--CONFIGURE-FILE=\"support/example.cnf\""));
   test_true_got(memc_ptr, "memcached() failed");
   memcached_free(memc_ptr);
 
@@ -346,56 +347,58 @@ test_return_t memcached_create_with_options_with_filename(memcached_st*)
 
 test_return_t libmemcached_check_configuration_with_filename_test(memcached_st*)
 {
-  if (access(SUPPORT_EXAMPLE_CNF, R_OK))
-    return TEST_SKIPPED;
+  test_skip(0, access(SUPPORT_EXAMPLE_CNF, R_OK));
 
-  memcached_return_t rc;
   char buffer[BUFSIZ];
 
-  rc= libmemcached_check_configuration(test_literal_param("--CONFIGURE-FILE=\"support/example.cnf\""), buffer, sizeof(buffer));
-  test_true_got(rc == MEMCACHED_SUCCESS, (rc == MEMCACHED_ERRNO) ? strerror(errno) : memcached_strerror(NULL, rc));
+  test_compare_hint(MEMCACHED_SUCCESS,
+                    libmemcached_check_configuration(test_literal_param("--CONFIGURE-FILE=\"support/example.cnf\""), buffer, sizeof(buffer)),
+                    buffer);
 
-  rc= libmemcached_check_configuration(test_literal_param("--CONFIGURE-FILE=support/example.cnf"), buffer, sizeof(buffer));
-  test_false_with(rc == MEMCACHED_SUCCESS, memcached_strerror(NULL, rc));
+  test_compare_hint(MEMCACHED_SUCCESS,
+                    libmemcached_check_configuration(test_literal_param("--CONFIGURE-FILE=support/example.cnf"), buffer, sizeof(buffer)),
+                    buffer);
 
-  rc= libmemcached_check_configuration(test_literal_param("--CONFIGURE-FILE=\"bad-path/example.cnf\""), buffer, sizeof(buffer));
-  test_true_got(rc == MEMCACHED_ERRNO, memcached_strerror(NULL, rc));
+  test_compare_hint(MEMCACHED_ERRNO,
+                    libmemcached_check_configuration(test_literal_param("--CONFIGURE-FILE=\"bad-path/example.cnf\""), buffer, sizeof(buffer)),
+                    buffer) ;
 
   return TEST_SUCCESS;
 }
 
 test_return_t libmemcached_check_configuration_test(memcached_st*)
 {
-  memcached_return_t rc;
   char buffer[BUFSIZ];
-
   test_compare(MEMCACHED_SUCCESS,
                libmemcached_check_configuration(test_literal_param("--server=localhost"), buffer, sizeof(buffer)));
 
-  rc= libmemcached_check_configuration(test_literal_param("--dude=localhost"), buffer, sizeof(buffer));
-  test_false_with(rc == MEMCACHED_SUCCESS, buffer);
-  test_true(rc == MEMCACHED_PARSE_ERROR);
+  test_compare_hint(MEMCACHED_PARSE_ERROR,
+                    libmemcached_check_configuration(test_literal_param("--dude=localhost"), buffer, sizeof(buffer)),
+                    buffer);
 
   return TEST_SUCCESS;
 }
 
 test_return_t memcached_create_with_options_test(memcached_st*)
 {
-  memcached_st *memc_ptr;
-  memc_ptr= memcached(test_literal_param("--server=localhost"));
-  test_true_got(memc_ptr, memcached_last_error_message(memc_ptr));
-  memcached_free(memc_ptr);
+  {
+    memcached_st *memc_ptr;
+    memc_ptr= memcached(test_literal_param("--server=localhost"));
+    test_true_got(memc_ptr, memcached_last_error_message(memc_ptr));
+    memcached_free(memc_ptr);
+  }
 
-  memc_ptr= memcached(test_literal_param("--dude=localhost"));
-  test_false_with(memc_ptr, memcached_last_error_message(memc_ptr));
+  {
+    memcached_st *memc_ptr= memcached(test_literal_param("--dude=localhost"));
+    test_false_with(memc_ptr, memcached_last_error_message(memc_ptr));
+  }
 
   return TEST_SUCCESS;
 }
 
 test_return_t test_include_keyword(memcached_st*)
 {
-  if (access(SUPPORT_EXAMPLE_CNF, R_OK))
-    return TEST_SKIPPED;
+  test_skip(0, access(SUPPORT_EXAMPLE_CNF, R_OK));
 
   char buffer[BUFSIZ];
   test_compare(MEMCACHED_SUCCESS, 
@@ -432,7 +435,7 @@ test_return_t test_error_keyword(memcached_st*)
   return TEST_SUCCESS;
 }
 
-#define RANDOM_STRINGS 100
+#define RANDOM_STRINGS 1000
 test_return_t random_statement_build_test(memcached_st*)
 {
   std::vector<scanner_string_st *> option_list;
@@ -455,7 +458,26 @@ test_return_t random_statement_build_test(memcached_st*)
   for (scanner_variable_t *ptr= hash_strings; ptr->type != NIL; ptr++)
     option_list.push_back(&ptr->option);
 
-  bool seen_namespace= false;
+  std::vector<bool> used_list;
+  used_list.resize(option_list.size());
+
+  struct used_options_st {
+    bool has_hash;
+    bool has_namespace;
+    bool has_distribution;
+    bool has_buffer_requests;
+    bool has_udp;
+
+    used_options_st() :
+      has_hash(false),
+      has_namespace(false),
+      has_distribution(false),
+      has_buffer_requests(false),
+      has_udp(false)
+    {
+    }
+  } used_options;
+
   for (uint32_t x= 0; x < RANDOM_STRINGS; x++)
   {
     std::string random_options;
@@ -463,17 +485,79 @@ test_return_t random_statement_build_test(memcached_st*)
     uint32_t number_of= random() % option_list.size();
     for (uint32_t options= 0; options < number_of; options++)
     {
-      std::string random_string= option_list[random() % option_list.size()]->c_str;
-      bool is_namespace= memcmp(random_string.c_str(), test_literal_param("--NAMESPACE")) == 0;
+      size_t option_list_position= random() % option_list.size();
 
-      if (is_namespace and seen_namespace)
+      if (used_list[option_list_position])
       {
         continue;
       }
+      used_list[option_list_position]= true;
+
+      std::string random_string= option_list[option_list_position]->c_str;
+
+      if (random_string.compare(0, test_literal_compare_param("--HASH")) == 0)
+      {
+        if (used_options.has_hash)
+        {
+          continue;
+        }
+
+        if (used_options.has_distribution)
+        {
+          continue;
+        }
+        used_options.has_hash= true;
+      }
+
+      if (random_string.compare(0, test_literal_compare_param("--NAMESPACE")) == 0)
+      {
+        if (used_options.has_namespace)
+        {
+          continue;
+        }
+        used_options.has_namespace= true;
+      }
 
-      if (is_namespace)
+      if (random_string.compare(0, test_literal_compare_param("--USE-UDP")) == 0)
       {
-        seen_namespace= true;
+        if (used_options.has_udp)
+        {
+          continue;
+        }
+        used_options.has_udp= true;
+
+        if (used_options.has_buffer_requests)
+        {
+          continue;
+        }
+      }
+
+      if (random_string.compare(0, test_literal_compare_param("--BUFFER-REQUESTS")) == 0)
+      {
+        if (used_options.has_buffer_requests)
+        {
+          continue;
+        }
+        used_options.has_buffer_requests= true;
+
+        if (used_options.has_udp)
+        {
+          continue;
+        }
+      }
+
+      if (random_string.compare(0, test_literal_compare_param("--DISTRIBUTION")) == 0)
+      {
+        if (used_options.has_distribution)
+        {
+          continue;
+        }
+
+        if (used_options.has_hash)
+        {
+          continue;
+        }
+        used_options.has_distribution= true;
       }
 
       random_options+= random_string;
@@ -485,9 +569,10 @@ test_return_t random_statement_build_test(memcached_st*)
       continue;
     }
 
-    char buffer[BUFSIZ];
-    memcached_return_t rc= libmemcached_check_configuration(random_options.c_str(), random_options.size() -1, buffer, sizeof(buffer));
+    random_options.resize(random_options.size() -1);
 
+    char buffer[BUFSIZ];
+    memcached_return_t rc= libmemcached_check_configuration(random_options.c_str(), random_options.size(), buffer, sizeof(buffer));
     if (memcached_failed(rc))
     {
       Error << "libmemcached_check_configuration(" << random_options << ") : " << buffer;
index 58d0ce270945fb8b11fbbf4f157e340eca80e5a2..873551e5f39539e278cc6c5c658b4db7eb50f57b 100644 (file)
@@ -47,6 +47,8 @@
 #define util_literal_param(X) (X), (static_cast<size_t>((sizeof(X) - 1)))
 #define util_literal_param_size(X) static_cast<size_t>(sizeof(X) - 1)
 
+#define util_literal_compare_param(X) (static_cast<size_t>((sizeof(X) - 1))), (X)
+
 #define util_string_make_from_cstr(X) (X), ((X) ? strlen(X) : 0)
 
 #define util_array_length(__array) sizeof(__array)/sizeof(&__array)