]> git.saurik.com Git - redis.git/commitdiff
Merge branch 'issue327' into unstable
authorantirez <antirez@gmail.com>
Thu, 16 Feb 2012 08:40:27 +0000 (09:40 +0100)
committerantirez <antirez@gmail.com>
Thu, 16 Feb 2012 08:40:27 +0000 (09:40 +0100)
19 files changed:
00-RELEASENOTES [new file with mode: 0644]
INSTALL
MANIFESTO [new file with mode: 0644]
deps/lua/src/Makefile
deps/lua/src/lua_struct.c [new file with mode: 0644]
runtest
src/MANIFESTO [deleted file]
src/Makefile
src/ae.c
src/debug.c
src/endian.c [deleted file]
src/endian.h [deleted file]
src/endianconv.c [new file with mode: 0644]
src/endianconv.h [new file with mode: 0644]
src/intset.c
src/redis-check-aof.c
src/scripting.c
src/ziplist.c
src/zipmap.c

diff --git a/00-RELEASENOTES b/00-RELEASENOTES
new file mode 100644 (file)
index 0000000..49221f2
--- /dev/null
@@ -0,0 +1,79 @@
+Redis 2.6 release notes
+
+Migrating from 2.4 to 2.6
+=========================
+
+Redis 2.4 is mostly a strict subset of 2.6. However there are a few things
+that you should be aware of:
+
+* You can't use .rdb and AOF files generated with 2.6 into a 2.4 instance.
+* 2.4 slaves can be attached to 2.6 masters, but not the contrary, and only
+  for the time needed to perform the version upgrade.
+
+There are also a few API differences, that are unlikely to cause problems,
+but it is better to keep them in mind:
+
+* SORT now will refuse to sort in numerical mode elements that can't be parsed
+  as numbers.
+* EXPIREs now all have millisecond resolution (but this is very unlikely to
+  break code that was not conceived exploting the previous resolution error
+  in some way.)
+* INFO output is a bit different now, and contains empty lines and comments
+  starting with '#'. All the major clients should be already fixed to work
+  with the new INFO format.
+
+---------
+CHANGELOG
+---------
+
+What's new in Redis 2.6.0
+=========================
+
+UPGRADE URGENCY: We suggest new users to start with 2.6.0, and old users to
+                 upgrade after some testing of the application with the new
+                 Redis version.
+
+* Server side Lua scripting, see http://redis.io/commands/eval
+* Virtual Memory removed (was deprecated in 2.4)
+* Hardcoded limits about max number of clients removed.
+* AOF low level semantics is generally more sane, and especially when used
+  in slaves.
+* Milliseconds resolution expires, also added new commands with milliseconds
+  precision (PEXPIRE, PTTL, ...).
+* Clinets max output buffer soft and hard limits. You can specifiy different
+  limits for different classes of clients (normal,pubsub,slave).
+* AOF is now able to rewrite aggregate data types using variadic commands,
+  often producing an AOF that is faster to save, load, and is smaller in size.
+* Every redis.conf directive is now accepted as a command line option for the
+  redis-server binary, with the same name and number of arguments.
+* Hash table seed randomization for protection against collisions attacks.
+* Performances improved when writing large objects to Redis.
+* Significant parts of the core refactored or rewritten. New internal APIs
+  and core changes allowed to develop Redis Cluster on top of the new code,
+  however for 2.6 all the cluster code was removed, and will be released with
+  Redis 3.0 when it is more complete and stable.
+* Redis ASCII art logo added at startup.
+* Crash report on memory violation or failed asserts improved significantly
+  to make debugging of hard to catch bugs simpler.
+* redis-benchmark improvements: ability to run selected tests,
+  CSV output, faster, better help.
+* redis-cli improvements: --eval for comfortable development of Lua scripts.
+* SHUTDOWN now supports two optional arguments: "SAVE" and "NOSAVE".
+* INFO output split into sections, the command is now able to just show 
+  pecific sections.
+* New statistics about how many time a command was called, and how much
+  execution time it used (INFO commandstats).
+* More predictable SORT behavior in edge cases.
+* INCRBYFLOAT and HINCRBYFLOAT commands.
+
+--------------------------------------------------------------------------------
+
+Credits: Where not specified the implementation and design are done by
+Salvatore Sanfilippo and Pieter Noordhuis. Thanks to VMware for making all
+this possible. Also many thanks to all the other contributors and the amazing
+community we have.
+
+See commit messages for more credits.
+
+Cheers,
+Salvatore
diff --git a/INSTALL b/INSTALL
index 2b9fc4a82fd2128d13d3d4a0b55f06f836cb9bf6..3083f1afd50c34e1139ab1577510a17e968b0ed4 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,30 +1 @@
-To compile Redis, do the following:
-
-    cd src; make
-
-The compilation will produce a redis-server binary.
-
-To install Redis, use
-
-    make install
-
-and all the binaries will be installed on /usr/local/bin.
-
-Alternatively:
-
-    make PREFIX=/some/other/directory install
-
-to have the binaries in /some/other/directory/bin.
-
-Run the server using the following command line:
-
-    /path/to/redis-server
-
-This will start a Redis server with the default configuration.
-
-Otherwise if you want to provide your configuration use:
-
-    /path/to/redis-server /path/to/redis.conf
-
-You can find an example redis.conf file in the root directory
-of this source distribution.
+See README
diff --git a/MANIFESTO b/MANIFESTO
new file mode 100644 (file)
index 0000000..ad94fd8
--- /dev/null
+++ b/MANIFESTO
@@ -0,0 +1,20 @@
+[Note: this is the Redis manifesto, for general information about
+       installing and running Redis read the README file instead.]
+
+Redis Manifesto
+===============
+
+1 - A DSL for Abstract Data Types. Redis is a DSL (Domain Specific Language) that manipulates abstract data types and implemented as a TCP daemon. Commands manipulate a key space where keys are binary-safe strings and values are different kinds of abstract data types. Every data type represents an abstract version of a fundamental data structure. For instance Redis Lists are an abstract representation of linked lists. In Redis, the essence of a data type isn't just the kind of operations that the data types support, but also the space and time complexity of the data type and the operations performed upon it.
+
+2 - Memory storage is #1. The Redis data set, composed of defined key-value pairs, is primarily stored in the computer's memory. The amount of memory in all kinds of computers, including entry-level servers, is increasing significantly each year. Memory is fast, and allows Redis to have very predictable performance.  Datasets composed of 10k or 40 millions keys will perform similarly.  Complex data types like Redis Sorted Sets are easy to implement and manipulate in memory with good performance, making Redis very simple.  Redis will continue to explore alternative options (where data can be optionally stored on disk, say) but the main goal of the project remains the development of an in-memory database.
+
+3 - Fundamental data structures for a fundamental API. The Redis API is a direct consequence of fundamental data structures. APIs can often be arbitrary but not an API that resembles the nature of fundamental data structures. If we ever meet intelligent life forms from another part of the universe, they'll likely know, understand and recognize the same basic data structures we have in our computer science books. Redis will avoid intermediate layers in API, so that the complexity is obvious and more complex operations can be performed as the sum of the basic operations.
+
+4 - Code is like a poem; it's not just something we write to reach some practical result.  Sometimes people that are far from the Redis philosophy suggest using other  code written by other authors (frequently in other languages) in order to implement something Redis currently lacks. But to us this is like if Shakespeare decided to end Enrico IV using the Paradiso from the Divina Commedia. Is using any external code a bad idea? Not at all. Like in "One Thousand and One Nights" smaller self contained stories are embedded in a bigger story, we'll be happy to use beautiful self contained libraries when needed. At the same time, when writing the Redis story we're trying to write smaller stories that will fit in to other code.
+
+5 - We're against complexity. We believe designing systems is a fight against complexity. We'll accept to fight the complexity when it's worthwhile but we'll try hard to recognize when a small feature is not worth 1000s of lines of code. Most of the time the best way to fight complexity is by not creating it at all.
+
+6 - Two levels of API. The Redis API has two levels: 1) a subset of the API fits naturally into a distributed version of Redis and 2) a more complex API that supports multi-key operations. Both are useful if used judiciously but there's no way to make the more complex multi-keys API distributed in an opaque way without violating our other principles. We don't want to provide the illusion of something that will work magically when actually it can't in all cases. Instead we'll provide commands to quickly migrate keys from one instance to another to perform multi-key operations and expose the tradeoffs to the user.
+
+7 - We optimize for joy. We believe writing code is a lot of hard work, and the only way it can be worth is by enjoying it.  When there is no longer joy in writing code, the best thing to do is stop. To prevent this, we'll avoid taking paths that will make Redis less of a joy to develop.
+
index ff6661607a0b8490e423f7fb7782cfb0b9c5197e..6caed7419bc3b3c38cdcc4c80aaca0cc9c88f409 100644 (file)
@@ -27,7 +27,7 @@ CORE_O=       lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
        lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o  \
        lundump.o lvm.o lzio.o strbuf.o
 LIB_O= lauxlib.o lbaselib.o ldblib.o liolib.o lmathlib.o loslib.o ltablib.o \
