Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Typos.

  • Loading branch information...
commit d94afe3ee222cbf2aae9e06e3c0c414af2e73163 1 parent cb90dc1
@djanowski djanowski authored
View
9 README.md
@@ -49,7 +49,7 @@ backticks. For example: <code>`INCR`</code>.
example: `@multi-bulk-reply`. These keywords will get expanded and
auto-linked to relevant parts of the documentation.
-There should be at least three pre-defined sections: time complexity,
+There should be at least three predefined sections: time complexity,
description and return value. These sections are marked using magic
keywords, too:
@@ -83,3 +83,10 @@ files compile properly. You can do this by running Rake inside your
working directory.
$ rake
+
+Additionally, if you have [Aspell](http://aspell.net/) installed, you
+can spell check the documentation:
+
+ $ rake spellcheck
+
+Exceptions can be added to `./wordlist`.
View
28 Rakefile
@@ -1,4 +1,4 @@
-task :default => :parse
+task :default => [:parse, :spellcheck]
task :parse do
require "json"
@@ -13,3 +13,29 @@ task :parse do
end
end
end
+
+task :spellcheck do
+ require "json"
+
+ `mkdir -p tmp`
+
+ IO.popen("aspell --lang=en create master ./tmp/dict", "w") do |io|
+ io.puts(JSON.parse(File.read("commands.json")).keys.map(&:split).flatten.join("\n"))
+ io.puts(File.read("wordlist"))
+ end
+
+ Dir["**/*.md"].each do |file|
+ command = %q{
+ ruby -pe 'gsub /^ .*$/, ""' |
+ ruby -pe 'gsub /`[^`]+`/, ""' |
+ ruby -e 'puts $stdin.read.gsub /\[([^\]]+)\]\(([^\)]+)\)/m, "\\1"' |
+ aspell -H -a --extra-dicts=./tmp/dict 2>/dev/null
+ }
+
+ words = `cat '#{file}' | #{command}`.lines.map do |line|
+ line[/^& ([^ ]+)/, 1]
+ end.compact
+
+ puts "#{file}: #{words.uniq.sort.join(" ")}" if words.any?
+ end
+end
View
2  commands/auth.md
@@ -2,7 +2,7 @@
Request for authentication in a password protected Redis server.
Redis can be instructed to require a password before allowing clients
-to execute commands. This is done using the _requirepass_ directive in the
+to execute commands. This is done using the `requirepass` directive in the
configuration file.
If `password` matches the password in the configuration file, the server replies with
View
4 commands/config get.md
@@ -4,7 +4,7 @@ Not applicable.
@description
-The CONFIG GET ommand is used to read the configuration parameters of a running
+The `CONFIG GET` command is used to read the configuration parameters of a running
Redis server. Not all the configuration parameters are supported.
The symmetric command used to alter the configuration at run time is
`CONFIG SET`.
@@ -22,7 +22,7 @@ list of key-value pairs. Example:
6) "512"
You can obtain a list of all the supported configuration parameters typing
-`CONFIG GET *` in an open redis-cli prompt.
+`CONFIG GET *` in an open `redis-cli` prompt.
All the supported parameters have the same meaning of the equivalent
configuration parameter used in the [redis.conf](http://github.com/antirez/redis/raw/2.2/redis.conf) file, with the following important differences:
View
4 commands/info.md
@@ -23,8 +23,8 @@ All the fields are in the form of `field:value` terminated by `\r\n`.
## Notes
* `used_memory` is the total number of bytes allocated by Redis using its
- allocator (either standard libc malloc, or an alternative allocator such as
- [tcmalloc][1]
+ allocator (either standard `libc` `malloc`, or an alternative allocator such as
+ [`tcmalloc`][1]
* `used_memory_rss` is the number of bytes that Redis allocated as seen by the
operating system. Optimally, this number is close to `used_memory` and there
View
2  commands/lrem.md
@@ -10,7 +10,7 @@ following ways:
* `count < 0`: Remove elements equal to `value` moving from tail to head.
* `count = 0`: Remove all elements equal to `value`.
-For example, `LREM list -2 "hello"` will remove the last two occurances of
+For example, `LREM list -2 "hello"` will remove the last two occurrences of
`"hello"` in the list stored at `list`.
Note that non-existing keys are treated like empty lists, so when `key` does
View
2  commands/move.md
@@ -3,7 +3,7 @@
O(1)
-Move `key` from the currently selected database (see `SELECT`) to the speficied
+Move `key` from the currently selected database (see `SELECT`) to the specified
destination database. When `key` already exists in the destination database, or
it does not exist in the source database, it does nothing. It is possible to
use `MOVE` as a locking primitive because of this.
View
4 commands/rpoplpush.md
@@ -45,7 +45,7 @@ from the backup list using the `LREM` command when the message was correctly
processed.
Another process (that we call _Helper_), can monitor the backup list to check for
-timed out entries to repush against the main queue.
+timed out entries to re-push against the main queue.
## Design pattern: server-side O(N) list traversal
@@ -53,5 +53,5 @@ Using `RPOPLPUSH` with the same source and destination key, a process can
visit all the elements of an N-elements list in O(N) without transferring
the full list from the server to the client in a single `LRANGE` operation.
Note that a process can traverse the list even while other processes
-are actively `RPUSH`-ing against the list, and still no element will be skipped.
+are actively pushing to the list, and still no element will be skipped.
View
2  commands/setbit.md
@@ -15,7 +15,7 @@ bits are set to 0.
**Warning**: When setting the last possible bit (_offset_ equal to 2^32 -1) and
the string value stored at _key_ does not yet hold a string value, or holds a
small string value, Redis needs to allocate all intermediate memory which can
-block the server for some time. On a 2010 Macbook Pro, setting bit number
+block the server for some time. On a 2010 MacBook Pro, setting bit number
2^32 -1 (512MB allocation) takes ~300ms, setting bit number 2^30 -1 (128MB
allocation) takes ~80ms, setting bit number 2^28 -1 (32MB allocation) takes
~30ms and setting bit number 2^26 -1 (8MB allocation) takes ~8ms. Note that
View
4 commands/setrange.md
@@ -1,7 +1,7 @@
@complexity
O(1), not counting the time taken to copy the new string in place. Usually,
-this string is very small so the amortized complexity is O(1). Otheriwse,
+this string is very small so the amortized complexity is O(1). Otherwise,
complexity is O(M) with M being the length of the _value_ argument.
Overwrites part of the string stored at _key_, starting at the specified
@@ -18,7 +18,7 @@ can use multiple keys.
**Warning**: When setting the last possible byte and the string value stored at
_key_ does not yet hold a string value, or holds a small string value, Redis
needs to allocate all intermediate memory which can block the server for some
-time. On a 2010 Macbook Pro, setting byte number 536870911 (512MB allocation)
+time. On a 2010 MacBook Pro, setting byte number 536870911 (512MB allocation)
takes ~300ms, setting byte number 134217728 (128MB allocation) takes ~80ms,
setting bit number 33554432 (32MB allocation) takes ~30ms and setting bit
number 8388608 (8MB allocation) takes ~8ms. Note that once this first
View
8 commands/sort.md
@@ -16,7 +16,7 @@ large to small, use the `!DESC` modifier:
SORT mylist DESC
-When `mylist` contains string values and you want to sort them lexographically,
+When `mylist` contains string values and you want to sort them lexicographically,
use the `!ALPHA` modifier:
SORT mylist ALPHA
@@ -24,7 +24,7 @@ use the `!ALPHA` modifier:
Redis is UTF-8 aware, assuming you correctly set the `!LC_COLLATE` environment
variable.
-The number of returned elementes can be limited using the `!LIMIT` modifier.
+The number of returned elements can be limited using the `!LIMIT` modifier.
This modifier takes the `offset` argument, specifying the number of elements to
skip and the `count` argument, specifying the number of elements to return from
starting at `offset`. The following example will return 10 elements of the
@@ -33,7 +33,7 @@ sorted version of `mylist`, starting at element 0 (`offset` is zero-based):
SORT mylist LIMIT 0 10
Almost all modifiers can be used together. The following example will return
-the first 5 elements, lexographically sorted in descending order:
+the first 5 elements, lexicographically sorted in descending order:
SORT mylist LIMIT 0 5 ALPHA DESC
@@ -56,7 +56,7 @@ element in the list (`1`, `2` and `3` in this example).
## Skip sorting the elements
-The `!BY` option can also take a nonexisting key, which causes `SORT` to skip
+The `!BY` option can also take a non-existent key, which causes `SORT` to skip
the sorting operation. This is useful if you want to retrieve external keys
(see the `!GET` option below) without the overhead of sorting.
View
2  commands/subscribe.md
@@ -4,6 +4,6 @@ O(N) where N is the number of channels to subscribe to.
Subscribes the client to the specified channels.
-Once the client enters the subscripted state it is not supposed to issue
+Once the client enters the subscribed state it is not supposed to issue
any other commands, expect for additional `SUBSCRIBE`, `PSUBSCRIBE`,
`UNSUBSCRIBE` and `PUNSUBSCRIBE` commands.
View
2  commands/zrevrangebyscore.md
@@ -9,7 +9,7 @@ and `min` (including elements with score equal to `max` or `min`). In contrary
to the default ordering of sorted sets, for this command the elements are
considered to be ordered from high to low scores.
-The elements having the same score are returned in reverse lexographical order.
+The elements having the same score are returned in reverse lexicographical order.
Apart from the reversed ordering, `ZREVRANGEBYSCORE` is similar to
`ZRANGEBYSCORE`.
View
6 topics/benchmarks.md
@@ -7,7 +7,7 @@ against a Linux box.
* The test was done with 50 simultaneous clients performing 100000 requests.
* The value SET and GET is a 256 bytes string.
-* The Linux box is running *Linux 2.6*, it's *Xeon X3320 2.5Ghz*.
+* The Linux box is running *Linux 2.6*, it's *Xeon X3320 2.5 GHz*.
* Text executed using the loopback interface (127.0.0.1).
Results: *about 110000 SETs per second, about 81000 GETs per second.*
@@ -97,7 +97,7 @@ GETs may be slower with big payloads). The same for the number of clients, from
a bit slower.
You can expect different results from different boxes. For example a low
-profile box like *Intel core duo T5500 clocked at 1.66Ghz running Linux 2.6*
+profile box like *Intel core duo T5500 clocked at 1.66 GHz running Linux 2.6*
will output the following:
$ ./redis-benchmark -q -n 100000
@@ -107,7 +107,7 @@ will output the following:
LPUSH: 34803.41 requests per second
LPOP: 37367.20 requests per second
-Another one using a 64 bit box, a Xeon L5420 clocked at 2.5 Ghz:
+Another one using a 64 bit box, a Xeon L5420 clocked at 2.5 GHz:
$ ./redis-benchmark -q -n 100000
PING: 111731.84 requests per second
View
6 topics/expire.md
@@ -1,6 +1,6 @@
# Expiring keys
-Voltile keys are stored on disk like the other keys, the timeout is persistent
+Volatile keys are stored on disk like the other keys, the timeout is persistent
too like all the other aspects of the dataset. Saving a dataset containing
expires and stopping the server does not stop the flow of time as Redis
stores on disk the time when the key will no longer be available as Unix
@@ -96,7 +96,7 @@ per second divided by 4.
## Example
-Ok let's start with the problem:
+OK, let's start with the problem:
SET a 100
OK
@@ -158,4 +158,4 @@ the master instance, and there is no longer a chance of consistency errors.
However while the slaves connected to a master will not expire keys
independently, they'll still take the full state of the expires existing in
the dataset, so when a slave is elected to a master it will be able to expire
-the keys independently, fully acting as a master.
+the keys independently, fully acting as a master.
View
8 topics/faq.md
@@ -58,7 +58,7 @@ the right data structures for the problem we are trying to solve.
Yes you can. When Redis saves the DB it actually creates a temp file, then
rename(2) that temp file name to the destination file name. So even while the
-server is working it is safe to save the database file just with the _cp_ unix
+server is working it is safe to save the database file just with the _cp_ UNIX
command. Note that you can use master-slave replication in order to have
redundancy of data, but if all you need is backups, cp or scp will do the work
pretty well.
@@ -66,7 +66,7 @@ pretty well.
## What's the Redis memory footprint?
Worst case scenario: 1 Million keys with the key being the natural numbers from
-0 to 999999 and the string "Hello World" as value use 100MB on my Intel macbook
+0 to 999999 and the string "Hello World" as value use 100MB on my Intel MacBook
(32bit). Note that the same data stored linearly in an unique string takes
something like 16MB, this is the norm because with small keys and values there
is a lot of overhead. Memcached will perform similarly.
@@ -181,7 +181,7 @@ MMAP_THRESHOLD=4096`
## I have an empty Redis server but INFO and logs are reporting megabytes of memory in use!
-This may happen and it's prefectly ok. Redis objects are small C structures
+This may happen and it's perfectly okay. Redis objects are small C structures
allocated and freed a lot of times. This costs a lot of CPU so instead of being
freed, released objects are taken into a free list and reused when needed. This
memory is taken exactly by this free objects ready to be reused.
@@ -251,7 +251,7 @@ more optimistic allocation fashion, and this is indeed what you want for Redis.
A good source to understand how Linux Virtual Memory work and other
alternatives for `overcommit_memory` and `overcommit_ratio` is this classic
-from Red Hat Magaize, ["Understanding Virtual Memory"][redhatvm].
+from Red Hat Magazine, ["Understanding Virtual Memory"][redhatvm].
[redhatvm]: http://www.redhat.com/magazine/001nov04/features/vm/
View
2  topics/internals-eventlib.md
@@ -22,7 +22,7 @@ Q: How do Event Libraries do what they do?<br/>
A: They use the operating system's [polling](http://www.devshed.com/c/a/BrainDump/Linux-Files-and-the-Event-Poll-Interface/) facility along with timers.
Q: So are there any open source event libraries that do what you just described? <br/>
-A: Yes. Libevent and Libev are two such event libraries that I can recall off the top of my head.
+A: Yes. `libevent` and `libev` are two such event libraries that I can recall off the top of my head.
Q: Does Redis use such open source event libraries for handling socket I/O?<br/>
A: No. For various [reasons](http://groups.google.com/group/redis-db/browse_thread/thread/b52814e9ef15b8d0/) Redis uses its own event library.
View
59 topics/internals-rediseventlib.md
@@ -1,20 +1,20 @@
Redis Event Library
===
-Redis implements its own event library. The event library is implemented in *ae.c*.
+Redis implements its own event library. The event library is implemented in `ae.c`.
The best way to understand how the Redis event library works is to understand how Redis uses it.
Event Loop Initialization
---
-`initServer` function defined in *redis.c* initializes the numerous fields of the `redisServer` structure variable. One such field is the Redis event loop `el`:
+`initServer` function defined in `redis.c` initializes the numerous fields of the `redisServer` structure variable. One such field is the Redis event loop `el`:
- aeEventLoop *el
+ aeEventLoop *el
-`initServer` initializes `server.el` field by calling `aeCreateEventLoop` defined in *ae.c*. The definition of `aeEventLoop` is below:
+`initServer` initializes `server.el` field by calling `aeCreateEventLoop` defined in `ae.c`. The definition of `aeEventLoop` is below:
- typedef struct aeEventLoop
+ typedef struct aeEventLoop
{
int maxfd;
long long timeEventNextId;
@@ -26,46 +26,45 @@ Event Loop Initialization
aeBeforeSleepProc *beforesleep;
} aeEventLoop;
-aeCreateEventLoop
+`aeCreateEventLoop`
---
-`aeCreateEventLoop` first mallocs aeEventLoop structure then calls ae_epoll.c:aeApiCreate`.
+`aeCreateEventLoop` first `malloc`s `aeEventLoop` structure then calls `ae_epoll.c:aeApiCreate`.
-`aeApiCreate` mallocs `aeApiState` that has two fields - `epfd` that holds the epoll file descriptor returned by a call from [epoll_create](http://man.cx/epoll_create%282%29) and `events` that is of type `struct epoll_event` define by the Linux epoll library. The use of the `events` field will be described later.
+`aeApiCreate` `malloc`s `aeApiState` that has two fields - `epfd` that holds the `epoll` file descriptor returned by a call from [`epoll_create`](http://man.cx/epoll_create%282%29) and `events` that is of type `struct epoll_event` define by the Linux `epoll` library. The use of the `events` field will be described later.
-Next is 'ae.c:aeCreateTimeEvent`. But before that `initServer` call `anet.c:anetTcpServer` that creates and returns a _listening descriptor_. The descriptor is listens to *port 6379* by default. The returned _listening descriptor_ is stored in `server.fd` field.
+Next is `ae.c:aeCreateTimeEvent`. But before that `initServer` call `anet.c:anetTcpServer` that creates and returns a _listening descriptor_. The descriptor listens on *port 6379* by default. The returned _listening descriptor_ is stored in `server.fd` field.
-aeCreateTimeEvent
+`aeCreateTimeEvent`
---
`aeCreateTimeEvent` accepts the following as parameters:
- * eventLoop: This is `server.el` in *redis.c*
- * milliseconds: The number of milliseconds from the curent time after which the timer expires.
- * proc: Function pointer. Stores the address of the function that has to be called after the timer expires.
- * clientData: Mostly NULL.
- * finalizerProc: Pointer to the function that has to be called before the timed event is removed from the list of timed events.
+ * `eventLoop`: This is `server.el` in `redis.c`
+ * milliseconds: The number of milliseconds from the current time after which the timer expires.
+ * `proc`: Function pointer. Stores the address of the function that has to be called after the timer expires.
+ * `clientData`: Mostly `NULL`.
+ * `finalizerProc`: Pointer to the function that has to be called before the timed event is removed from the list of timed events.
`initServer` calls `aeCreateTimeEvent` to add a timed event to `timeEventHead` field of `server.el`. `timeEventHead` is a pointer to a list of such timed events. The call to `aeCreateTimeEvent` from `redis.c:initServer` function is given below:
-
aeCreateTimeEvent(server.el /*eventLoop*/, 1 /*milliseconds*/, serverCron /*proc*/, NULL /*clientData*/, NULL /*finalizerProc*/);
`redis.c:serverCron` performs many operations that helps keep Redis running properly.
-aeCreateFileEvent
+`aeCreateFileEvent`
---
-The essence of `aeCreateFileEvent` function is to execute [epoll_ctl](http://man.cx/epoll_ctl) system call which adds a watch for `EPOLLIN` event on the _listening descriptor_ create by `anetTcpServer` and associate it with the epoll descriptor created by a call to `aeCreateEventLoop`.
+The essence of `aeCreateFileEvent` function is to execute [`epoll_ctl`](http://man.cx/epoll_ctl) system call which adds a watch for `EPOLLIN` event on the _listening descriptor_ create by `anetTcpServer` and associate it with the `epoll` descriptor created by a call to `aeCreateEventLoop`.
Following is an explanation of what precisely `aeCreateFileEvent` does when called from `redis.c:initServer`.
`initServer` passes the following arguments to `aeCreateFileEvent`:
- * server.el: The event loop created by `aeCreateEventLoop`. The epoll descriptor is got from server.el.
- * server.fd: The _listening descriptor_ that also serves as an index to access the relevant file event structure from the `eventLoop->events` table and store extra information like the callback function.
- * AE_READABLE: Signifies that server.fd has to be watched for EPOLLIN event.
- * acceptHandler: The function that has to be executed when the event being watched for is ready. This function pointer is stored in `eventLoop->events[server.fd]->rfileProc`.
+ * `server.el`: The event loop created by `aeCreateEventLoop`. The `epoll` descriptor is got from `server.el`.
+ * `server.fd`: The _listening descriptor_ that also serves as an index to access the relevant file event structure from the `eventLoop->events` table and store extra information like the callback function.
+ * `AE_READABLE`: Signifies that `server.fd` has to be watched for `EPOLLIN` event.
+ * `acceptHandler`: The function that has to be executed when the event being watched for is ready. This function pointer is stored in `eventLoop->events[server.fd]->rfileProc`.
This completes the initialization of Redis event loop.
@@ -76,21 +75,21 @@ Event Loop Processing
`ae.c:aeMain` calls `ae.c:aeProcessEvents` in a while loop that processes pending time and file events.
-aeProcessEvents
+`aeProcessEvents`
---
-`ae.c:aeProcessEvents` looks for the time event that will be pending in the smallest amount of time by calling `ae.c:aeSearchNearestTimer` on the event loop. In our case there is only one timer event in the event loop that was created by `ae.c:aeCreateTimeEvent`.
+`ae.c:aeProcessEvents` looks for the time event that will be pending in the smallest amount of time by calling `ae.c:aeSearchNearestTimer` on the event loop. In our case there is only one timer event in the event loop that was created by `ae.c:aeCreateTimeEvent`.
-Remember, that timer event created by `aeCreateTimeEvent` has by now probably elapsed because it had a expiry time of one millisecond. Since, the timer has already expired the seconds and microseconds fields of the `tvp` timeval structure variable is initialized to zero.
+Remember, that timer event created by `aeCreateTimeEvent` has by now probably elapsed because it had a expiry time of one millisecond. Since, the timer has already expired the seconds and microseconds fields of the `tvp` `timeval` structure variable is initialized to zero.
The `tvp` structure variable along with the event loop variable is passed to `ae_epoll.c:aeApiPoll`.
-`aeApiPoll` functions does a [epoll_wait](http://man.cx/epoll_wait) on the epoll descriptor and populates the `eventLoop->fired` table with the details:
+`aeApiPoll` functions does a [`epoll_wait`](http://man.cx/epoll_wait) on the `epoll` descriptor and populates the `eventLoop->fired` table with the details:
- * fd: The descriptor that is now ready to do a read/write operation depending on the mask value. The
- * mask: The read/write event that can now be performed on the corresponding descriptor.
+ * `fd`: The descriptor that is now ready to do a read/write operation depending on the mask value.
+ * `mask`: The read/write event that can now be performed on the corresponding descriptor.
-`aeApiPoll` returns the number of such file events ready for operation. Now to put things in context, if any client has requested for a connection then aeApiPoll would have noticed it and populated the `eventLoop->fired` table with an entry of the descriptor being the _listening descriptor_ and mask being `AE_READABLE`.
+`aeApiPoll` returns the number of such file events ready for operation. Now to put things in context, if any client has requested for a connection then `aeApiPoll` would have noticed it and populated the `eventLoop->fired` table with an entry of the descriptor being the _listening descriptor_ and mask being `AE_READABLE`.
Now, `aeProcessEvents` calls the `redis.c:acceptHandler` registered as the callback. `acceptHandler` executes [accept](http://man.cx/accept) on the _listening descriptor_ returning a _connected descriptor_ with the client. `redis.c:createClient` adds a file event on the _connected descriptor_ through a call to `ae.c:aeCreateFileEvent` like below:
@@ -104,7 +103,7 @@ Now, `aeProcessEvents` calls the `redis.c:acceptHandler` registered as the callb
Next the `ae.c:aeProcessEvent` calls `ae.c:processTimeEvents`
-processTimeEvents
+`processTimeEvents`
---
`ae.processTimeEvents` iterates over list of time events starting at `eventLoop->timeEventHead`.
View
34 topics/internals-sds.md
@@ -1,9 +1,9 @@
Hacking Strings
===
-The implementation of Redis strings is contained in **sds.c** ( sds stands for Simple Dynamic Strings ).
+The implementation of Redis strings is contained in `sds.c` (`sds` stands for Simple Dynamic Strings).
-The C structure _sdshdr_ declared in *sds.h* represents a Redis string:
+The C structure `sdshdr` declared in `sds.h` represents a Redis string:
struct sdshdr {
long len;
@@ -11,23 +11,23 @@ The C structure _sdshdr_ declared in *sds.h* represents a Redis string:
char buf[];
};
-The _buf_ character array stores the actual string.
+The `buf` character array stores the actual string.
-The _len_ field stores the length of _buf_. This makes obtaining the length
+The `len` field stores the length of `buf`. This makes obtaining the length
of a Redis string an O(1) operation.
-The _free_ field stores the number of additional bytes available for use.
+The `free` field stores the number of additional bytes available for use.
-Together the _len_ and _free_ field can be thought of as holding the metadata of the _buf_ character array.
+Together the `len` and `free` field can be thought of as holding the metadata of the `buf` character array.
Creating Redis Strings
---
-A new data type named `sds` is defined in *sds.h* to be a synonymn for a character pointer:
+A new data type named `sds` is defined in `sds.h` to be a synonym for a character pointer:
typedef char *sds;
-`sdsnewlen` function defined in *sds.c* creates a new Redis String:
+`sdsnewlen` function defined in `sds.c` creates a new Redis String:
sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
@@ -56,20 +56,20 @@ Suppose I create a Redis string using `sdsnewlen` like below:
sdsnewlen("redis", 5);
-This creates a new variable of type `struct sdshdr` allocating memory for _len_ and _free_
-fields as well as for the _buf_ character array.
+This creates a new variable of type `struct sdshdr` allocating memory for `len` and `free`
+fields as well as for the `buf` character array.
sh = zmalloc(sizeof(struct sdshdr)+initlen+1); // initlen is length of init argument.
-After `sdsnewlen` succesfully creates a Redis string the result is something like:
+After `sdsnewlen` successfully creates a Redis string the result is something like:
-----------
|5|0|redis|
-----------
^ ^
- sh sh->buf
+ sh sh->buf
-`sdsnewlen` returns sh->buf to the caller.
+`sdsnewlen` returns `sh->buf` to the caller.
What do you do if you need to free the Redis string pointed by `sh`?
@@ -77,10 +77,10 @@ You want the pointer `sh` but you only have the pointer `sh->buf`.
Can you get the pointer `sh` from `sh->buf`?
-Yes. Pointer arithmetic. Notice from the above ASCII art that if you subtract
-the size of two longs from `sh->buf` you get the pointer `sh`.
+Yes. Pointer arithmetic. Notice from the above ASCII art that if you subtract
+the size of two longs from `sh->buf` you get the pointer `sh`.
-The sizeof two longs happens to be the size of `struct sdshdr`.
+The `sizeof` two longs happens to be the size of `struct sdshdr`.
Look at `sdslen` function and see this trick at work:
@@ -89,6 +89,6 @@ Look at `sdslen` function and see this trick at work:
return sh->len;
}
-Knowing this trick you could easily go through the rest of the functions in *sds.c*.
+Knowing this trick you could easily go through the rest of the functions in `sds.c`.
The Redis string implementation is hidden behind an interface that accepts only character pointers. The users of Redis strings need not care about how its implemented and treat Redis strings as a character pointer.
View
14 topics/internals-vm.md
@@ -89,7 +89,7 @@ Redis takes a "bitmap" (an contiguous array of bits set to zero or one) in memor
Taking this bitmap (that will call the page table) in memory is a huge win in terms of performances, and the memory used is small: we just need 1 bit for every page on disk. For instance in the example below 134217728 pages of 32 bytes each (4GB swap file) is using just 16 MB of RAM for the page table.
-Transfering objects from memory to swap
+Transferring objects from memory to swap
---
In order to transfer an object from memory to disk we need to perform the following steps (assuming non threaded VM, just a simple blocking approach):
@@ -126,11 +126,11 @@ If this function detects we are out of memory, that is, the memory used is great
vmSwapOneObject acts performing the following steps:
* The key space in inspected in order to find a good candidate for swapping (we'll see later what a good candidate for swapping is).
- * The associated value is transfered to disk, in a blocking way.
+ * The associated value is transferred to disk, in a blocking way.
* The key storage field is set to REDIS_VM_SWAPPED, while the _vm_ fields of the object are set to the right values (the page index where the object was swapped, and the number of pages used to swap it).
* Finally the value object is freed and the value entry of the hash table is set to NULL.
-The function is called again and again until one of the following happens: there is no way to swap more objects because either the swap file is full or nearly all the objects are already transfered on disk, or simply the memory usage is already under the vm-max-memory parameter.
+The function is called again and again until one of the following happens: there is no way to swap more objects because either the swap file is full or nearly all the objects are already transferred on disk, or simply the memory usage is already under the vm-max-memory parameter.
What values to swap when we are out of memory?
---
@@ -152,7 +152,7 @@ If the value object of the `foo` key is swapped we need to load it back in memor
So this is what happens:
- * The user calls some command having as argumenet a swapped key
+ * The user calls some command having as argument a swapped key
* The command implementation calls the lookup function
* The lookup function search for the key in the top level hash table. If the value associated with the requested key is swapped (we can see that checking the _storage_ field of the key object), we load it back in memory in a blocking way before to return to the user.
@@ -170,7 +170,7 @@ The child process will just store the whole dataset into the dump.rdb file and f
* The parent process needs to access the swap file in order to load values back into memory if an operation against swapped out values are performed.
* The child process needs to access the swap file in order to retrieve the full dataset while saving the data set on disk.
-In order to avoid problems while both the processes are accessing the same swap file we do a simple thing, that is, not allowing values to be swapped out in the parent process while a background saving is in progress. This way both the processes will access the swap file in read only. This approach has the problem that while the child process is saving no new values can be transfered on the swap file even if Redis is using more memory than the max memory parameters dictates. This is usually not a problem as the background saving will terminate in a short amount of time and if still needed a percentage of values will be swapped on disk ASAP.
+In order to avoid problems while both the processes are accessing the same swap file we do a simple thing, that is, not allowing values to be swapped out in the parent process while a background saving is in progress. This way both the processes will access the swap file in read only. This approach has the problem that while the child process is saving no new values can be transferred on the swap file even if Redis is using more memory than the max memory parameters dictates. This is usually not a problem as the background saving will terminate in a short amount of time and if still needed a percentage of values will be swapped on disk ASAP.
An alternative to this scenario is to enable the Append Only File that will have this problem only when a log rewrite is performed using the BGREWRITEAOF command.
@@ -197,7 +197,7 @@ I/O Threads
The threaded VM design goals where the following, in order of importance:
- * Simple implementation, little room for race condtions, simple locking, VM system more or less completeley decoupled from the rest of Redis code.
+ * Simple implementation, little room for race conditions, simple locking, VM system more or less completely decoupled from the rest of Redis code.
* Good performances, no locks for clients accessing values in memory.
* Ability to decode/encode objects in the I/O threads.
@@ -248,7 +248,7 @@ For instance in the case of the SORT command used together with the GET or BY op
Blocking clients on swapped keys
---
-How to block clients? To suspend a client in an event-loop based server is pretty trivial. All we do is cancelling its read handler. Sometimes we do something different (for instance for BLPOP) that is just marking the client as blocked, but not processing new data (just accumulating the new data into input buffers).
+How to block clients? To suspend a client in an event-loop based server is pretty trivial. All we do is canceling its read handler. Sometimes we do something different (for instance for BLPOP) that is just marking the client as blocked, but not processing new data (just accumulating the new data into input buffers).
Aborting I/O jobs
---
View
8 topics/memory-optimization.md
@@ -14,7 +14,7 @@ Since this is a CPU / memory trade off it is possible to tune the maximum number
list-max-ziplist-value 64
set-max-intset-entries 512
-If a specially encoded value will overflow the configured max size, Redis will automatically convert it into normal encoding. This operation is very fast for small values, but if you change the setting in order to use specially encoded values for much larger aggregate types the suggestin is to run some benchmark and test to check the convertion time.
+If a specially encoded value will overflow the configured max size, Redis will automatically convert it into normal encoding. This operation is very fast for small values, but if you change the setting in order to use specially encoded values for much larger aggregate types the suggestion is to run some benchmark and test to check the conversion time.
Using 32 bit instances
----------------------
@@ -24,7 +24,7 @@ Redis compiled with 32 bit target uses a lot less memory per key, since pointers
New 2.2 bit and byte level operations
-------------------------------------
-Redis 2.2 introduced new bit and byte level operations: [GETRANGE](/commands/getrange), [SETRANGE](/commands/setrange), [GETBIT](/commands/getbit) and [SETBIT](/commands/setbit). Using this commands you can treat the Redis string type as a random access array. For instance if you have an application where users are identified by an unique progressive integer number, you can use a bitmap in order to save information about sex of users, setting the bit for females and clearing it for males, or the other way around. With 100 millions of users this data will take just 12 megabyte of RAM in a Redis instance. You can do the same using [GETRANGE](/commands/getrange) and [SETRANGE](/commands/setrange) in order to store one byte of information for user. This is just an example but it is actually possible to model a number of problems in very little space with this new primitives.
+Redis 2.2 introduced new bit and byte level operations: `GETRANGE`, `SETRANGE`, `GETBIT` and `SETBIT`. Using this commands you can treat the Redis string type as a random access array. For instance if you have an application where users are identified by an unique progressive integer number, you can use a bitmap in order to save information about sex of users, setting the bit for females and clearing it for males, or the other way around. With 100 millions of users this data will take just 12 megabyte of RAM in a Redis instance. You can do the same using `GETRANGE` and `SETRANGE` in order to store one byte of information for user. This is just an example but it is actually possible to model a number of problems in very little space with this new primitives.
Use hashes when possible
------------------------
@@ -62,7 +62,7 @@ cache locality than an hash table).
However since hash fields and values are not (always) represented as full
featured Redis objects, hash fields can't have an associated time to live
-(expire) like a real key, and can only contain a string. But we are ok with
+(expire) like a real key, and can only contain a string. But we are okay with
this, this was anyway the intention when the hash data type API was
designed (we trust simplicity more than features, so nested data structures
are not allowed, as expires of single fields are not allowed).
@@ -173,7 +173,7 @@ You may ask, why don't you do this implicitly in the normal key space so that
I don't have to care? There are two reasons: one is that we tend to make
trade offs explicit, and this is a clear tradeoff between many things: CPU,
memory, max element size. The second is that the top level key space must
-support a lot of interesting things like expires, LRU informations, and so
+support a lot of interesting things like expires, LRU data, and so
forth so it is not practical to do this in a general way.
But the Redis Way is that the user must understand how things work so that
View
6 topics/pipelining.md
@@ -19,9 +19,9 @@ So for instance a four commands sequence is something like this:
* *Client:* INCR X
* *Server:* 4
-Clients and Servers are connected via a networking link. Such a link can be very fast (a loopback interface) or very slow (a connection established over the internet with many hops between the two hosts). Whatever the network latency is, there is a time for the packets to travel from the client to the server, and back from the server to the client to carry the reply.
+Clients and Servers are connected via a networking link. Such a link can be very fast (a loopback interface) or very slow (a connection established over the Internet with many hops between the two hosts). Whatever the network latency is, there is a time for the packets to travel from the client to the server, and back from the server to the client to carry the reply.
-This time is called RTT (Round Trip Time). It is very easy to see how this can affect the performances when a client needs to perform many requests in a row (for instance adding many elements to the same list, or populating a database with many keys). For instance if the RTT time is 250 milliseconds (in the case of a very slow link over the internet), even if the server is able to process 100k requests per second, we'll be able to process at max four requests per second.
+This time is called RTT (Round Trip Time). It is very easy to see how this can affect the performances when a client needs to perform many requests in a row (for instance adding many elements to the same list, or populating a database with many keys). For instance if the RTT time is 250 milliseconds (in the case of a very slow link over the Internet), even if the server is able to process 100k requests per second, we'll be able to process at max four requests per second.
If the interface used is a loopback interface, the RTT is much shorter (for instance my host reports 0,044 milliseconds pinging 127.0.0.1), but it is still a lot if you need to perform many writes in a row.
@@ -104,6 +104,6 @@ Pipelining VS other multi-commands
---
Often we get requests about adding new commands performing multiple operations in a single pass.
-For instance there is no command to add multiple elements in a set. You need calling many times [SADD](/commands/sadd).
+For instance there is no command to add multiple elements in a set. You need calling many times `SADD`.
With pipelining you can have performances near to an hypothetical MSADD command, but at the same time we'll avoid bloating the Redis command set with too many commands. An additional advantage is that the version written using just SADD will be ready for a distributed environment (for instance Redis Cluster, that is in the process of being developed) just dropping the pipelining code.
View
2  topics/protocol.md
@@ -53,7 +53,7 @@ to see the exact value of every byte in the query:
As you will see in a moment this format is also used in Redis replies. The
format used for every argument `$6\r\nmydata\r\n` is called a Bulk Reply.
While the actual unified request protocol is what Redis uses to return list of
-items, and is called a Multi Bulk Reply. It is just the sum of N different Bulk
+items, and is called a @multi-bulk-reply. It is just the sum of N different Bulk
Replies prefixed by a `*<argc>\r\n` string where `<argc>` is the number of
arguments (Bulk Replies) that will follow.
View
2  topics/replication.md
@@ -60,7 +60,7 @@ configuration file:
slaveof 192.168.1.1 6379
-Of course you need to replace 192.168.1.1 6379 with your master ip address (or
+Of course you need to replace 192.168.1.1 6379 with your master IP address (or
hostname) and port. Alternatively, you can call the `SLAVEOF` command and the
master host will start a sync with the slave.
View
2  topics/sponsors.md
@@ -11,7 +11,7 @@ In the past Redis accepted donations from the following companies:
* [Hitmeister](http://www.hitmeister.de/) 15 Dec 2009, part of Redis Cluster.
* [Engine Yard](http://engineyard.com) 13 Dec 2009, for blocking POP (BLPOP) and part of the Virtual Memory implementation.
-Also thaks to the following people or organizations that donated to the Project:
+Also thanks to the following people or organizations that donated to the Project:
* Emil Vladev
* [Brad Jasper](http://bradjasper.com/)
View
2  topics/transactions.md
@@ -21,7 +21,7 @@ operations are performed. When using the
to use a single write(2) syscall to write the transaction on disk.
However if the Redis server crashes or is killed by the system administrator
in some hard way it is possible that only a partial number of operations
-are registered. Redis will detect this condition at restart, and will exit with an error. Using the **redis-check-aof** tool it is possible to fix the
+are registered. Redis will detect this condition at restart, and will exit with an error. Using the `redis-check-aof` tool it is possible to fix the
append only file that will remove the partial transaction so that the
server can start again.
View
22 topics/twitter-clone.md
@@ -40,7 +40,7 @@ Other common operations provided by key-value stores are DEL used to delete a gi
Atomic operations
---
-So far it should be pretty simple, but there is something special about INCR. Think about this, why to provide such an operation if we can do it ourself with a bit of code? After all it is as simple as:
+So far it should be pretty simple, but there is something special about INCR. Think about this, why to provide such an operation if we can do it ourselves with a bit of code? After all it is as simple as:
x = GET foo
x = x + 1
@@ -73,7 +73,7 @@ This is very useful for our Twitter clone. Updates of users can be stored into a
LRANGE mylist 0 1 => c,b
-LRANGE uses zero-based indexes, that is the first element is 0, the second 1, and so on. The command aguments are `LRANGE key first-index last-index`. The _last index_ argument can be negative, with a special meaning: -1 is the last element of the list, -2 the penultimate, and so on. So in order to get the whole list we can use:
+LRANGE uses zero-based indexes, that is the first element is 0, the second 1, and so on. The command arguments are `LRANGE key first-index last-index`. The _last index_ argument can be negative, with a special meaning: -1 is the last element of the list, -2 the penultimate, and so on. So in order to get the whole list we can use:
LRANGE mylist 0 -1 => c,b,a
@@ -103,12 +103,12 @@ SINTER can return the intersection between Sets but it is not limited to two set
SISMEMBER myset foo => 1
SISMEMBER myset notamember => 0
-Ok I think we are ready to start coding!
+Okay, I think we are ready to start coding!
Prerequisites
---
-If you didn't download it already please grab the [source code of Retwis](http://code.google.com/p/redis/downloads/list). It's a simple tar.gz file with a few of .php files inside. The implementation is very simple. You will find the PHP library client inside (redis.php) that is used to talk with the Redis server from PHP. This library was written by [Ludovico Magnocavallo](http://qix.it) and you are free to reuse this in your own projects, but for updated version of the library please download the Redis distribution. (Note: there are now better PHP libraries available, check our [clients page](/clients).
+If you didn't download it already please grab the [source code of Retwis](http://code.google.com/p/redis/downloads/list). It's a simple tar.gz file with a few of PHP files inside. The implementation is very simple. You will find the PHP library client inside (redis.php) that is used to talk with the Redis server from PHP. This library was written by [Ludovico Magnocavallo](http://qix.it) and you are free to reuse this in your own projects, but for updated version of the library please download the Redis distribution. (Note: there are now better PHP libraries available, check our [clients page](/clients).
Another thing you probably want is a working Redis server. Just get the source, compile with make, and run with ./redis-server and you are done. No configuration is required at all in order to play with it or to run Retwis in your computer.
@@ -117,7 +117,7 @@ Data layout
Working with a relational database this is the stage were the database layout should be produced in form of tables, indexes, and so on. We don't have tables, so what should be designed? We need to identify what keys are needed to represent our objects and what kind of values this keys need to hold.
-Let's start from Users. We need to represent this users of course, with the username, userid, password, followers and following users, and so on. The first question is, what should identify an user inside our system? The username can be a good idea since it is unique, but it is also too big, and we want to stay low on memory. So like if our DB was a relational one we can associate an unique ID to every user. Every other reference to this user will be done by id. That's very simple to do, because we have our atomic INCR operation! When we create a new user we can do something like this, assuming the user is callled "antirez":
+Let's start from Users. We need to represent this users of course, with the username, userid, password, followers and following users, and so on. The first question is, what should identify an user inside our system? The username can be a good idea since it is unique, but it is also too big, and we want to stay low on memory. So like if our DB was a relational one we can associate an unique ID to every user. Every other reference to this user will be done by id. That's very simple to do, because we have our atomic INCR operation! When we create a new user we can do something like this, assuming the user is called "antirez":
INCR global:nextUserId => 1000
SET uid:1000:username antirez
@@ -145,12 +145,12 @@ Another important thing we need is a place were we can add the updates to displa
Authentication
---
-Ok we have more or less everything about the user, but authentication. We'll handle authentication in a simple but robust way: we don't want to use PHP sessions or other things like this, our system must be ready in order to be distributed among different servers, so we'll take the whole state in our Redis database. So all we need is a random string to set as the cookie of an authenticated user, and a key that will tell us what is the user ID of the client holding such a random string. We need two keys in order to make this thing working in a robust way:
+OK, we have more or less everything about the user, but authentication. We'll handle authentication in a simple but robust way: we don't want to use PHP sessions or other things like this, our system must be ready in order to be distributed among different servers, so we'll take the whole state in our Redis database. So all we need is a random string to set as the cookie of an authenticated user, and a key that will tell us what is the user ID of the client holding such a random string. We need two keys in order to make this thing working in a robust way:
SET uid:1000:auth fea5e81ac8ca77622bed1c2132a021f9
SET auth:fea5e81ac8ca77622bed1c2132a021f9 1000
-In order to authenticate an user we'll do this simple work (login.php):
+In order to authenticate an user we'll do this simple work (`login.php`):
* Get the username and password via the login form
* Check if the username:`<username>`:uid key actually exists
* If it exists we have the user id, (i.e. 1000)
@@ -165,7 +165,7 @@ This is the actual code:
if (!gt("username") || !gt("password"))
goback("You need to enter both username and password to login.");
- # The form is ok, check if the username is available
+ # The form is OK, check if the username is available
$username = gt("username");
$password = gt("password");
$r = redisLink();
@@ -183,9 +183,9 @@ This is the actual code:
This happens every time the users log in, but we also need a function isLoggedIn in order to check if a given user is already authenticated or not. These are the logical steps preformed by the `isLoggedIn` function:
* Get the "auth" cookie from the user. If there is no cookie, the user is not logged in, of course. Let's call the value of this cookie `<authcookie>`
- * Check if auth:`<authcookie>` exists, and what the value (the user id) is (1000 in the exmple).
+ * Check if auth:`<authcookie>` exists, and what the value (the user id) is (1000 in the example).
* In order to be sure check that uid:1000:auth matches.
- * Ok the user is authenticated, and we loaded a bit of information in the $User global variable.
+ * OK the user is authenticated, and we loaded a bit of information in the $User global variable.
The code is simpler than the description, possibly:
@@ -237,7 +237,7 @@ The code is simpler than the description, possibly:
header("Location: index.php");
-That is just what we described and should be simple to undestand.
+That is just what we described and should be simple to understand.
Updates
---
View
2  topics/virtual-memory.md
@@ -179,7 +179,7 @@ out. A file system not supporting sparse files can at some point block the
Redis process while creating a very big file at once.
For a list of file systems supporting spare files, [check this check this
-Wikipedia pkage comparing different files systems][wikifs].
+Wikipedia page comparing different files systems][wikifs].
[wikifs]: http://en.wikipedia.org/wiki/Comparison_of_file_systems
View
33 wordlist
@@ -0,0 +1,33 @@
+AOF
+backticks
+blazingly
+blog
+btw
+CLI
+dataset
+GHz
+hostname
+indices
+JPEG
+JSON
+keyspace
+MacBook
+multi
+pipelining
+RDB
+SHA
+SQL
+subcommand
+subcommands
+substring
+timestamp
+tuple
+tuples
+unsubscribe
+unsubscribed
+unsubscribes
+unwatch/ES
+UTF
+Xeon
+Yukihiro
+desync
Please sign in to comment.
Something went wrong with that request. Please try again.