-       lstrlib.o loadlib.o linit.o lua_cjson.o
+       lstrlib.o loadlib.o linit.o lua_cjson.o lua_struct.o
 
 LUA_T= lua
 LUA_O= lua.o
diff --git a/deps/lua/src/lua_struct.c b/deps/lua/src/lua_struct.c
new file mode 100644 (file)
index 0000000..6807c83
--- /dev/null
@@ -0,0 +1,354 @@
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+
+
+#include "lua.h"
+#include "lauxlib.h"
+
+
+/*
+** {======================================================
+** Library for packing/unpacking structures.
+** $Id: struct.c,v 1.2 2008/04/18 20:06:01 roberto Exp $
+** See Copyright Notice at the end of this file
+** =======================================================
+*/
+/*
+** Valid formats:
+** > - big endian
+** < - little endian
+** ![num] - alignment
+** x - pading
+** b/B - signed/unsigned byte
+** h/H - signed/unsigned short
+** l/L - signed/unsigned long
+** i/In - signed/unsigned integer with size `n' (default is size of int)
+** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
+        the whole string; when unpacking, n==0 means use the previous
+        read number as the string length
+** s - zero-terminated string
+** f - float
+** d - double
+** ' ' - ignored
+*/
+
+
+/* is 'x' a power of 2? */
+#define isp2(x)                ((x) > 0 && ((x) & ((x) - 1)) == 0)
+
+/* dummy structure to get alignment requirements */
+struct cD {
+  char c;
+  double d;
+};
+
+
+#define PADDING                (sizeof(struct cD) - sizeof(double))
+#define MAXALIGN       (PADDING > sizeof(int) ? PADDING : sizeof(int))
+
+
+/* endian options */
+#define BIG    0
+#define LITTLE 1
+
+
+static union {
+  int dummy;
+  char endian;
+} const native = {1};
+
+
+typedef struct Header {
+  int endian;
+  int align;
+} Header;
+
+
+static size_t getnum (const char **fmt, size_t df) {
+  if (!isdigit(**fmt))  /* no number? */
+    return df;  /* return default value */
+  else {
+    size_t a = 0;
+    do {
+      a = a*10 + *((*fmt)++) - '0';
+    } while (isdigit(**fmt));
+    return a;
+  }
+}
+
+
+#define defaultoptions(h)      ((h)->endian = native.endian, (h)->align = 1)
+
+
+
+static size_t optsize (lua_State *L, char opt, const char **fmt) {
+  switch (opt) {
+    case 'B': case 'b': return sizeof(char);
+    case 'H': case 'h': return sizeof(short);
+    case 'L': case 'l': return sizeof(long);
+    case 'f':  return sizeof(float);
+    case 'd':  return sizeof(double);
+    case 'x': return 1;
+    case 'c': return getnum(fmt, 1);
+    case 's': case ' ': case '<': case '>': case '!': return 0;
+    case 'i': case 'I': {
+      int sz = getnum(fmt, sizeof(int));
+      if (!isp2(sz))
+        luaL_error(L, "integral size %d is not a power of 2", sz);
+      return sz;
+    }
+    default: {
+      const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt);
+      return luaL_argerror(L, 1, msg);
+    }
+  }
+}
+
+
+static int gettoalign (size_t len, Header *h, int opt, size_t size) {
+  if (size == 0 || opt == 'c') return 0;
+  if (size > (size_t)h->align) size = h->align;  /* respect max. alignment */
+  return  (size - (len & (size - 1))) & (size - 1);
+}
+
+
+static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) {
+  switch (opt) {
+    case  ' ': return;  /* ignore white spaces */
+    case '>': h->endian = BIG; return;
+    case '<': h->endian = LITTLE; return;
+    case '!': {
+      int a = getnum(fmt, MAXALIGN);
+      if (!isp2(a))
+        luaL_error(L, "alignment %d is not a power of 2", a);
+      h->align = a;
+      return;
+    }
+    default: assert(0);
+  }
+}
+
+
+static void putinteger (lua_State *L, luaL_Buffer *b, int arg, int endian,
+                        int size) {
+  lua_Number n = luaL_checknumber(L, arg);
+  unsigned long value;
+  if (n < (lua_Number)LONG_MAX)
+    value = (long)n;
+  else
+    value = (unsigned long)n;
+  if (endian == LITTLE) {
+    int i;
+    for (i = 0; i < size; i++)
+      luaL_addchar(b, (value >> 8*i) & 0xff);
+  }
+  else {
+    int i;
+    for (i = size - 1; i >= 0; i--)
+      luaL_addchar(b, (value >> 8*i) & 0xff);
+  }
+}
+
+
+static void correctbytes (char *b, int size, int endian) {
+  if (endian != native.endian) {
+    int i = 0;
+    while (i < --size) {
+      char temp = b[i];
+      b[i++] = b[size];
+      b[size] = temp;
+    }
+  }
+}
+
+
+static int b_pack (lua_State *L) {
+  luaL_Buffer b;
+  const char *fmt = luaL_checkstring(L, 1);
+  Header h;
+  int arg = 2;
+  size_t totalsize = 0;
+  defaultoptions(&h);
+  lua_pushnil(L);  /* mark to separate arguments from string buffer */
+  luaL_buffinit(L, &b);
+  while (*fmt != '\0') {
+    int opt = *fmt++;
+    size_t size = optsize(L, opt, &fmt);
+    int toalign = gettoalign(totalsize, &h, opt, size);
+    totalsize += toalign;
+    while (toalign-- > 0) luaL_putchar(&b, '\0');
+    switch (opt) {
+      case 'b': case 'B': case 'h': case 'H':
+      case 'l': case 'L': case 'i': case 'I': {  /* integer types */
+        putinteger(L, &b, arg++, h.endian, size);
+        break;
+      }
+      case 'x': {
+        luaL_putchar(&b, '\0');
+        break;
+      }
+      case 'f': {
+        float f = (float)luaL_checknumber(L, arg++);
+        correctbytes((char *)&f, size, h.endian);
+        luaL_addlstring(&b, (char *)&f, size);
+        break;
+      }
+      case 'd': {
+        double d = luaL_checknumber(L, arg++);
+        correctbytes((char *)&d, size, h.endian);
+        luaL_addlstring(&b, (char *)&d, size);
+        break;
+      }
+      case 'c': case 's': {
+        size_t l;
+        const char *s = luaL_checklstring(L, arg++, &l);
+        if (size == 0) size = l;
+        luaL_argcheck(L, l >= (size_t)size, arg, "string too short");
+        luaL_addlstring(&b, s, size);
+        if (opt == 's') {
+          luaL_putchar(&b, '\0');  /* add zero at the end */
+          size++;
+        }
+        break;
+      }
+      default: commoncases(L, opt, &fmt, &h);
+    }
+    totalsize += size;
+  }
+  luaL_pushresult(&b);
+  return 1;
+}
+
+
+static lua_Number getinteger (const char *buff, int endian,
+                        int issigned, int size) {
+  unsigned long l = 0;
+  if (endian == BIG) {
+    int i;
+    for (i = 0; i < size; i++)
+      l |= (unsigned long)(unsigned char)buff[size - i - 1] << (i*8);
+  }
+  else {
+    int i;
+    for (i = 0; i < size; i++)
+      l |= (unsigned long)(unsigned char)buff[i] << (i*8);
+  }
+  if (!issigned)
+    return (lua_Number)l;
+  else {  /* signed format */
+    unsigned long mask = ~(0UL) << (size*8 - 1);
+    if (l & mask)  /* negative value? */
+      l |= mask;  /* signal extension */
+    return (lua_Number)(long)l;
+  }
+}
+
+
+static int b_unpack (lua_State *L) {
+  Header h;
+  const char *fmt = luaL_checkstring(L, 1);
+  size_t ld;
+  const char *data = luaL_checklstring(L, 2, &ld);
+  size_t pos = luaL_optinteger(L, 3, 1) - 1;
+  defaultoptions(&h);
+  lua_settop(L, 2);
+  while (*fmt) {
+    int opt = *fmt++;
+    size_t size = optsize(L, opt, &fmt);
+    pos += gettoalign(pos, &h, opt, size);
+    luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
+    switch (opt) {
+      case 'b': case 'B': case 'h': case 'H':
+      case 'l': case 'L': case 'i':  case 'I': {  /* integer types */
+        int issigned = islower(opt);
+        lua_Number res = getinteger(data+pos, h.endian, issigned, size);
+        lua_pushnumber(L, res);
+        break;
+      }
+      case 'x': {
+        break;
+      }
+      case 'f': {
+        float f;
+        memcpy(&f, data+pos, size);
+        correctbytes((char *)&f, sizeof(f), h.endian);
+        lua_pushnumber(L, f);
+        break;
+      }
+      case 'd': {
+        double d;
+        memcpy(&d, data+pos, size);
+        correctbytes((char *)&d, sizeof(d), h.endian);
+        lua_pushnumber(L, d);
+        break;
+      }
+      case 'c': {
+        if (size == 0) {
+          if (!lua_isnumber(L, -1))
+            luaL_error(L, "format `c0' needs a previous size");
+          size = lua_tonumber(L, -1);
+          lua_pop(L, 1);
+          luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
+        }
+        lua_pushlstring(L, data+pos, size);
+        break;
+      }
+      case 's': {
+        const char *e = (const char *)memchr(data+pos, '\0', ld - pos);
+        if (e == NULL)
+          luaL_error(L, "unfinished string in data");
+        size = (e - (data+pos)) + 1;
+        lua_pushlstring(L, data+pos, size - 1);
+        break;
+      }
+      default: commoncases(L, opt, &fmt, &h);
+    }
+    pos += size;
+  }
+  lua_pushinteger(L, pos + 1);
+  return lua_gettop(L) - 2;
+}
+
+/* }====================================================== */
+
+
+
+static const struct luaL_reg thislib[] = {
+  {"pack", b_pack},
+  {"unpack", b_unpack},
+  {NULL, NULL}
+};
+
+
+LUALIB_API int luaopen_struct (lua_State *L) {
+  luaL_register(L, "struct", thislib);
+  return 1;
+}
+
+
+
+/******************************************************************************
+* Copyright (C) 2010 Lua.org, PUC-Rio.  All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to deal in the Software without restriction, including
+* without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to
+* permit persons to whom the Software is furnished to do so, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+******************************************************************************/
diff --git a/runtest b/runtest
index 2ea4d39bec5db0e27f186be42357f25127528b8e..0eb384c24dc47df446dd8da3960dbbaaf284a863 100755 (executable)
--- a/runtest
+++ b/runtest
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 TCL=tclsh8.5
 which $TCL
 if [ "$?" != "0" ]
diff --git a/src/MANIFESTO b/src/MANIFESTO
deleted file mode 100644 (file)
index ad94fd8..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-[Note: this is the Redis manifesto, for general information about
-       installing and running Redis read the README file instead.]
-
-Redis Manifesto
-===============
-
-1 - A DSL for Abstract Data Types. Redis is a DSL (Domain Specific Language) that manipulates abstract data types and implemented as a TCP daemon. Commands manipulate a key space where keys are binary-safe strings and values are different kinds of abstract data types. Every data type represents an abstract version of a fundamental data structure. For instance Redis Lists are an abstract representation of linked lists. In Redis, the essence of a data type isn't just the kind of operations that the data types support, but also the space and time complexity of the data type and the operations performed upon it.
-
-2 - Memory storage is #1. The Redis data set, composed of defined key-value pairs, is primarily stored in the computer's memory. The amount of memory in all kinds of computers, including entry-level servers, is increasing significantly each year. Memory is fast, and allows Redis to have very predictable performance.  Datasets composed of 10k or 40 millions keys will perform similarly.  Complex data types like Redis Sorted Sets are easy to implement and manipulate in memory with good performance, making Redis very simple.  Redis will continue to explore alternative options (where data can be optionally stored on disk, say) but the main goal of the project remains the development of an in-memory database.
-
-3 - Fundamental data structures for a fundamental API. The Redis API is a direct consequence of fundamental data structures. APIs can often be arbitrary but not an API that resembles the nature of fundamental data structures. If we ever meet intelligent life forms from another part of the universe, they'll likely know, understand and recognize the same basic data structures we have in our computer science books. Redis will avoid intermediate layers in API, so that the complexity is obvious and more complex operations can be performed as the sum of the basic operations.
-
-4 - Code is like a poem; it's not just something we write to reach some practical result.  Sometimes people that are far from the Redis philosophy suggest using other  code written by other authors (frequently in other languages) in order to implement something Redis currently lacks. But to us this is like if Shakespeare decided to end Enrico IV using the Paradiso from the Divina Commedia. Is using any external code a bad idea? Not at all. Like in "One Thousand and One Nights" smaller self contained stories are embedded in a bigger story, we'll be happy to use beautiful self contained libraries when needed. At the same time, when writing the Redis story we're trying to write smaller stories that will fit in to other code.
-
-5 - We're against complexity. We believe designing systems is a fight against complexity. We'll accept to fight the complexity when it's worthwhile but we'll try hard to recognize when a small feature is not worth 1000s of lines of code. Most of the time the best way to fight complexity is by not creating it at all.
-
-6 - Two levels of API. The Redis API has two levels: 1) a subset of the API fits naturally into a distributed version of Redis and 2) a more complex API that supports multi-key operations. Both are useful if used judiciously but there's no way to make the more complex multi-keys API distributed in an opaque way without violating our other principles. We don't want to provide the illusion of something that will work magically when actually it can't in all cases. Instead we'll provide commands to quickly migrate keys from one instance to another to perform multi-key operations and expose the tradeoffs to the user.
-
-7 - We optimize for joy. We believe writing code is a lot of hard work, and the only way it can be worth is by enjoying it.  When there is no longer joy in writing code, the best thing to do is stop. To prevent this, we'll avoid taking paths that will make Redis less of a joy to develop.
-
index 659d1d7fa34fd3692169b3fb26a73a6105fab24b..cca785cbc2f238401e05738362e571e888a98c05 100644 (file)
@@ -59,7 +59,7 @@ CCOPT= $(CFLAGS) $(ARCH) $(PROF)
 
 PREFIX= /usr/local
 INSTALL_BIN= $(PREFIX)/bin
-INSTALL= cp -p
+INSTALL= cp -pf
 
 CCCOLOR="\033[34m"
 LINKCOLOR="\033[34;1m"
@@ -73,7 +73,7 @@ QUIET_CC = @printf '    %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR
 QUIET_LINK = @printf '    %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR);
 endif
 
-OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endian.o slowlog.o scripting.o bio.o rio.o rand.o
+OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o
 BENCHOBJ = ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
 CLIOBJ = anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o
 CHECKDUMPOBJ = redis-check-dump.o lzf_c.o lzf_d.o
@@ -112,8 +112,8 @@ db.o: db.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
 debug.o: debug.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
   zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h sha1.h
 dict.o: dict.c fmacros.h dict.h zmalloc.h
-endian.o: endian.c
-intset.o: intset.c intset.h zmalloc.h endian.h
+endianconv.o: endianconv.c
+intset.o: intset.c intset.h zmalloc.h endianconv.h
 lzf_c.o: lzf_c.c lzfP.h
 lzf_d.o: lzf_d.c lzfP.h
 multi.o: multi.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
@@ -163,8 +163,8 @@ t_string.o: t_string.c redis.h fmacros.h config.h ae.h sds.h dict.h \
 t_zset.o: t_zset.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h \
   zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
 util.o: util.c fmacros.h util.h
-ziplist.o: ziplist.c zmalloc.h util.h ziplist.h endian.h
-zipmap.o: zipmap.c zmalloc.h endian.h
+ziplist.o: ziplist.c zmalloc.h util.h ziplist.h endianconv.h
+zipmap.o: zipmap.c zmalloc.h endianconv.h
 zmalloc.o: zmalloc.c config.h zmalloc.h
 
 # Clean local objects when ARCH is different
@@ -175,7 +175,7 @@ else
 endif
 
 .make-arch:
-       -(cd ../deps && make $(DEPENDENCY_TARGETS) ARCH="$(ARCH)")
+       -(cd ../deps && $(MAKE) $(DEPENDENCY_TARGETS) ARCH="$(ARCH)")
        -(echo $(ARCH) > .make-arch)
 
 # Clean local objects when allocator changes
index 4c8aff9b0011034baaa5513a9d6bf3e234c2e162..4099b12598f4ea2a740590a86d44f30b183bb948 100644 (file)
--- a/src/ae.c
+++ b/src/ae.c
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "ae.h"
 #include "zmalloc.h"
index 54920032fd891262edec0fdacb8f0ac381366b7f..fe21531ba51ad35a673871d4ba7835bda58a9f3e 100644 (file)
@@ -389,6 +389,14 @@ void _redisPanic(char *msg, char *file, int line) {
 #endif
 }
 
+void bugReportStart(void) {
+    if (server.bug_report_start == 0) {
+        redisLog(REDIS_WARNING,
+            "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===");
+        server.bug_report_start = 1;
+    }
+}
+
 #ifdef HAVE_BACKTRACE
 static void *getMcontextEip(ucontext_t *uc) {
 #if defined(__FreeBSD__)
@@ -420,14 +428,6 @@ static void *getMcontextEip(ucontext_t *uc) {
 #endif
 }
 
-void bugReportStart(void) {
-    if (server.bug_report_start == 0) {
-        redisLog(REDIS_WARNING,
-            "\n\n=== REDIS BUG REPORT START: Cut & paste starting from here ===");
-        server.bug_report_start = 1;
-    }
-}
-
 void logStackContent(void **sp) {
     int i;
     for (i = 15; i >= 0; i--) {
diff --git a/src/endian.c b/src/endian.c
deleted file mode 100644 (file)
index aff2425..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Toggle the 16 bit unsigned integer pointed by *p from little endian to
- * big endian */
-void memrev16(void *p) {
-    unsigned char *x = p, t;
-
-    t = x[0];
-    x[0] = x[1];
-    x[1] = t;
-}
-
-/* Toggle the 32 bit unsigned integer pointed by *p from little endian to
- * big endian */
-void memrev32(void *p) {
-    unsigned char *x = p, t;
-
-    t = x[0];
-    x[0] = x[3];
-    x[3] = t;
-    t = x[1];
-    x[1] = x[2];
-    x[2] = t;
-}
-
-/* Toggle the 64 bit unsigned integer pointed by *p from little endian to
- * big endian */
-void memrev64(void *p) {
-    unsigned char *x = p, t;
-
-    t = x[0];
-    x[0] = x[7];
-    x[7] = t;
-    t = x[1];
-    x[1] = x[6];
-    x[6] = t;
-    t = x[2];
-    x[2] = x[5];
-    x[5] = t;
-    t = x[3];
-    x[3] = x[4];
-    x[4] = t;
-}
-
-#ifdef TESTMAIN
-#include <stdio.h>
-
-int main(void) {
-    char buf[32];
-
-    sprintf(buf,"ciaoroma");
-    memrev16(buf);
-    printf("%s\n", buf);
-
-    sprintf(buf,"ciaoroma");
-    memrev32(buf);
-    printf("%s\n", buf);
-
-    sprintf(buf,"ciaoroma");
-    memrev64(buf);
-    printf("%s\n", buf);
-
-    return 0;
-}
-#endif
diff --git a/src/endian.h b/src/endian.h
deleted file mode 100644 (file)
index bef8227..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __ENDIAN_H
-#define __ENDIAN_H
-
-void memrev16(void *p);
-void memrev32(void *p);
-void memrev64(void *p);
-
-/* variants of the function doing the actual convertion only if the target
- * host is big endian */
-#if (BYTE_ORDER == LITTLE_ENDIAN)
-#define memrev16ifbe(p)
-#define memrev32ifbe(p)
-#define memrev64ifbe(p)
-#else
-#define memrev16ifbe(p) memrev16(p)
-#define memrev32ifbe(p) memrev32(p)
-#define memrev64ifbe(p) memrev64(p)
-#endif
-
-#endif
diff --git a/src/endianconv.c b/src/endianconv.c
new file mode 100644 (file)
index 0000000..9adf09c
--- /dev/null
@@ -0,0 +1,124 @@
+/* endinconv.c -- Endian conversions utilities.
+ *
+ * This functions are never called directly, but always using the macros
+ * defined into endianconv.h, this way we define everything is a non-operation
+ * if the arch is already little endian.
+ *
+ * Redis tries to encode everything as little endian (but a few things that need
+ * to be backward compatible are still in big endian) because most of the
+ * production environments are little endian, and we have a lot of conversions
+ * in a few places because ziplists, intsets, zipmaps, need to be endian-neutral
+ * even in memory, since they are serialied on RDB files directly with a single
+ * write(2) without other additional steps.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (c) 2011-2012, Salvatore Sanfilippo <antirez at gmail dot com>
+ * 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.
+ *   * Neither the name of Redis nor the names of its contributors may 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.
+ */
+
+
+#include <stdint.h>
+
+/* Toggle the 16 bit unsigned integer pointed by *p from little endian to
+ * big endian */
+void memrev16(void *p) {
+    unsigned char *x = p, t;
+
+    t = x[0];
+    x[0] = x[1];
+    x[1] = t;
+}
+
+/* Toggle the 32 bit unsigned integer pointed by *p from little endian to
+ * big endian */
+void memrev32(void *p) {
+    unsigned char *x = p, t;
+
+    t = x[0];
+    x[0] = x[3];
+    x[3] = t;
+    t = x[1];
+    x[1] = x[2];
+    x[2] = t;
+}
+
+/* Toggle the 64 bit unsigned integer pointed by *p from little endian to
+ * big endian */
+void memrev64(void *p) {
+    unsigned char *x = p, t;
+
+    t = x[0];
+    x[0] = x[7];
+    x[7] = t;
+    t = x[1];
+    x[1] = x[6];
+    x[6] = t;
+    t = x[2];
+    x[2] = x[5];
+    x[5] = t;
+    t = x[3];
+    x[3] = x[4];
+    x[4] = t;
+}
+
+uint16_t intrev16(uint16_t v) {
+    memrev16(&v);
+    return v;
+}
+
+uint32_t intrev32(uint32_t v) {
+    memrev32(&v);
+    return v;
+}
+
+uint64_t intrev64(uint64_t v) {
+    memrev64(&v);
+    return v;
+}
+
+#ifdef TESTMAIN
+#include <stdio.h>
+
+int main(void) {
+    char buf[32];
+
+    sprintf(buf,"ciaoroma");
+    memrev16(buf);
+    printf("%s\n", buf);
+
+    sprintf(buf,"ciaoroma");
+    memrev32(buf);
+    printf("%s\n", buf);
+
+    sprintf(buf,"ciaoroma");
+    memrev64(buf);
+    printf("%s\n", buf);
+
+    return 0;
+}
+#endif
diff --git a/src/endianconv.h b/src/endianconv.h
new file mode 100644 (file)
index 0000000..f76e0e6
--- /dev/null
@@ -0,0 +1,63 @@
+/* See endianconv.c top comments for more information
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * Copyright (c) 2011-2012, Salvatore Sanfilippo <antirez at gmail dot com>
+ * 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.
+ *   * Neither the name of Redis nor the names of its contributors may 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.
+ */ 
+
+#ifndef __ENDIANCONV_H
+#define __ENDIANCONV_H
+
+#include <stdint.h>
+
+void memrev16(void *p);
+void memrev32(void *p);
+void memrev64(void *p);
+uint16_t intrev16(uint16_t v);
+uint32_t intrev32(uint32_t v);
+uint64_t intrev64(uint64_t v);
+
+/* variants of the function doing the actual convertion only if the target
+ * host is big endian */
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define memrev16ifbe(p)
+#define memrev32ifbe(p)
+#define memrev64ifbe(p)
+#define intrev16ifbe(v) (v)
+#define intrev32ifbe(v) (v)
+#define intrev64ifbe(v) (v)
+#else
+#define memrev16ifbe(p) memrev16(p)
+#define memrev32ifbe(p) memrev32(p)
+#define memrev64ifbe(p) memrev64(p)
+#define intrev16ifbe(v) intrev16(v)
+#define intrev32ifbe(v) intrev32(v)
+#define intrev64ifbe(v) intrev64(v)
+#endif
+
+#endif
index 4dd0141d852f85b401973e73c5aa77638afe3b6d..225f0e92aea1203d95140bffe79898cca07736e7 100644 (file)
@@ -3,7 +3,7 @@
 #include <string.h>
 #include "intset.h"
 #include "zmalloc.h"
-#include "endian.h"
+#include "endianconv.h"
 
 /* Note that these encodings are ordered, so:
  * INTSET_ENC_INT16 < INTSET_ENC_INT32 < INTSET_ENC_INT64. */
@@ -44,15 +44,17 @@ static int64_t _intsetGetEncoded(intset *is, int pos, uint8_t enc) {
 
 /* Return the value at pos, using the configured encoding. */
 static int64_t _intsetGet(intset *is, int pos) {
-    return _intsetGetEncoded(is,pos,is->encoding);
+    return _intsetGetEncoded(is,pos,intrev32ifbe(is->encoding));
 }
 
 /* Set the value at pos, using the configured encoding. */
 static void _intsetSet(intset *is, int pos, int64_t value) {
-    if (is->encoding == INTSET_ENC_INT64) {
+    uint32_t encoding = intrev32ifbe(is->encoding);
+
+    if (encoding == INTSET_ENC_INT64) {
         ((int64_t*)is->contents)[pos] = value;
         memrev64ifbe(((int64_t*)is->contents)+pos);
-    } else if (is->encoding == INTSET_ENC_INT32) {
+    } else if (encoding == INTSET_ENC_INT32) {
         ((int32_t*)is->contents)[pos] = value;
         memrev32ifbe(((int32_t*)is->contents)+pos);
     } else {
@@ -64,14 +66,14 @@ static void _intsetSet(intset *is, int pos, int64_t value) {
 /* Create an empty intset. */
 intset *intsetNew(void) {
     intset *is = zmalloc(sizeof(intset));
-    is->encoding = INTSET_ENC_INT16;
+    is->encoding = intrev32ifbe(INTSET_ENC_INT16);
     is->length = 0;
     return is;
 }
 
 /* Resize the intset */
 static intset *intsetResize(intset *is, uint32_t len) {
-    uint32_t size = len*is->encoding;
+    uint32_t size = len*intrev32ifbe(is->encoding);
     is = zrealloc(is,sizeof(intset)+size);
     return is;
 }
@@ -81,18 +83,18 @@ static intset *intsetResize(intset *is, uint32_t len) {
  * the value is not present in the intset and sets "pos" to the position
  * where "value" can be inserted. */
 static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
-    int min = 0, max = is->length-1, mid = -1;
+    int min = 0, max = intrev32ifbe(is->length)-1, mid = -1;
     int64_t cur = -1;
 
     /* The value can never be found when the set is empty */
-    if (is->length == 0) {
+    if (intrev32ifbe(is->length) == 0) {
         if (pos) *pos = 0;
         return 0;
     } else {
         /* Check for the case where we know we cannot find the value,
          * but do know the insert position. */
-        if (value > _intsetGet(is,is->length-1)) {
-            if (pos) *pos = is->length;
+        if (value > _intsetGet(is,intrev32ifbe(is->length)-1)) {
+            if (pos) *pos = intrev32ifbe(is->length);
             return 0;
         } else if (value < _intsetGet(is,0)) {
             if (pos) *pos = 0;
@@ -123,14 +125,14 @@ static uint8_t intsetSearch(intset *is, int64_t value, uint32_t *pos) {
 
 /* Upgrades the intset to a larger encoding and inserts the given integer. */
 static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
-    uint8_t curenc = is->encoding;
+    uint8_t curenc = intrev32ifbe(is->encoding);
     uint8_t newenc = _intsetValueEncoding(value);
-    int length = is->length;
+    int length = intrev32ifbe(is->length);
     int prepend = value < 0 ? 1 : 0;
 
     /* First set new encoding and resize */
-    is->encoding = newenc;
-    is = intsetResize(is,is->length+1);
+    is->encoding = intrev32ifbe(newenc);
+    is = intsetResize(is,intrev32ifbe(is->length)+1);
 
     /* Upgrade back-to-front so we don't overwrite values.
      * Note that the "prepend" variable is used to make sure we have an empty
@@ -142,19 +144,21 @@ static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {
     if (prepend)
         _intsetSet(is,0,value);
     else
-        _intsetSet(is,is->length,value);
-    is->length++;
+        _intsetSet(is,intrev32ifbe(is->length),value);
+    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
     return is;
 }
 
 static void intsetMoveTail(intset *is, uint32_t from, uint32_t to) {
     void *src, *dst;
-    uint32_t bytes = is->length-from;
-    if (is->encoding == INTSET_ENC_INT64) {
+    uint32_t bytes = intrev32ifbe(is->length)-from;
+    uint32_t encoding = intrev32ifbe(is->encoding);
+
+    if (encoding == INTSET_ENC_INT64) {
         src = (int64_t*)is->contents+from;
         dst = (int64_t*)is->contents+to;
         bytes *= sizeof(int64_t);
-    } else if (is->encoding == INTSET_ENC_INT32) {
+    } else if (encoding == INTSET_ENC_INT32) {
         src = (int32_t*)is->contents+from;
         dst = (int32_t*)is->contents+to;
         bytes *= sizeof(int32_t);
@@ -175,7 +179,7 @@ intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
     /* Upgrade encoding if necessary. If we need to upgrade, we know that
      * this value should be either appended (if > 0) or prepended (if < 0),
      * because it lies outside the range of existing values. */
-    if (valenc > is->encoding) {
+    if (valenc > intrev32ifbe(is->encoding)) {
         /* This always succeeds, so we don't need to curry *success. */
         return intsetUpgradeAndAdd(is,value);
     } else {
@@ -187,12 +191,12 @@ intset *intsetAdd(intset *is, int64_t value, uint8_t *success) {
             return is;
         }
 
-        is = intsetResize(is,is->length+1);
-        if (pos < is->length) intsetMoveTail(is,pos,pos+1);
+        is = intsetResize(is,intrev32ifbe(is->length)+1);
+        if (pos < intrev32ifbe(is->length)) intsetMoveTail(is,pos,pos+1);
     }
 
     _intsetSet(is,pos,value);
-    is->length++;
+    is->length = intrev32ifbe(intrev32ifbe(is->length)+1);
     return is;
 }
 
@@ -202,14 +206,16 @@ intset *intsetRemove(intset *is, int64_t value, int *success) {
     uint32_t pos;
     if (success) *success = 0;
 
-    if (valenc <= is->encoding && intsetSearch(is,value,&pos)) {
+    if (valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,&pos)) {
+        uint32_t len = intrev32ifbe(is->length);
+
         /* We know we can delete */
         if (success) *success = 1;
 
         /* Overwrite value with tail and update length */
-        if (pos < (is->length-1)) intsetMoveTail(is,pos+1,pos);
-        is = intsetResize(is,is->length-1);
-        is->length--;
+        if (pos < (len-1)) intsetMoveTail(is,pos+1,pos);
+        is = intsetResize(is,len-1);
+        is->length = intrev32ifbe(len-1);
     }
     return is;
 }
@@ -217,18 +223,18 @@ intset *intsetRemove(intset *is, int64_t value, int *success) {
 /* Determine whether a value belongs to this set */
 uint8_t intsetFind(intset *is, int64_t value) {
     uint8_t valenc = _intsetValueEncoding(value);
-    return valenc <= is->encoding && intsetSearch(is,value,NULL);
+    return valenc <= intrev32ifbe(is->encoding) && intsetSearch(is,value,NULL);
 }
 
 /* Return random member */
 int64_t intsetRandom(intset *is) {
-    return _intsetGet(is,rand()%is->length);
+    return _intsetGet(is,rand()%intrev32ifbe(is->length));
 }
 
 /* Sets the value to the value at the given position. When this position is
  * out of range the function returns 0, when in range it returns 1. */
 uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value) {
-    if (pos < is->length) {
+    if (pos < intrev32ifbe(is->length)) {
         *value = _intsetGet(is,pos);
         return 1;
     }
@@ -237,12 +243,12 @@ uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value) {
 
 /* Return intset length */
 uint32_t intsetLen(intset *is) {
-    return is->length;
+    return intrev32ifbe(is->length);
 }
 
 /* Return intset blob size in bytes. */
 size_t intsetBlobLen(intset *is) {
-    return sizeof(intset)+is->length*is->encoding;
+    return sizeof(intset)+intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
 }
 
 #ifdef INTSET_TEST_MAIN
@@ -250,7 +256,7 @@ size_t intsetBlobLen(intset *is) {
 
 void intsetRepr(intset *is) {
     int i;
-    for (i = 0; i < is->length; i++) {
+    for (i = 0; i < intrev32ifbe(is->length); i++) {
         printf("%lld\n", (uint64_t)_intsetGet(is,i));
     }
     printf("\n");
@@ -296,11 +302,13 @@ intset *createSet(int bits, int size) {
 void checkConsistency(intset *is) {
     int i;
 
-    for (i = 0; i < (is->length-1); i++) {
-        if (is->encoding == INTSET_ENC_INT16) {
+    for (i = 0; i < (intrev32ifbe(is->length)-1); i++) {
+        uint32_t encoding = intrev32ifbe(is->encoding);
+
+        if (encoding == INTSET_ENC_INT16) {
             int16_t *i16 = (int16_t*)is->contents;
             assert(i16[i] < i16[i+1]);
-        } else if (is->encoding == INTSET_ENC_INT32) {
+        } else if (encoding == INTSET_ENC_INT32) {
             int32_t *i32 = (int32_t*)is->contents;
             assert(i32[i] < i32[i+1]);
         } else {
@@ -346,7 +354,7 @@ int main(int argc, char **argv) {
             is = intsetAdd(is,rand()%0x800,&success);
             if (success) inserts++;
         }
-        assert(is->length == inserts);
+        assert(intrev32ifbe(is->length) == inserts);
         checkConsistency(is);
         ok();
     }
@@ -354,18 +362,18 @@ int main(int argc, char **argv) {
     printf("Upgrade from int16 to int32: "); {
         is = intsetNew();
         is = intsetAdd(is,32,NULL);
-        assert(is->encoding == INTSET_ENC_INT16);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
         is = intsetAdd(is,65535,NULL);
-        assert(is->encoding == INTSET_ENC_INT32);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
         assert(intsetFind(is,32));
         assert(intsetFind(is,65535));
         checkConsistency(is);
 
         is = intsetNew();
         is = intsetAdd(is,32,NULL);
-        assert(is->encoding == INTSET_ENC_INT16);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
         is = intsetAdd(is,-65535,NULL);
-        assert(is->encoding == INTSET_ENC_INT32);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
         assert(intsetFind(is,32));
         assert(intsetFind(is,-65535));
         checkConsistency(is);
@@ -375,18 +383,18 @@ int main(int argc, char **argv) {
     printf("Upgrade from int16 to int64: "); {
         is = intsetNew();
         is = intsetAdd(is,32,NULL);
-        assert(is->encoding == INTSET_ENC_INT16);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
         is = intsetAdd(is,4294967295,NULL);
-        assert(is->encoding == INTSET_ENC_INT64);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
         assert(intsetFind(is,32));
         assert(intsetFind(is,4294967295));
         checkConsistency(is);
 
         is = intsetNew();
         is = intsetAdd(is,32,NULL);
-        assert(is->encoding == INTSET_ENC_INT16);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT16);
         is = intsetAdd(is,-4294967295,NULL);
-        assert(is->encoding == INTSET_ENC_INT64);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
         assert(intsetFind(is,32));
         assert(intsetFind(is,-4294967295));
         checkConsistency(is);
@@ -396,18 +404,18 @@ int main(int argc, char **argv) {
     printf("Upgrade from int32 to int64: "); {
         is = intsetNew();
         is = intsetAdd(is,65535,NULL);
-        assert(is->encoding == INTSET_ENC_INT32);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
         is = intsetAdd(is,4294967295,NULL);
-        assert(is->encoding == INTSET_ENC_INT64);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
         assert(intsetFind(is,65535));
         assert(intsetFind(is,4294967295));
         checkConsistency(is);
 
         is = intsetNew();
         is = intsetAdd(is,65535,NULL);
-        assert(is->encoding == INTSET_ENC_INT32);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT32);
         is = intsetAdd(is,-4294967295,NULL);
-        assert(is->encoding == INTSET_ENC_INT64);
+        assert(intrev32ifbe(is->encoding) == INTSET_ENC_INT64);
         assert(intsetFind(is,65535));
         assert(intsetFind(is,-4294967295));
         checkConsistency(is);
index ff0d1f82cf8b5f8297839726790f7f7eb003e679..3762d05e25e6bfabdc724cdae8229d09dc9ee55d 100644 (file)
@@ -9,11 +9,11 @@
 #define ERROR(...) { \
     char __buf[1024]; \
     sprintf(__buf, __VA_ARGS__); \
-    sprintf(error, "0x%08lx: %s", epos, __buf); \
+    sprintf(error, "0x%16llx: %s", (long long)epos, __buf); \
 }
 
 static char error[1024];
-static long epos;
+static off_t epos;
 
 int consumeNewline(char *buf) {
     if (strncmp(buf,"\r\n",2) != 0) {
@@ -25,7 +25,7 @@ int consumeNewline(char *buf) {
 
 int readLong(FILE *fp, char prefix, long *target) {
     char buf[128], *eptr;
-    epos = ftell(fp);
+    epos = ftello(fp);
     if (fgets(buf,sizeof(buf),fp) == NULL) {
         return 0;
     }
@@ -39,7 +39,7 @@ int readLong(FILE *fp, char prefix, long *target) {
 
 int readBytes(FILE *fp, char *target, long length) {
     long real;
-    epos = ftell(fp);
+    epos = ftello(fp);
     real = fread(target,1,length,fp);
     if (real != length) {
         ERROR("Expected to read %ld bytes, got %ld bytes",length,real);
@@ -72,13 +72,14 @@ int readArgc(FILE *fp, long *target) {
     return readLong(fp,'*',target);
 }
 
-long process(FILE *fp) {
-    long argc, pos = 0;
+off_t process(FILE *fp) {
+    long argc;
+    off_t pos = 0;
     int i, multi = 0;
     char *str;
 
     while(1) {
-        if (!multi) pos = ftell(fp);
+        if (!multi) pos = ftello(fp);
         if (!readArgc(fp, &argc)) break;
 
         for (i = 0; i < argc; i++) {
@@ -148,18 +149,20 @@ int main(int argc, char **argv) {
         exit(1);
     }
 
-    long size = sb.st_size;
+    off_t size = sb.st_size;
     if (size == 0) {
         printf("Empty file: %s\n", filename);
         exit(1);
     }
 
-    long pos = process(fp);
-    long diff = size-pos;
+    off_t pos = process(fp);
+    off_t diff = size-pos;
+    printf("AOF analyzed: size=%lld, ok_up_to=%lld, diff=%lld\n",
+        (long long) size, (long long) pos, (long long) diff);
     if (diff > 0) {
         if (fix) {
             char buf[2];
-            printf("This will shrink the AOF from %ld bytes, with %ld bytes, to %ld bytes\n",size,diff,pos);
+            printf("This will shrink the AOF from %lld bytes, with %lld bytes, to %lld bytes\n",(long long)size,(long long)diff,(long long)pos);
             printf("Continue? [y/N]: ");
             if (fgets(buf,sizeof(buf),stdin) == NULL ||
                 strncasecmp(buf,"y",1) != 0) {
index 75788a3a5e25b50dd35ffc82187a85115108b484..9d41a45f22dc83d19cb967082f97005c8e19e227 100644 (file)
@@ -343,6 +343,7 @@ void luaLoadLib(lua_State *lua, const char *libname, lua_CFunction luafunc) {
 }
 
 LUALIB_API int (luaopen_cjson) (lua_State *L);
+LUALIB_API int (luaopen_struct) (lua_State *L);
 
 void luaLoadLibraries(lua_State *lua) {
     luaLoadLib(lua, "", luaopen_base);
@@ -350,7 +351,8 @@ void luaLoadLibraries(lua_State *lua) {
     luaLoadLib(lua, LUA_STRLIBNAME, luaopen_string);
     luaLoadLib(lua, LUA_MATHLIBNAME, luaopen_math);
     luaLoadLib(lua, LUA_DBLIBNAME, luaopen_debug); 
-    luaLoadLib(lua, "cjson", luaopen_cjson); 
+    luaLoadLib(lua, "cjson", luaopen_cjson);
+    luaLoadLib(lua, "struct", luaopen_struct);
 
 #if 0 /* Stuff that we don't load currently, for sandboxing concerns. */
     luaLoadLib(lua, LUA_LOADLIBNAME, luaopen_package);
index 639e4b61ec3cc9c0e5f742448ff19c3420e5d2be..4ecd1885d6217f5416ec4ff0de85dcb6232c09f8 100644 (file)
@@ -69,7 +69,7 @@
 #include "zmalloc.h"
 #include "util.h"
 #include "ziplist.h"
-#include "endian.h"
+#include "endianconv.h"
 
 #define ZIP_END 255
 #define ZIP_BIGLEN 254
 #define ZIPLIST_LENGTH(zl)      (*((uint16_t*)((zl)+sizeof(uint32_t)*2)))
 #define ZIPLIST_HEADER_SIZE     (sizeof(uint32_t)*2+sizeof(uint16_t))
 #define ZIPLIST_ENTRY_HEAD(zl)  ((zl)+ZIPLIST_HEADER_SIZE)
-#define ZIPLIST_ENTRY_TAIL(zl)  ((zl)+ZIPLIST_TAIL_OFFSET(zl))
-#define ZIPLIST_ENTRY_END(zl)   ((zl)+ZIPLIST_BYTES(zl)-1)
+#define ZIPLIST_ENTRY_TAIL(zl)  ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))
+#define ZIPLIST_ENTRY_END(zl)   ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
 
 /* We know a positive increment can only be 1 because entries can only be
  * pushed one at a time. */
 #define ZIPLIST_INCR_LENGTH(zl,incr) { \
-    if (ZIPLIST_LENGTH(zl) < UINT16_MAX) ZIPLIST_LENGTH(zl)+=incr; }
+    if (ZIPLIST_LENGTH(zl) < UINT16_MAX) \
+        ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \
+}
 
 typedef struct zlentry {
     unsigned int prevrawlensize, prevrawlen;
@@ -302,11 +304,11 @@ static int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) {
         ret = i16;
     } else if (encoding == ZIP_INT_32B) {
         memcpy(&i32,p,sizeof(i32));
-        memrev16ifbe(&i32);
+        memrev32ifbe(&i32);
         ret = i32;
     } else if (encoding == ZIP_INT_64B) {
         memcpy(&i64,p,sizeof(i64));
-        memrev16ifbe(&i64);
+        memrev64ifbe(&i64);
         ret = i64;
     } else {
         assert(NULL);
@@ -335,8 +337,8 @@ static unsigned int zipRawEntryLength(unsigned char *p) {
 unsigned char *ziplistNew(void) {
     unsigned int bytes = ZIPLIST_HEADER_SIZE+1;
     unsigned char *zl = zmalloc(bytes);
-    ZIPLIST_BYTES(zl) = bytes;
-    ZIPLIST_TAIL_OFFSET(zl) = ZIPLIST_HEADER_SIZE;
+    ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
+    ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
     ZIPLIST_LENGTH(zl) = 0;
     zl[bytes-1] = ZIP_END;
     return zl;
@@ -345,7 +347,7 @@ unsigned char *ziplistNew(void) {
 /* Resize the ziplist. */
 static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
     zl = zrealloc(zl,len);
-    ZIPLIST_BYTES(zl) = len;
+    ZIPLIST_BYTES(zl) = intrev32ifbe(len);
     zl[len-1] = ZIP_END;
     return zl;
 }
@@ -371,7 +373,7 @@ static unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
  * The pointer "p" points to the first entry that does NOT need to be
  * updated, i.e. consecutive fields MAY need an update. */
 static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p) {
-    size_t curlen = ZIPLIST_BYTES(zl), rawlen, rawlensize;
+    size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), rawlen, rawlensize;
     size_t offset, noffset, extra;
     unsigned char *np;
     zlentry cur, next;
@@ -401,8 +403,10 @@ static unsigned char *__ziplistCascadeUpdate(unsigned char *zl, unsigned char *p
             noffset = np-zl;
 
             /* Update tail offset when next element is not the tail element. */
-            if ((zl+ZIPLIST_TAIL_OFFSET(zl)) != np)
-                ZIPLIST_TAIL_OFFSET(zl) += extra;
+            if ((zl+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))) != np) {
+                ZIPLIST_TAIL_OFFSET(zl) =
+                    intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+extra);
+            }
 
             /* Move the tail to the back. */
             memmove(np+rawlensize,
@@ -453,25 +457,30 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig
             zipPrevEncodeLength(p-nextdiff,first.prevrawlen);
 
             /* Update offset for tail */
-            ZIPLIST_TAIL_OFFSET(zl) -= totlen;
+            ZIPLIST_TAIL_OFFSET(zl) =
+                intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))-totlen);
 
             /* When the tail contains more than one entry, we need to take
              * "nextdiff" in account as well. Otherwise, a change in the
              * size of prevlen doesn't have an effect on the *tail* offset. */
             tail = zipEntry(p);
-            if (p[tail.headersize+tail.len] != ZIP_END)
-                ZIPLIST_TAIL_OFFSET(zl) += nextdiff;
+            if (p[tail.headersize+tail.len] != ZIP_END) {
+                ZIPLIST_TAIL_OFFSET(zl) =
+                   intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+nextdiff);
+            }
 
             /* Move tail to the front of the ziplist */
-            memmove(first.p,p-nextdiff,ZIPLIST_BYTES(zl)-(p-zl)-1+nextdiff);
+            memmove(first.p,p-nextdiff,
+                intrev32ifbe(ZIPLIST_BYTES(zl))-(p-zl)-1+nextdiff);
         } else {
             /* The entire tail was deleted. No need to move memory. */
-            ZIPLIST_TAIL_OFFSET(zl) = (first.p-zl)-first.prevrawlen;
+            ZIPLIST_TAIL_OFFSET(zl) =
+                intrev32ifbe((first.p-zl)-first.prevrawlen);
         }
 
         /* Resize and update length */
         offset = first.p-zl;
-        zl = ziplistResize(zl, ZIPLIST_BYTES(zl)-totlen+nextdiff);
+        zl = ziplistResize(zl, intrev32ifbe(ZIPLIST_BYTES(zl))-totlen+nextdiff);
         ZIPLIST_INCR_LENGTH(zl,-deleted);
         p = zl+offset;
 
@@ -485,7 +494,7 @@ static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsig
 
 /* Insert item at "p". */
 static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
-    size_t curlen = ZIPLIST_BYTES(zl), reqlen, prevlen = 0;
+    size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen, prevlen = 0;
     size_t offset;
     int nextdiff = 0;
     unsigned char encoding = 0;
@@ -538,17 +547,20 @@ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsig
         zipPrevEncodeLength(p+reqlen,reqlen);
 
         /* Update offset for tail */
-        ZIPLIST_TAIL_OFFSET(zl) += reqlen;
+        ZIPLIST_TAIL_OFFSET(zl) =
+            intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+reqlen);
 
         /* When the tail contains more than one entry, we need to take
          * "nextdiff" in account as well. Otherwise, a change in the
          * size of prevlen doesn't have an effect on the *tail* offset. */
         tail = zipEntry(p+reqlen);
-        if (p[reqlen+tail.headersize+tail.len] != ZIP_END)
-            ZIPLIST_TAIL_OFFSET(zl) += nextdiff;
+        if (p[reqlen+tail.headersize+tail.len] != ZIP_END) {
+            ZIPLIST_TAIL_OFFSET(zl) =
+                intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+nextdiff);
+        }
     } else {
         /* This element will be the new tail. */
-        ZIPLIST_TAIL_OFFSET(zl) = p-zl;
+        ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(p-zl);
     }
 
     /* When nextdiff != 0, the raw length of the next entry has changed, so
@@ -720,8 +732,8 @@ unsigned int ziplistCompare(unsigned char *p, unsigned char *sstr, unsigned int
 /* Return length of ziplist. */
 unsigned int ziplistLen(unsigned char *zl) {
     unsigned int len = 0;
-    if (ZIPLIST_LENGTH(zl) < UINT16_MAX) {
-        len = ZIPLIST_LENGTH(zl);
+    if (intrev16ifbe(ZIPLIST_LENGTH(zl)) < UINT16_MAX) {
+        len = intrev16ifbe(ZIPLIST_LENGTH(zl));
     } else {
         unsigned char *p = zl+ZIPLIST_HEADER_SIZE;
         while (*p != ZIP_END) {
@@ -730,14 +742,14 @@ unsigned int ziplistLen(unsigned char *zl) {
         }
 
         /* Re-store length if small enough */
-        if (len < UINT16_MAX) ZIPLIST_LENGTH(zl) = len;
+        if (len < UINT16_MAX) ZIPLIST_LENGTH(zl) = intrev16ifbe(len);
     }
     return len;
 }
 
 /* Return ziplist blob size in bytes. */
 size_t ziplistBlobLen(unsigned char *zl) {
-    return ZIPLIST_BYTES(zl);
+    return intrev32ifbe(ZIPLIST_BYTES(zl));
 }
 
 void ziplistRepr(unsigned char *zl) {
@@ -749,9 +761,9 @@ void ziplistRepr(unsigned char *zl) {
         "{total bytes %d} "
         "{length %u}\n"
         "{tail offset %u}\n",
-        ZIPLIST_BYTES(zl),
-        ZIPLIST_LENGTH(zl),
-        ZIPLIST_TAIL_OFFSET(zl));
+        intrev32ifbe(ZIPLIST_BYTES(zl)),
+        intrev16ifbe(ZIPLIST_LENGTH(zl)),
+        intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)));
     p = ZIPLIST_ENTRY_HEAD(zl);
     while(*p != ZIP_END) {
         entry = zipEntry(p);
@@ -852,7 +864,7 @@ void stress(int pos, int num, int maxsize, int dnum) {
             zl = ziplistDeleteRange(zl,0,1);
         }
         printf("List size: %8d, bytes: %8d, %dx push+pop (%s): %6lld usec\n",
-            i,ZIPLIST_BYTES(zl),num,posstr[pos],usec()-start);
+            i,intrev32ifbe(ZIPLIST_BYTES(zl)),num,posstr[pos],usec()-start);
         zfree(zl);
     }
 }
index 65ed29c89ade473dc4fcb123de4780781cd2168c..1f11fd429ea016a303a04cf6d78645bb1d8fa60f 100644 (file)
@@ -80,7 +80,7 @@
 #include <string.h>
 #include <assert.h>
 #include "zmalloc.h"
-#include "endian.h"
+#include "endianconv.h"
 
 #define ZIPMAP_BIGLEN 254
 #define ZIPMAP_END 255