Compare commits

...
551 Commits
Author SHA1 Message Date
antirez 4e6d34bd2c Redis 2.8.0. 2013-11-22 10:25:29 +01:00
antirez f75fccafe7 Sentinel: example sentinel.conf updated. 2013-11-21 17:07:10 +01:00
antirez 312ca4dacc Sentinel: different comments updated to new implementation. 2013-11-21 16:23:11 +01:00
antirez c84275ee60 Sentinel: cleanup around SENTINEL_INFO_VALIDITY_TIME. 2013-11-21 16:06:07 +01:00
antirez 0b2639123b Sentinel: removed mem leak and useless code. 2013-11-21 15:44:10 +01:00
antirez 750b007d7c Sentinel: manual failover works again. 2013-11-21 15:24:27 +01:00
antirez 4bd1dd1c53 Sentinel: test for writable config file.
This commit introduces a funciton called when Sentinel is ready for
normal operations to avoid putting Sentinel specific stuff in redis.c.
2013-11-21 15:24:22 +01:00
antirez 46e2f3468c Sentinel: check for disconnected links in sentinelSendHello().
Does not fix any bug as the test is performed by the caller, but better
to have the check.
2013-11-21 15:24:15 +01:00
antirez 87098a39f0 Sentinel: Hello message sending code refactored. 2013-11-21 15:24:11 +01:00
antirez 9ecd819ecb Sentinel: select slave with best (greater) replication offset. 2013-11-21 15:24:08 +01:00
antirez eeb8cb3305 Sentinel: take the replication offset in slaves state. 2013-11-21 15:24:03 +01:00
antirez c517f72343 CONFIG REWRITE: don't add the signature if it already exists.
At the end of the file, CONFIG REWRITE adds a comment line that:

    # Generated by CONFIG REWRITE

Followed by the additional config options required. However this was
added again and again at every rewrite in praticular conditions (when a
given set of options change in a given time during the time).

Now if it was alrady encountered, it is not added a second time.

This is especially important for Sentinel that rewrites the config at
every state change.
2013-11-21 15:23:47 +01:00
antirez 812f76a850 Sentinel: distinguish between is-master-down-by-addr requests.
Some are just to know if the master is down, and in this case the runid
in the request is set to "*", others are actually in order to seek for a
vote and get elected. In the latter case the runid is set to the runid
of the instance seeking for the vote.
2013-11-21 15:22:55 +01:00
antirez fc93198ff9 Sentinel: various fixes to leader election implementation. 2013-11-21 15:22:52 +01:00
antirez 44b3684633 Sentinel: failover script execution fixed. 2013-11-21 15:22:48 +01:00
antirez 6d0400f569 Sentinel: no longer used defines removed. 2013-11-21 15:22:44 +01:00
antirez 1bbce5bf01 Sentinel: when writing config on disk, remember sentinels runid. 2013-11-21 15:22:27 +01:00
antirez 679dc8b09d Sentinel: arity of known-sentinel/slave is 4 not 3. 2013-11-21 15:22:21 +01:00
antirez 3e1fc6278d Sentinel: rewriteConfigSentinelOption() sub-iterators var typo fixed. 2013-11-21 15:22:18 +01:00
antirez 9a9c0cfaa6 Sentinel: call sentinelFlushConfig() to persist state when needed.
Also the sentinel configuration rewriting was modified in order to
account for failover in progress, where we need to provide the promoted
slave address as master address, and the old master address as one of
the slaves address.
2013-11-21 15:22:14 +01:00
antirez 93d924ff1c Sentinel: sentinelFlushConfig() to CONFIG REWRITE + fsync. 2013-11-21 15:22:11 +01:00
antirez a52909c5f2 Sentinel: CONFIG REWRITE support for Sentinel config. 2013-11-21 15:22:07 +01:00
antirez 8c3e197040 Sentinel: can-failover option removed, many comments fixed. 2013-11-21 15:22:02 +01:00
antirez 04b1fb0b1a Fix typo 'configuraiton' in rewriteConfigRewriteLine() comment. 2013-11-21 15:21:58 +01:00
antirez 0b9853ecdc Sentinel: added config options useful to take state on config rewrite.
We'll use CONFIG REWRITE (internally) in order to store the new
configuration of a Sentinel after the internal state changes. In order
to do so, we need configuration options (that usually the user will not
touch at all) about config epoch of the master, Sentinels and Slaves
known for this master, and so forth.
2013-11-21 15:21:55 +01:00
antirez 737062745d Sentinel: failover abort function simplified. 2013-11-21 15:21:50 +01:00
antirez 66b03c1a40 Sentinel: slaves reconfig delay modified.
The time Sentinel waits since the slave is detected to be configured to
the wrong master, before reconfiguring it, is now the failover_timeout
time as this makes more sense in order to give the Sentinel performing
the failover enoung time to reconfigure the slaves slowly (if required
by the configuration).

Also we now PUBLISH more frequently the new configuraiton as this allows
to switch the reapprearing master back to slave faster.
2013-11-21 15:21:46 +01:00
antirez 8ba31c218b Sentinel: failover restart time is now multiple of failover timeout.
Also defaulf failover timeout changed to 3 minutes as the failover is a
fairly fast procedure most of the times, unless there are a very big
number of slaves and the user picked to configure them sequentially (in
that case the user should change the failover timeout accordingly).
2013-11-21 15:21:41 +01:00
antirez ccaba966bc Sentinel: state machine and timeouts simplified. 2013-11-21 15:21:37 +01:00
antirez 3c4497e83c Sentinel: election timeout define. 2013-11-21 15:21:34 +01:00
antirez e15ba6a697 Sentinel: fix address of master in Hello messages.
Once we switched configuration during a failover, we should advertise
the new address.

This was a serious race condition as the Sentinel performing the
failover for a moment advertised the old address with the new
configuration epoch: once trasmitted to the other Sentinels the broken
configuration would remain there forever, until the next failover
(because a greater configuration epoch is required to overwrite an older
one).
2013-11-21 15:21:30 +01:00
antirez 1a6abe7d79 Sentinel: master address selection in get-master-address refactored. 2013-11-21 15:21:26 +01:00
antirez 0eeb0a0782 Sentinel: fix conditional to only affect slaves with wrong master. 2013-11-21 15:21:21 +01:00
antirez 64c8de8657 Sentinel: simplify and refactor slave reconfig code. 2013-11-21 15:20:56 +01:00
antirez 782f9cacaf Sentinel: reconfigure slaves to right master. 2013-11-21 15:20:44 +01:00
antirez 7dbc0a63f5 Sentinel: remember last time slave changed master. 2013-11-21 15:20:40 +01:00
antirez 612dbb2a91 Sentinel: redirect-to-master is not ok with new algorithm.
Now Sentinel believe the current configuration is always the winner and
should be applied by Sentinels instead of trying to adapt our view of
the cluster based on what we observe.

So the only way to modify what a Sentinel believe to be the truth is to
win an election and advertise the new configuration via Pub / Sub with a
greater configuration epoch.
2013-11-21 15:20:36 +01:00
antirez 4ccf807abc Sentinel: safer slave reconfig, master reported role should match. 2013-11-21 15:20:31 +01:00
antirez e98d82c639 Sentinel: role reporting fixed and added in SENTINEL output. 2013-11-21 15:20:25 +01:00
antirez be19e5450c Sentinel: being a master and reporting as slave is considered SDOWN. 2013-11-21 15:20:20 +01:00
antirez 8c551d65a1 Sentinel: make sure role_reported is always updated. 2013-11-21 15:20:15 +01:00
antirez 9577fed8a3 Sentinel: track role change time. Wait before reconfigurations. 2013-11-21 15:20:11 +01:00
antirez fc10fb17da Sentinel: fix no-down check in master->slave conversion code. 2013-11-21 15:20:07 +01:00
antirez b02ef3d59a Sentinel: readd slaves back after a master reset. 2013-11-21 15:19:56 +01:00
antirez 1a1dc3de38 Sentinel: sentinelResetMaster() new flag to avoid removing set of sentinels.
This commit also removes some dead code and cleanup generic flags.
2013-11-21 15:19:52 +01:00
antirez 9f0e52a13d Sentinel: receive Pub/Sub messages from slaves. 2013-11-21 15:19:49 +01:00
antirez f7604b4c07 Sentinel: change event name when converting master to slave. 2013-11-21 15:19:45 +01:00
antirez 1569326277 Sentinel: added config-epoch to SENTINEL masters output. 2013-11-21 15:19:41 +01:00
antirez 9f20780de6 Sentinel: new failover algo, desync slaves and update config epoch. 2013-11-21 15:19:34 +01:00
antirez 2488257ad8 Sentinel: when starting failover seek for votes ASAP. 2013-11-21 15:19:30 +01:00
antirez 6593f33222 Sentinel: +new-epoch events. 2013-11-21 15:19:26 +01:00
antirez 48acc675dd Sentinel: wait some time between failover attempts. 2013-11-21 15:19:22 +01:00
antirez 447c2787a0 Sentinel: allow to vote for myself. 2013-11-21 15:19:16 +01:00
antirez eba4775b5d Sentinel: fix PUBLISH to masters and slaves. 2013-11-21 15:19:11 +01:00
antirez b95c6ed7b7 Sentinel: epoch introduced in leader vote. 2013-11-21 15:18:52 +01:00
antirez 663d79c0d5 Sentinel: leadership handling changes WIP.
Changes to leadership handling.

Now the leader gets selected by every Sentinel, for a specified epoch,
when the SENTINEL is-master-down-by-addr is sent.

This command now includes the runid and the currentEpoch of the instance
seeking for a vote. The Sentinel only votes a single time in a given
epoch.

Still a work in progress, does not even compile at this stage.
2013-11-21 15:18:45 +01:00
antirez b72985d7f7 Sentinel: handle Hello messages received via slaves correctly.
Even when messages are received via the slave, we should perform
operations (like adding a new Sentinel) in the context of the master.
2013-11-21 15:18:41 +01:00
antirez fe7f96f18c Sentinel: remove code not useful in the new design. 2013-11-21 15:18:36 +01:00
antirez be2ef1b59f Sentinel: epoch introduced.
Sentinel state now includes the idea of current epoch and config epoch.
In the Hello message, that is now published both on masters and slaves,
a Sentinel no longer just advertises itself but also broadcasts its
current view of the configuration: the master name / ip / port and its
current epoch.

Sentinels receiving such information switch to the new master if the
configuration epoch received is newer and the ip / port of the master
are indeed different compared to the previos ones.
2013-11-21 15:18:31 +01:00
antirez 98682cd178 Log to what master a slave is going to connect to. 2013-11-11 09:25:41 +01:00
antirez 68b911478f Fixed typo in release candidate notes. 2013-11-10 10:25:09 +01:00
antirez 875bc51909 Fix broken rdbWriteRaw() return value check in rdb.c.
Thanks to @PhoneLi for reporting.
2013-11-07 23:54:46 +01:00
antirez c874e39c45 Sentinel: sentinelSendSlaveOf() was missing a var and the prototype. 2013-11-06 11:29:57 +01:00
antirez 1767998751 Sentinel: increment pending_commands counter in two more places.
AUTH and SCRIPT KILL were sent without incrementing the pending commands
counter. Clearly this needs some kind of wrapper doing it for the caller
in order to be less bug prone.
2013-11-06 11:29:53 +01:00
antirez 97810c45e8 Sentinel: always send CONFIG REWRITE when changing instance role.
This change makes Sentinel less fragile about a number of failure modes.

This commit also fixes a different bug as a side effect, SLAVEOF command
was sent multiple times without incrementing the pending commands count.
2013-11-06 11:29:49 +01:00
antirez f7f97bf730 Redis 2.7.106 (2.8 Release Candidate 6). 2013-11-06 09:24:26 +01:00
antirez 3a66e0c157 Fixed typo in parseScanCursorOrReply(): ad -> at.
Thanks to @badboy for reporting it.
2013-11-05 17:25:34 +01:00
antirez 060d56e7eb SCAN code refactored to parse cursor first.
The previous implementation of SCAN parsed the cursor in the generic
function implementing SCAN, SSCAN, HSCAN and ZSCAN.

The actual higher-level command implementation only checked for empty
keys and return ASAP in that case. The result was that inverting the
arguments of, for instance, SSCAN for example and write:

    SSCAN 0 key

Instead of

    SSCAN key 0

Resulted into no error, since 0 is a non-existing key name very likely.
Just the iterator returned no elements at all.

In order to fix this issue the code was refactored to extract the
function to parse the cursor and return the error. Every higher level
command implementation now parses the cursor and later checks if the key
exist or not.
2013-11-05 17:25:29 +01:00
antirez 162acd8ac2 SCAN: when iterating ziplists or intsets always return cursor of 0.
The previous implementation assumed that the first call always happens
with cursor set to 0, this may not be the case, and we want to return 0
anyway otherwise the (broken) client code will loop forever.
2013-11-05 17:24:33 +01:00
antirez 406be0ea28 Use strtoul() instead of sscanf() in SCAN implementation. 2013-11-05 17:24:30 +01:00
antirez 4b615eea8f Added tests for [SHZ]SCAN with MATCH. 2013-11-05 17:24:26 +01:00
antirez 54a5a7dff8 HSCAN/ZSCAN: skip value when matching.
This fixes issue #1360 and #1362.
2013-11-05 17:24:22 +01:00
antirez bebbc7f9f7 Pass int64_t to intsetGet() instead of long long. 2013-11-05 17:24:17 +01:00
antirez 736e343509 removed not used vars in dictScan(). 2013-11-05 17:24:12 +01:00
antirez 59b30b327d SCAN: no sdsEncodedObject() API in Redis 2.8. 2013-10-31 18:22:29 +01:00
antirez 3d3e350b12 SSCAN with integer encoded object test improved. 2013-10-31 10:38:56 +01:00
antirez 3cc7d486bc Inverted variable boolean value and name after scanGenericCommand() refactoring. 2013-10-31 10:38:52 +01:00
antirez 06455014aa scanGenericCommand() refactoring and handling of integer encoded elements.
This commit fixes issue #1354.
2013-10-31 10:38:48 +01:00
antirez 141f30f421 Regression test added for [SHZ]SCAN issue #1354. 2013-10-31 10:38:45 +01:00
antirez c53cab5dde Test: added a SCAN test trying to trigger HT resize. 2013-10-30 16:51:48 +01:00
antirez ab6f4195dd Test: added ZSCAN test. 2013-10-30 16:27:43 +01:00
antirez 13e879c9cf Test: added HSCAN test. 2013-10-30 16:27:39 +01:00
antirez 9ea69a58ac Test: added SSCAN test. 2013-10-30 16:27:36 +01:00
antirez bd1962acc4 SCAN test keys sorting turned into more idiomatic Tcl. 2013-10-30 16:27:31 +01:00
antirez 02617b6e92 SCAN: tests moved to unit/scan.tcl. 2013-10-30 16:27:28 +01:00
antirez bb2df795e0 Aesthetic fix (missing space) into HSCAN and ZSCAN implementations.
Thanks to @badboy for reporting.
2013-10-29 16:21:21 +01:00
antirez 35816a2e4d ZSCAN implemented. 2013-10-29 16:21:18 +01:00
antirez 1cc7e646af HSCAN implemented. 2013-10-29 16:21:13 +01:00
antirez 24ecabc995 SSCAN implemented. 2013-10-29 16:21:01 +01:00
antirez 17785f40b5 dictScan(): empty hash table requires special handling. 2013-10-29 16:20:13 +01:00
antirez 7f063b1c8c SCAN is a random command and does not require output sorting.
Sorting the output helps when we want to turn a non-deterministic into a
deterministic command, in that case this is not possible.
2013-10-29 16:20:10 +01:00
antirez 9e62d9e79c SCAN: refactored into scanGenericCommand.
The new implementation is capable of iterating the keyspace but also
sets, hashes, and sorted sets, and can be used to implement SSCAN, ZSCAN
and HSCAN.
2013-10-29 16:20:06 +01:00
antirez 1a06bbe430 Fixed typos in dictScan() comment. 2013-10-29 16:20:02 +01:00
antirez 0880bec4e2 dictScan() algorithm documented. 2013-10-29 16:19:57 +01:00
antirez 1d659784f4 SCAN: stay inside 80 cols. 2013-10-29 16:19:54 +01:00
antirez 854b8be616 Revert "Fixed typo in SCAN comment. iff -> if."
Probably here Pieter means "if and only if".

This reverts commit 43fdf3b404.
2013-10-29 16:19:49 +01:00
antirez 5fa5153bf5 SCAN: simplify keys list cleanup using listSetFreeMethod(). 2013-10-29 16:19:45 +01:00
antirez 108c6e6734 SCAN: Fix test after option renamed from PATTERN to MATCH. 2013-10-29 16:19:41 +01:00
antirez 21da9b06a4 SCAN: improve variable names for readability. 2013-10-29 16:19:37 +01:00
antirez 907e06cd61 SCAN: remove additional newlines to conform to Redis code base. 2013-10-29 16:19:33 +01:00
antirez b44f1589a4 SCAN: remove useless assertion, already enforced by command table. 2013-10-29 16:19:28 +01:00
antirez d1c1f62ed5 SCAN: use define REDIS_LONGSTR_SIZE instead of fixed len. 2013-10-29 16:19:25 +01:00
antirez 8cdaf604ce Fixed typo in SCAN comment. iff -> if. 2013-10-29 16:19:21 +01:00
antirez 33409b4c6c SCAN option name changed: pattern -> match. 2013-10-29 16:19:17 +01:00
Pieter Noordhuis fd22106a98 Fix error in scan algorithm
The irrelevant bits shouldn't be masked to 1. This can result in slots being
skipped when the hash table is resized between calls to the iterator.
2013-10-29 16:19:12 +01:00
Pieter Noordhuis 8c4ff679fe SCAN requires at least 1 argument 2013-10-29 16:19:08 +01:00
Pieter Noordhuis 0dd95e23ab Add SCAN command 2013-10-29 16:18:24 +01:00
antirez 9546f7846b redis-benchmark: update help for new __rand_int__ form. 2013-10-28 18:14:11 +01:00
antirez 508d3c1bb7 Redis 2.7.105 (2.8 Release Candidate 5). 2013-10-09 13:08:42 +02:00
antirez df0c96002d Replication: install the write handler when reusing a cached master.
Sometimes when we resurrect a cached master after a successful partial
resynchronization attempt, there is pending data in the output buffers
of the client structure representing the master (likely REPLCONF ACK
commands).

If we don't reinstall the write handler, it will never be installed
again by addReply*() family functions as they'll assume that if there is
already data pending, the write handler is already installed.

This bug caused some slaves after a successful partial sync to never
send REPLCONF ACK, and continuously being detected as timing out by the
master, with a disconnection / reconnection loop.
2013-10-04 16:14:57 +02:00
antirez d7fa6d9aba Replication: fix master timeout.
Since we started sending REPLCONF ACK from slaves to masters, the
lastinteraction field of the client structure is always refreshed as
soon as there is room in the socket output buffer, so masters in timeout
are detected with too much delay (the socket buffer takes a lot of time
to be filled by small REPLCONF ACK <number> entries).

This commit only counts data received as interactions with a master,
solving the issue.
2013-10-04 13:01:49 +02:00
antirez c8c1006cf4 PSYNC: safer handling of PSYNC requests.
There was a bug that over-esteemed the amount of backlog available,
however this could only happen when a slave was asking for an offset
that was in the "future" compared to the master replication backlog.

Now this case is handled well and logged as an incident in the master
log file.
2013-10-04 12:27:40 +02:00
antirez 81f614ef6f Add REWRITE to CONFIG subcommands help message. 2013-10-04 12:27:36 +02:00
Michel Martens 20c506f432 Document the redis-cli --csv option. 2013-09-26 10:12:51 +02:00
antirez af967ff9cb Allow AUTH / PING when disconnected from slave and serve-stale-data is no. 2013-09-17 09:46:40 +02:00
antirez 2d55f1ca7f redis-cli: fix big keys search when the key no longer exist.
The code freed a reply object that was never created, resulting in a
segfault every time randomkey returned a key that was deleted before we
queried it for size.
2013-09-04 10:37:55 +02:00
Maxim Zakharov 9a0f27a5d0 mistype fixed 2013-09-03 15:15:42 +02:00
Maxim Zakharov c713b1ebdd A mistype fixed 2013-09-03 15:15:34 +02:00
antirez 56ce068664 Redis 2.7.104 (2.8 Release Candidate 4). 2013-08-30 09:52:18 +02:00
antirez 23acf93f97 Test: Lua stack leak regression test added. 2013-08-30 08:59:16 +02:00
antirez 0ea9a20d47 Test: added a memory efficiency test. 2013-08-30 08:48:07 +02:00
antirez 752b1fca90 Fixed critical memory leak from EVAL.
Multiple missing calls to lua_pop prevented the error handler function
pushed on the stack for lua_pcall() to be popped before returning,
causing a memory leak in almost all the code paths of EVAL (both
successful calls and calls returning errors).

This caused two issues: Lua leaking memory (and this was very visible
from INFO memory output, as the 'used_memory_lua' field reported an
always increasing amount of memory used), and as a result slower and
slower GC cycles resulting in all the CPU being used.

Thanks to Tanguy Le Barzic for noticing something was wrong with his 2.8
slave, and for creating a testing EC2 environment where I was able to
investigate the issue.
2013-08-29 11:49:28 +02:00
Salvatore Sanfilippo 3e62d7c308 Merge pull request #1244 from yihuang/2.8
fix lua_cmsgpack pack map as array
2013-08-27 06:15:32 -07:00
antirez a57294b339 Fix an hypothetical issue in processMultibulkBuffer(). 2013-08-27 13:00:14 +02:00
antirez facc5c0661 tryObjectEncoding(): optimize sds strings if possible.
When no encoding is possible, at least try to reallocate the sds string
with one that does not waste memory (with free space at the end of the
buffer) when the string is large enough.
2013-08-27 12:36:09 +02:00
antirez 79a1d335c8 tryObjectEncoding(): don't call stringl2() for too big strings.
We are sure that a string that is longer than 21 chars cannot be
represented by a 64 bit signed integer, as -(2^64) is 21 chars:

strlen(-18446744073709551616) => 21
2013-08-27 12:30:42 +02:00
antirez 0f32c37fc9 Fix DEBUG SDSLEN after 2.8 back port. 2013-08-27 12:26:02 +02:00
antirez df21771c69 Don't over-allocate the sds string for large bulk requests.
The call to sdsMakeRoomFor() did not accounted for the amount of data
already present in the query buffer, resulting into over-allocation.
2013-08-27 12:22:12 +02:00
antirez f05b1f6889 DEBUG SDSLEN added.
This command is only useful for low-level debugging of memory issues due
to sds wasting memory as empty buffer at the end of the string.
2013-08-27 12:22:07 +02:00
antirez 9c3e6c3aa0 Update server.lastbgsave_status when fork() fails. 2013-08-27 10:16:25 +02:00
antirez 9df63fcabf Only run the fast active expire cycle if master & enabled. 2013-08-27 09:31:43 +02:00
antirez f5903846bc Opening TCP listening ports refactored into a function. 2013-08-22 14:06:54 +02:00
antirez bd6327855b Print error message when can't bind * on any address. 2013-08-22 13:03:07 +02:00
antirez 2c94d80f58 Fix for issue #1214 simplified. 2013-08-21 11:41:35 +02:00
Allan 778f753deb fixed initServer fail while having no IPv6 nor IPv4 2013-08-21 11:41:30 +02:00
Allan 6c2b34a465 fixed initServer failed if no IPV4 or no IPV6 2013-08-21 11:41:25 +02:00
Allan 0a4656d63f fixed bug issue of #1213 2013-08-21 11:41:21 +02:00
antirez 7c861340b1 Use printf %zu specifier to print private_dirty. 2013-08-20 12:09:36 +02:00
antirez 2c018b14fb dictFingerprint(): cast pointers to integer of same size. 2013-08-20 12:09:31 +02:00
antirez 6a88a84ec7 Redis 2.7.103 (2.8 Release Candidate 3). 2013-08-19 18:04:32 +02:00
antirez 5621272575 Revert "Fixed type in dict.c comment: 265 -> 256."
This reverts commit 009515f914.
2013-08-19 17:25:57 +02:00
antirez 009515f914 Fixed type in dict.c comment: 265 -> 256. 2013-08-19 15:11:07 +02:00
antirez 837817b2b7 assert.h replaced with redisassert.h when appropriate.
Also a warning was suppressed by including unistd.h in redisassert.h
(needed for _exit()).
2013-08-19 15:02:16 +02:00
antirez bd353d9a3c Added redisassert.h as drop in replacement for assert.h.
By using redisassert.h version of assert() you get stack traces in the
log instead of a process disappearing on assertions.
2013-08-19 15:02:13 +02:00
antirez c7da5fc6c1 dictFingerprint() fingerprinting made more robust.
The previous hashing used the trivial algorithm of xoring the integers
together. This is not optimal as it is very likely that different
hash table setups will hash the same, for instance an hash table at the
start of the rehashing process, and at the end, will have the same
fingerprint.

Now we hash N integers in a smarter way, by summing every integer to the
previous hash, and taking the integer hashing again (see the code for
further details). This way it is a lot less likely that we get a
collision. Moreover this way of hashing explicitly protects from the
same set of integers in a different order to hash to the same number.

This commit is related to issue #1240.
2013-08-19 15:02:10 +02:00
antirez 8368550733 Fix comments for correctness in zunionInterGenericCommand().
Related to issue #1240.
2013-08-19 15:02:06 +02:00
antirez 3ad87c652b Properly init/release iterators in zunionInterGenericCommand().
This commit does mainly two things:

1) It fixes zunionInterGenericCommand() by removing mass-initialization
of all the iterators used, so that we don't violate the unsafe iterator
API of dictionaries. This fixes issue #1240.

2) Since the zui* APIs required the allocator to be initialized in the
zsetopsrc structure in order to use non-iterator related APIs, this
commit fixes this strict requirement by accessing objects directly via
the op->subject->ptr pointer we have to the object.
2013-08-19 15:02:02 +02:00
antirez 05379f49ee dict.c iterator API misuse protection.
dict.c allows the user to create unsafe iterators, that are iterators
that will not touch the dictionary data structure in any way, preventing
copy on write, but at the same time are limited in their usage.

The limitation is that when itearting with an unsafe iterator, no call
to other dictionary functions must be done inside the iteration loop,
otherwise the dictionary may be incrementally rehashed resulting into
missing elements in the set of the elements returned by the iterator.

However after introducing this kind of iterators a number of bugs were
found due to misuses of the API, and we are still finding
bugs about this issue. The bugs are not trivial to track because the
effect is just missing elements during the iteartion.

This commit introduces auto-detection of the API misuse. The idea is
that an unsafe iterator has a contract: from initialization to the
release of the iterator the dictionary should not change.

So we take a fingerprint of the dictionary state, xoring a few important
dict properties when the unsafe iteartor is initialized. We later check
when the iterator is released if the fingerprint is still the same. If it
is not, we found a misuse of the iterator, as not allowed API calls
changed the internal state of the dictionary.

This code was checked against a real bug, issue #1240.

This is what Redis prints (aborting) when a misuse is detected:

Assertion failed: (iter->fingerprint == dictFingerprint(iter->d)),
function dictReleaseIterator, file dict.c, line 587.
2013-08-19 15:01:58 +02:00
yihuang 706056ca16 fix lua_cmsgpack pack map as array 2013-08-13 17:48:40 +08:00
antirez 14a1cba3e3 Use precomptued objects for bulk and mbulk prefixes. 2013-08-12 12:43:26 +02:00
antirez 004f00bfa4 replicationFeedSlaves() func name typo: feedReplicationBacklogWithObject -> feedReplicationBacklog. 2013-08-12 12:38:52 +02:00
antirez 45d4e06e93 replicationFeedSlave() reworked for correctness and speed.
The previous code using a static buffer as an optimization was lame:

1) Premature optimization, actually it was *slower* than naive code
   because resulted into the creation / destruction of the object
   encapsulating the output buffer.
2) The code was very hard to test, since it was needed to have specific
   tests for command lines exceeding the size of the static buffer.
3) As a result of "2" the code was bugged as the current tests were not
   able to stress specific corner cases.

It was replaced with easy to understand code that is safer and faster.
2013-08-12 12:31:20 +02:00
antirez 3eab283b65 Fix a PSYNC bug caused by a variable name typo. 2013-08-12 11:51:03 +02:00
antirez 0e72cc601f Fix sdsempty() prototype in sds.h. 2013-08-12 11:38:28 +02:00
antirez 689829f2e1 redis-benchmark: changes to random arguments substitution.
Before this commit redis-benchmark supported random argumetns in the
form of :rand:000000000000. In every string of that form, the zeros were
replaced with a random number of 12 digits at every command invocation.

However this was far from perfect as did not allowed to generate simply
random numbers as arguments, there was always the :rand: prefix.

Now instead every argument in the form __rand_int__ is replaced with a
12 digits number. Note that "__rand_int__" is 12 characters itself.

In order to implement the new semantic, it was needed to change a few
thigns in the internals of redis-benchmark, as new clients are created
cloning old clients, so without a stable prefix such as ":rand:" the old
way of cloning the client was no longer able to understand, from the old
command line, what was the position of the random strings to substitute.

Now instead a client structure is passed as a reference for cloning, so
that we can directly clone the offsets inside the command line.
2013-08-08 16:47:18 +02:00
antirez 4fe67cc103 redis-benchmark: replace snprintf()+memcpy with faster code.
This change was profiler-driven, but the actual effect is hard to
measure in real-world redis benchmark runs.
2013-08-08 14:31:54 +02:00
Jan-Erik Rediger a256b83448 Little typo 2013-08-07 16:09:33 +02:00
antirez a79862de2a redis-benchmark: fix memory leak introduced by 346256f 2013-08-07 16:09:13 +02:00
antirez bcc7965931 redis-benchmark: max pipeline length hardcoded limit removed. 2013-08-07 16:09:09 +02:00
antirez 46c1bafeab redis-benchmark: fix db selection when :rand: feature is used. 2013-08-07 11:22:33 +02:00
antirez 151ad68540 redis-benchmark: ability to SELECT a specifid db number. 2013-08-07 11:22:28 +02:00
antirez fa48b1fa32 Add per-db average TTL information in INFO output.
Example:

db0:keys=221913,expires=221913,avg_ttl=655

The algorithm uses a running average with only two samples (current and
previous). Keys found to be expired are considered at TTL zero even if
the actual TTL can be negative.

The TTL is reported in milliseconds.
2013-08-06 15:36:43 +02:00
antirez 31d0f34100 activeExpireCycle(): fix about fast cycle early start.
We don't want to repeat a fast cycle too soon, the previous code was
broken, we need to wait two times the period *since* the start of the
previous cycle in order to avoid there is an even space between cycles:

.-> start                   .-> second start
|                           |
+-------------+-------------+--------------+
| first cycle |    pause    | second cycle |
+-------------+-------------+--------------+

The second and first start must be PERIOD*2 useconds apart hence the *2
in the new code.
2013-08-06 15:36:39 +02:00
antirez 00c8cfef74 Some activeExpireCycle() refactoring. 2013-08-06 15:36:35 +02:00
antirez 8686a70303 Remove dead code and fix comments for new expire code. 2013-08-06 15:36:31 +02:00
antirez d54e373b84 Darft #2 for key collection algo: more improvements.
This commit makes the fast collection cycle time configurable, at
the same time it does not allow to run a new fast collection cycle
for the same amount of time as the max duration of the fast
collection cycle.
2013-08-06 15:36:27 +02:00
antirez 500155b91b Draft #1 of a new expired keys collection algorithm.
The main idea here is that when we are no longer to expire keys at the
rate the are created, we can't block more in the normal expire cycle as
this would result in too big latency spikes.

For this reason the commit introduces a "fast" expire cycle that does
not run for more than 1 millisecond but is called in the beforeSleep()
hook of the event loop, so much more often, and with a frequency bound
to the frequency of executed commnads.

The fast expire cycle is only called when the standard expiration
algorithm runs out of time, that is, consumed more than
REDIS_EXPIRELOOKUPS_TIME_PERC of CPU in a given cycle without being able
to take the number of already expired keys that are yet not collected
to a number smaller than 25% of the number of keys.

You can test this commit with different loads, but a simple way is to
use the following:

Extreme load with pipelining:

redis-benchmark -r 100000000 -n 100000000  \
        -P 32 set ele:rand:000000000000 foo ex 2

Remove the -P32 in order to avoid the pipelining for a more real-world
load.

In another terminal tab you can monitor the Redis behavior with:

redis-cli -i 0.1 -r -1 info keyspace

and

redis-cli --latency-history

Note: this commit will make Redis printing a lot of debug messages, it
is not a good idea to use it in production.
2013-08-06 15:36:23 +02:00
antirez cc94697284 Redis 2.7.102 (2.8 Release Candidate 2). 2013-07-30 20:20:02 +02:00
antirez f8e43aba78 Test: regression test for issue #1221. 2013-07-29 17:40:18 +02:00
antirez 13f7ade551 Fix replicationFeedSlaves() off-by-one bug.
This fixes issue #1221.
2013-07-28 12:50:35 +02:00
antirez 78644f5e3e Remove dead variable bothsds from object.c.
Thanks to @run and @badboy for spotting this.
Triva: clang was not able to provide me a warning about that when
compiling.

This closes #1024 and #1207, committing the change myself as the pull
requests no longer apply cleanly after other changes to the same
function.
2013-07-28 11:02:20 +02:00
antirez aea8020554 Use latest sds.c in the hiredis library under deps. 2013-07-25 10:34:02 +02:00
antirez c3e1724a57 Ignore sdsrange return value. 2013-07-24 18:59:36 +02:00
antirez f899ab55ca sdsrange() does not need to return a value.
Actaully the string is modified in-place and a reallocation is never
needed, so there is no need to return the new sds string pointer as
return value of the function, that is now just "void".
2013-07-24 11:22:52 +02:00
antirez a1d37ba469 Inline protocol improved to accept quoted strings. 2013-07-24 10:38:05 +02:00
antirez 57c8e026b9 Every function inside sds.c is now commented. 2013-07-23 16:36:14 +02:00
antirez f3b44f291d Merge remote-tracking branch 'origin/2.8' into 2.8 2013-07-19 14:55:49 +02:00
antirez 5d0ad2f983 Fixed typo in 2.8 release notes. 2013-07-18 16:10:31 +02:00
Salvatore Sanfilippo 349f6349be Merge pull request #1203 from ronnix/patch-1
Fix a few typos in release notes
2013-07-18 03:27:41 -07:00
Ronan Amicel 5b19e9d433 Fix a few typos in release notes 2013-07-18 12:23:47 +02:00
antirez 3cb3714e99 Redis 2.7.101 (2.8 Release Candidate 1). 2013-07-18 11:26:53 +02:00
antirez a50635bb6c addReplyDouble(): format infinite in a libc agnostic way.
There are systems that when printing +/- infinte with printf-family
functions will not use the usual "inf" "-inf", but different strings.
Handle that explicitly.

Fixes issue #930.
2013-07-17 15:04:22 +02:00
antirez 2e449d42e0 Fixed typo in rio.h, simgle -> single. 2013-07-16 15:43:41 +02:00
yoav 9f6f436a51 Chunked loading of RDB to prevent redis from stalling reading very large keys. 2013-07-16 15:41:59 +02:00
antirez 112e763618 Make sure that ZADD can accept the full range of double values.
This fixes issue #1194, that contains many details.

However in short, it was possible for ZADD to not accept as score values
that was however possible to obtain with multiple calls to ZINCRBY, like
in the following example:

redis 127.0.0.1:6379> zadd k 2.5e-308 m
(integer) 1
redis 127.0.0.1:6379> zincrby k -2.4e-308 m
"9.9999999999999694e-310"
redis 127.0.0.1:6379> zscore k m
"9.9999999999999694e-310"
redis 127.0.0.1:6379> zadd k 9.9999999999999694e-310 m1
(error) ERR value is not a valid float

The problem was due to strtod() returning ERANGE in the following case
specified by POSIX:

"If the correct value would cause an underflow, a value whose magnitude
is no greater than the smallest normalized positive number in the return
type shall be returned and errno set to [ERANGE].".

Now instead the returned value is accepted even when ERANGE is returned
as long as the return value of the function is not negative or positive
HUGE_VAL or zero.
2013-07-16 15:08:57 +02:00
Ted Nyman fe04710908 Make sure the log standardizes on 'timeout' 2013-07-12 23:12:27 +02:00
antirez 98757b4a6e Use the environment locale for strcoll() collation. 2013-07-12 13:39:48 +02:00
antirez 18fabeb264 SORT ALPHA: use collation instead of binary comparison.
Note that we only do it when STORE is not used, otherwise we want an
absolutely locale independent and binary safe sorting in order to ensure
AOF / replication consistency.

This is probably an unexpected behavior violating the least surprise
rule, but there is currently no other simple / good alternative.
2013-07-12 13:39:44 +02:00
antirez d8fcbb6645 Fixed compareStringObject() and introduced collateStringObject().
compareStringObject was not always giving the same result when comparing
two exact strings, but encoded as integers or as sds strings, since it
switched to strcmp() when at least one of the strings were not sds
encoded.

For instance the two strings "123" and "123\x00456", where the first
string was integer encoded, would result into the old implementation of
compareStringObject() to return 0 as if the strings were equal, while
instead the second string is "greater" than the first in a binary
comparison.

The same compasion, but with "123" encoded as sds string, would instead
return a value < 0, as it is correct. It is not impossible that the
above caused some obscure bug, since the comparison was not always
deterministic, and compareStringObject() is used in the implementation
of skiplists, hash tables, and so forth.

At the same time, collateStringObject() was introduced by this commit, so
that can be used by SORT command to return sorted strings usign
collation instead of binary comparison. See next commit.
2013-07-12 13:39:40 +02:00
Jan-Erik Rediger 1bcbb7a90c Wrap IPv6 in brackets in the prompt. 2013-07-12 10:58:47 +02:00
antirez 1e23848ed3 Sentinel: embed IPv6 address into [] when naming slave/sentinel instance. 2013-07-11 17:10:09 +02:00
antirez 076f6395b9 Sentinel: use comma as separator to publish hello messages.
We use comma to play well with IPv6 addresses, but the implementation is
still able to parse the old messages separated by colons.
2013-07-11 17:09:44 +02:00
antirez 4cfd70e903 hiredis: minimal IPv6 support. 2013-07-11 17:09:35 +02:00
antirez 98d0abcecd Sentinel: make sure published addr/id buffer is large enough.
With ipv6 support we need more space, so we account for the IP address
max size plus what we need for the Run ID, port, flags.
2013-07-11 17:09:30 +02:00
antirez 8669e70921 anet.c: save some vertical space. 2013-07-11 17:09:25 +02:00
antirez 9e089e7c5d anet.c: use SO_REUSEADDR when creating listening sockets.
It used to be ok, but the socket option was removed when adding IPv6
support.
2013-07-11 17:09:22 +02:00
antirez cdf801d92e Use getClientPeerId() for MONITOR implementation. 2013-07-11 17:09:18 +02:00
antirez 3472d045d8 getClientPeerId() refactored into two functions. 2013-07-11 17:09:14 +02:00
antirez da18366609 getClientPeerId() now reports errors.
We now also use it in CLIENT KILL implementation.
2013-07-11 17:09:10 +02:00
antirez 4fa68b2815 getClientPeerID introduced.
The function returns an unique identifier for the client, as ip:port for
IPv4 and IPv6 clients, or as path:0 for Unix socket clients.

See the top comment in the function for more info.
2013-07-11 17:09:04 +02:00
antirez a7451c1b6d All IP string repr buffers are now REDIS_IP_STR_LEN bytes. 2013-07-11 17:07:52 +02:00
antirez 2e75d3947c IPv6: bind IPv4 and IPv6 interfaces by default. 2013-07-11 17:07:41 +02:00
antirez b5423b099c Fix old anetPeerToString() API call in replication.c 2013-07-11 17:07:38 +02:00
antirez 1e7949227c Revert "Document port6 and bind6 config options."
IPv6 support is not going to use IPv6 specific options, just it will be
possible to specify all the ipv4 / ipv6 addresses of the interfaces to
bind, otherwise connections will be accepted from all the interfaces in
both IPv4 and IPv6 addresses.

This reverts commit 93570e179e.
2013-07-11 17:07:34 +02:00
Geoff Garside 0d8f254359 Add IPv6 support to sentinel.c.
This has been done by exposing the anetSockName() function anet.c
to be used when the sentinel is publishing its existence to the masters.

This implementation is very unintelligent as it will likely break if used
with IPv6 as the nested colons will break any parsing of the PUBLISH string
by the master.
2013-07-11 17:07:31 +02:00
Geoff Garside 5938126c98 Cleanup main() and BACKTRACE mistaken pulled while rebasing. 2013-07-11 17:07:27 +02:00
Geoff Garside d3bf85423a Fix calls to anetPeerToString() missing buffer size. 2013-07-11 17:07:22 +02:00
Geoff Garside 47620a3186 Document port6 and bind6 config options.
Add commented port6 and bind6 options to default redis.conf file.
2013-07-11 17:07:18 +02:00
Geoff Garside fd8a6ae7a6 Add anetTcp6Server() function.
Refactor the common code from anetTcpServer into internal function which
can be used by both anetTcpServer and anetTcp6Server.
2013-07-11 17:07:13 +02:00
Geoff Garside f638236902 Add static anetV6Only() function.
This function sets the IPV6_V6ONLY option to 1 to use separate stack
IPv6 sockets.
2013-07-11 17:07:07 +02:00
Geoff Garside 71795d4e7e Change anetTcpGenericConnect to use AF_UNSPEC.
This allows anetTcpGenericConnect to try to connect to AF_INET6
addresses in addition to any resolved AF_INET addresses.
2013-07-11 17:07:03 +02:00
Geoff Garside d37d006cd2 Mark places that might want changing for IPv6.
Any places which I feel might want to be updated to work differently
with IPv6 have been marked with a comment starting "IPV6:".

Currently the only comments address places where an IP address is
combined with a port using the standard : separated form. These may want
to be changed when printing IPv6 addresses to wrap the address in []
such as

	[2001:db8::c0:ffee]:6379

instead of

	2001:db8::c0:ffee:6379

as the latter format is a technically valid IPv6 address and it is hard
to distinguish the IPv6 address component from the port unless you know
the port is supposed to be there.
2013-07-11 17:06:55 +02:00
Geoff Garside 57e2b23dfb Expand ip char buffers which are too small for v6.
Increase the size of character buffers being used to store printable IP
addresses so that they can safely store IPv6 addresses.
2013-07-11 17:06:43 +02:00
Geoff Garside 39d57c057f Mark ip string buffers which could be reduced.
In two places buffers have been created with a size of 128 bytes which
could be reduced to INET6_ADDRSTRLEN to still hold a full IP address.
These places have been marked as they are presently big enough to handle
the needs of storing a printable IPv6 address.
2013-07-11 17:06:35 +02:00
Geoff Garside f1151f869e Update anetPeerToString to handle AF_INET6 addrs.
Change the sockaddr_in to sockaddr_storage which is capable of storing
both AF_INET and AF_INET6 sockets. Uses the sockaddr_storage ss_family
to correctly return the printable IP address and port.
2013-07-11 17:05:21 +02:00
Geoff Garside fefa14914e Update anetTcpAccept to handle AF_INET6 addresses.
Change the sockaddr_in to sockaddr_storage which is capable of storing
both AF_INET and AF_INET6 sockets. Uses the sockaddr_storage ss_family
to correctly return the printable IP address and port.
2013-07-11 17:05:16 +02:00
Geoff Garside 77ddec8582 Update anetResolve to resolve AF_INET6 as well.
Change the getaddrinfo(3) hints family from AF_INET to AF_UNSPEC to
allow resolution of IPv6 addresses as well as IPv4 addresses. The
function will return the IP address of whichever address family is
preferenced by the operating system. Most current operating systems
will preference AF_INET6 over AF_INET.

Unfortunately without attempting to establish a connection to the
remote address we can't know if the host is capable of using the
returned IP address. It might be desirable to have anetResolve
accept an additional argument specifying the AF_INET/AF_INET6 address
the caller would like to receive. Currently though it does not appear
as though the anetResolve function is ever used within Redis.
2013-07-11 17:05:12 +02:00
Geoff Garside 4b2e374e4a Update calls to anetResolve to include buffer size 2013-07-11 17:05:08 +02:00
Geoff Garside 3570411def Update calls to anetPeerToString to include ip_len. 2013-07-11 17:05:03 +02:00
Geoff Garside 68d72aa5b1 Add macro to define clusterNode.ip buffer size.
Add REDIS_CLUSTER_IPLEN macro to define the size of the clusterNode ip
character array. Additionally use this macro in inet_ntop(3) calls where
the size of the array was being defined manually.

The REDIS_CLUSTER_IPLEN is defined as INET_ADDRSTRLEN which defines the
correct size of a buffer to store an IPv4 address in. The
INET_ADDRSTRLEN macro itself is defined in the <netinet/in.h> header
file and should be portable across the majority of systems.
2013-07-11 17:04:32 +02:00
Geoff Garside 30836721f2 Update anetTcpAccept & anetPeerToString calls.
Add the additional ip buffer length argument to function calls of
anetTcpAccept and anetPeerToString in network.c and cluster.c
2013-07-11 17:02:29 +02:00
Geoff Garside 920ab4c926 Use inet_ntop(3) in anet. #apichange
Replace inet_ntoa(3) calls with the more future proof inet_ntop(3)
function which is capable of handling additional address families.

API Change: anetTcpAccept() & anetPeerToString() additional argument
  additional argument required to specify the length of the character
  buffer the IP address is written to in order to comply with
  inet_ntop(3) function semantics.
2013-07-11 17:02:12 +02:00
Geoff Garside aee5ee70fa Use getaddrinfo(3) in a anetTcpServer.
Change anetTcpServer() function to use getaddrinfo(3) to perform
address resolution, socket creation and binding. Resolved addresses
are limited to those reachable by the AF_INET address family.
2013-07-11 17:02:08 +02:00
Geoff Garside e50f2c93bc Use getaddrinfo(3) in anetTcpGenericConnect.
Change anetTcpGenericConnect() function to use getaddrinfo(3) to
perform address resolution, socket creation and connection. Resolved
addresses are limited to those reachable by the AF_INET family.
2013-07-11 17:02:04 +02:00
Geoff Garside d36dc1fc82 Add anetSetReuseAddr(err, fd) static function.
Extract setting SO_REUSEADDR socket option into separate function
so the same code can be more easily used by anetCreateSocket and
other functions.
2013-07-11 17:01:59 +02:00
Geoff Garside 855ff8df9f Use getaddrinfo(3) in anetResolve. #apichange
Change anetResolve() function to use getaddrinfo(3) to resolve hostnames.
Resolved hostnames are limited to those reachable by the AF_INET address
family.

API Change: anetResolve requires additional argument.
  additional argument required to specify the length of the character
  buffer the IP address is written to in order to comply with
  inet_ntop(3) function semantics. inet_ntop(3) replaces inet_ntoa(3)
  as it has been designed to be compatible with more address families.
2013-07-11 17:01:55 +02:00
antirez 33c5f0a243 Example redis.conf: bind to multiple interfaces documented. 2013-07-08 10:42:37 +02:00
antirez 323e5e2058 Remove cluster stuff from closeListeningSockets() for 2.8. 2013-07-08 10:31:49 +02:00
antirez fc022ca300 Binding multiple IPs done properly with multiple sockets. 2013-07-08 10:30:54 +02:00
antirez 00063bea33 Revert "anet.c: Allow creation of TCP listening sockets bound to N addresses."
Bind() can't be called multiple times against the same socket, multiple
sockets are required to bind multiple interfaces, silly me.

This reverts commit bd234d62bb.
2013-07-08 10:28:02 +02:00
antirez 6dabd34ad0 Ability to bind multiple addresses. 2013-07-08 10:27:21 +02:00
antirez 14857decfa anet.c: Allow creation of TCP listening sockets bound to N addresses. 2013-07-08 10:25:51 +02:00
antirez 2150cfebb7 sds.c: new function sdsjoin() to join strings. 2013-07-08 10:25:47 +02:00
antirez 3e3501262b redis-cli: introduced --pipe-timeout.
When in --pipe mode, after all the data transfer to the server is
complete, now redis-cli waits at max the specified amount of
seconds (30 by default, use 0 to wait forever) without receiving any
reply at all from the server. After this time limit the operation is
aborted with an error.

That's related to issue #681.
2013-07-03 12:18:55 +02:00
antirez 24b3799238 redis-cli --pipe: send final ECHO in a safer way.
If the protocol read from stdin happened to contain grabage (invalid
random chars), in the previous implementation it was possible to end
with something like:

dksfjdksjflskfjl*2\r\n$4\r\nECHO....

That is invalid as the *2 should start into a new line. Now we prefix
the ECHO with a CRLF that has no effects on the server but prevents this
issues most of the times.

Of course if the offending wrong sequence is something like:

$3248772349\r\n

No one is going to save us as Redis will wait for data in the context of
a big argument, so this fix does not cover all the cases.

This partially fixes issue #681.
2013-07-03 12:02:09 +02:00
antirez 2f6560f351 pqsort.c: remove the "switch to insertion sort" optimization.
It causes catastrophic performance for certain inputs.

Relevant NetBSD commit:

http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/qsort.c?rev=1.20&content-type=text/x-cvsweb-markup&only_with_tag=MAIN

This fixes issue #968.
2013-07-02 17:48:49 +02:00
charsyam 847a40805f fix randstring bug 2013-07-02 12:25:30 +02:00
antirez aaf5623535 Only allow basenames for dbfilename and appendfilename.
This fixes issue #1094.
2013-07-02 12:24:12 +02:00
antirez 25a3ad7f74 pathIsBaseName() added to utils.c
The function is used to test that the specified string looks like just
as the basename of a path, without any absolute or relative path.
2013-07-02 12:24:08 +02:00
antirez 028fdbb70b getAbsolutePath() moved into utils.c 2013-07-02 12:24:05 +02:00
antirez 8090c37f71 CONFIG SET maxclients. 2013-07-01 10:44:08 +02:00
antirez 75dc48f04a ae.c event loop: API to resize the fd set size on the run. 2013-07-01 10:44:04 +02:00
antirez 0a0fd37e5b Allow SHUTDOWN in loading state. 2013-06-27 12:14:23 +02:00
antirez 7bfbc38068 Redis 2.7.3 2013-06-26 15:26:11 +02:00
antirez bb0d0fd479 function renamed: popcount_binary -> redisPopcount. 2013-06-26 15:24:58 +02:00
antirez cdf79c063f Don't disconnect pre PSYNC replication clients for timeout.
Clients using SYNC to replicate are older implementations, such as
redis-cli --slave, and are not designed to acknowledge the master with
REPLCONF ACK commands, so we don't have any feedback and should not
disconnect them on timeout.
2013-06-26 15:24:30 +02:00
antirez 7cca200603 Test: add some AOF testing to EVALSHA replication test. 2013-06-26 15:24:26 +02:00
antirez 29308077a8 Flush the replication script cache after SCRIPT FLUSH. 2013-06-26 15:24:22 +02:00
antirez 9faa6b9dc3 Test: EVALSHA replication. 2013-06-26 15:24:19 +02:00
antirez b0e0f3c5b2 Test: randomInt() behavior commented. 2013-06-26 15:24:16 +02:00
antirez 4e2b97bb89 Test: replication-3 test speedup in master-slave setup. 2013-06-26 15:24:12 +02:00
antirez d34c1ac208 Force propagation of SCRIPT LOAD to AOF. 2013-06-26 15:24:09 +02:00
antirez b7233f40fb SCRIPT FLUSH comment minor pedantic improvement. 2013-06-26 15:24:04 +02:00
antirez 8450d6e24d Move Replication Script Cache initialization in safer place.
It should be called just one time at startup and not every time the Lua
scripting engine is re-initialized, otherwise memory is leaked.
2013-06-26 15:23:52 +02:00
antirez 545fe0c318 Use the RSC to replicate EVALSHA unmodified.
This commit uses the Replication Script Cache in order to avoid
translating EVALSHA into EVAL whenever possible for both the AOF and
slaves.
2013-06-26 15:23:29 +02:00
antirez 9d894b1b8c Replication of scripts as EVALSHA: sha1 caching implemented.
This code is only responsible to take an LRU-evicted fixed length cache
of SHA1 that we are sure all the slaves received.

In this commit only the implementation is provided, but the Redis core
does not use it to actually send EVALSHA to slaves when possible.
2013-06-26 15:23:15 +02:00
antirez 8328d993e1 New API to force propagation.
The old REDIS_CMD_FORCE_REPLICATION flag was removed from the
implementation of Redis, now there is a new API to force specific
executions of a command to be propagated to AOF / Replication link:

    void forceCommandPropagation(int flags);

The new API is also compatible with Lua scripting, so a script that will
execute commands that are forced to be propagated, will also be
propagated itself accordingly even if no change to data is operated.

As a side effect, this new design fixes the issue with scripts not able
to propagate PUBLISH to slaves (issue #873).
2013-06-26 15:21:55 +02:00
antirez aeab473dfb Allow PUBSUB NUMSUB without channels.
The result is an empty list but it is handy to call it programmatically.
2013-06-26 15:21:12 +02:00
antirez a8f1474dfd PUBSUB command implemented.
Currently it implements three subcommands:

PUBSUB CHANNELS [<pattern>]    List channels with non-zero subscribers.
PUBSUB NUMSUB [channel_1 ...]  List number of subscribers for channels.
PUBSUB NUMPAT                  Return number of subscribed patterns.
2013-06-26 15:21:08 +02:00
antirez 72d3fbea65 Fix comment typo in integration/aof.tcl. 2013-06-26 15:21:05 +02:00
YAMAMOTO Takashi 3642557ae6 don't assume time_t == long
time_t is always 64bit on recent versions of NetBSD.
2013-06-26 15:20:59 +02:00
YAMAMOTO Takashi 30f3ae03a5 use nanosleep instead of usleep
SUSv3 says that:
	The useconds argument shall be less than one million. If the value of
	useconds is 0, then the call has no effect.
and actually NetBSD's implementation rejects such a value with EINVAL.
use nanosleep which has no such a limitation instead.
2013-06-26 15:20:56 +02:00
YAMAMOTO Takashi f27896a17d rename popcount to popcount_binary to avoid a conflict with NetBSD libc
NetBSD-current's libc has a function named popcount.
hiding these extensions using feature macros is not possible because
redis uses other extensions covered by the same feature macro.
eg. inet_aton
2013-06-26 15:20:32 +02:00
YAMAMOTO Takashi 9a7b09ed35 don't define _XOPEN_SOURCE for NetBSD
on NetBSD, defining _XOPEN_SOURCE hides extensions
like inet_aton, strcasecmp, etc.
2013-06-26 15:20:03 +02:00
Jan-Erik Rediger 90c3a14ac0 Initialize char* to NULL to remove compiler warning 2013-06-20 16:59:04 +02:00
antirez 9af8125c7d Sentinel: parse new INFO replication output correctly.
Sentinel was not able to detect slaves when connected to a very recent
version of Redis master since a previos non-backward compatible change
to INFO broken the parsing of the slaves ip:port INFO output.

This fixes issue #1164
2013-06-20 10:24:31 +02:00
antirez be8d5fd954 Test: regression test for #1163. 2013-06-19 18:53:14 +02:00
antirez 86147afd08 Allow writes from scripts called by AOF loading in read-only slaves.
This fixes issue #1163
2013-06-19 18:29:05 +02:00
antirez 449ec38fe4 Fix logStackTrace() when logging to stdout.
When the semantics changed from logfile = NULL to logfile = "" to log
into standard output, no proper change was made to logStackTrace() to
make it able to work with the new setup.

This commit fixes the issue.
2013-06-19 14:45:38 +02:00
antirez bf8e078aa2 Lua script errors format more unified.
lua_pcall error handler now formats errors in a way more similar to
luaPushError() so that errors generated in different contexts look alike.
2013-06-18 19:38:23 +02:00
antirez b3fbc84cc1 Lua scripting: improve error reporting.
When calling Lua scripts we try to report not just the error but
information about the code line causing the error.
2013-06-18 19:38:19 +02:00
Marc-Antoine Perennou 1cf839a216 test-server: only listen to 127.0.0.1
Signed-off-by: Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
2013-06-18 19:38:16 +02:00
ioddly e34f00842f Try to report source of bad Lua API calls 2013-06-18 19:38:10 +02:00
antirez b435817b17 Binary safe dump of object content in redisLogObjectDebugInfo(). 2013-06-04 15:55:35 +02:00
antirez 054632f551 CONFIG SET: accept slave-priority zero, it is valid. 2013-05-31 19:31:51 +02:00
antirez d34c623e10 Test: avoid a false positive in min-slaves test. 2013-05-31 11:43:23 +02:00
antirez fe4b62fcaf Refresh good slaves count after CONFIG SET min-slaves-...
This way just after the CONFIG SET enabling the min-slaves feature it is
possible to write to the database without delays.
2013-05-31 07:20:19 +02:00
antirez 971217c7b4 New INFO field "min_slaves_good_slaves".
When min-slaves-to-write feature is active, this field reports the
number of slaves considered good (online state, lag within the specified
range).
2013-05-31 07:19:45 +02:00
antirez f5275da6e9 Refresh good slaves count when setting slave state as online. 2013-05-31 07:19:42 +02:00
antirez 9a7ea3dae9 Tests added for min-slaves feature. 2013-05-30 18:54:39 +02:00
antirez 4333e6ce20 Make tests compatible with new INFO replication output. 2013-05-30 11:43:53 +02:00
antirez 9d1bc3efcf min-replicas-to-write: only deny write commands.
I guess I needed another coffee...
2013-05-30 11:32:00 +02:00
antirez d0d67f8d42 min-slaves-to-write: don't accept writes with less than N replicas.
This feature allows the user to specify the minimum number of
connected replicas having a lag less or equal than the specified
amount of seconds for writes to be accepted.
2013-05-30 11:31:46 +02:00
antirez fc2587ec6e min-slaves-to-write: initial description of the feature in redis.conf 2013-05-30 11:30:34 +02:00
antirez 75fcf5c936 repl_offset field in INFO replication is now just offset. 2013-05-29 19:56:40 +02:00
antirez c64338aa8f Slaves list in INFO output: lag added, format changed.
There is a new 'lag' information in the list of slaves, in the
"replication" section of the INFO output.

Also the format was changed in a backward incompatible way in order to
make it more easy to parse if new fields are added in the future, as the
new format is comma separated but has named fields (no longer positional
fields).
2013-05-29 19:55:11 +02:00
antirez 889d39b5ba Accept REPLCONF in any state. 2013-05-28 15:26:55 +02:00
antirez 1b87b3ef38 A comment about BLPOP timeout did not reflected actual behavior. 2013-05-27 19:34:12 +02:00
antirez 2d497014ea Version bumped to 2.7.2. 2013-05-27 11:43:47 +02:00
antirez 75bf91abea redis.conf updated: repl-timeout now uesd by masters as well. 2013-05-27 11:43:21 +02:00
antirez 308940aa2c Close connection with timedout slaves.
Now masters, using the time at which the last REPLCONF ACK was received,
are able to explicitly disconnect slaves that are no longer responding.

Previously the only chance was to see a very long output buffer, that
was highly suboptimal.
2013-05-27 11:43:17 +02:00
antirez 45e6a4023a Send ACK to master once every second.
ACKs can be also used as a base for synchronous replication. However in
that case they'll be explicitly requested by the master when the client
sends a request that needs to be replicated synchronously.
2013-05-27 11:43:14 +02:00
antirez a74f8fe1ad Don't ACK the master after every command.
Sending an ACK is now moved into the replicationSendAck() function.
2013-05-27 11:43:10 +02:00
antirez 0000d5334d Make sure that REPLCONF ACK really has no return value. 2013-05-27 11:43:06 +02:00
antirez 146f1d7d86 Replication: send REPLCONF ACK to master. 2013-05-27 11:43:03 +02:00
antirez 1e77b77de4 REPLCONF ACK command.
This special command is used by the slave to inform the master the
amount of replication stream it currently consumed.

it does not return anything so that we not need to consume additional
bandwidth needed by the master to reply something.

The master can do a number of things knowing the amount of stream
processed, such as understanding the "lag" in bytes of the slave, verify
if a given command was already processed by the slave, and so forth.
2013-05-27 11:43:00 +02:00
antirez 0387f86947 Fixed a bug in no queueing replies to master. 2013-05-25 01:00:16 +02:00
antirez 7ae29d5d9e Replication: don't even queue replies to master commands.
When master send commands, there is no need for the slave to reply.
Redis used to queue the reply in the output buffer and discard the reply
later, this is a waste of work and it is not clear why it was this way
(I sincerely don't remember).

This commit changes it in order to don't queue the reply at all.

All tests passing.
2013-05-24 19:48:03 +02:00
antirez 302b0a5c7b Top comment for prepareClientToWrite() clarified.
We don't write the output buffer to the client socket for slaves only if
the slave is not online.
2013-05-24 18:42:18 +02:00
antirez 0b398b6ffa Don't stop reading redis.conf if line has no args.
Should be "continue" and was "return".

This fixes issue #1110
2013-05-18 16:22:24 +02:00
antirez 059018c4cd CONFIG REWRITE: remove cluster stuff for 2.8 back port. 2013-05-15 12:02:44 +02:00
antirez 414d5db85c Use memtoll() when parsing the backlog-size option. 2013-05-15 12:01:32 +02:00
antirez 604efb02ab CONFIG REWRITE: backlog size is a bytes option. 2013-05-15 12:01:27 +02:00
antirez 7d338fd982 CONFIG REWRITE: bindaddr -> bind. 2013-05-15 12:01:23 +02:00
antirez 2173f30836 CONFIG REWRITE: when rewriting amount of bytes use GB, MB, KB if possible. 2013-05-15 12:01:14 +02:00
antirez 901ceab20b CONFIG REWRITE: correctly escape the notify-keyspace-events option. 2013-05-15 12:01:06 +02:00
antirez b4ce02988c CONFIG REWRITE: "active-rehashing" -> "activerehashing". 2013-05-15 12:01:02 +02:00
antirez 2a29cf430a CONFIG REWRITE: fixed typo in AOF fsync policy. 2013-05-15 12:00:57 +02:00
antirez c95a60960b CONFIG REWRITE: repl-disable-tcp-nodelay is a boolean option. 2013-05-15 12:00:52 +02:00
antirez e8cc959300 Test default config modified to set logfile to empty string.
Required because of recent changes in the way logfile is set to standard
output.
2013-05-15 12:00:47 +02:00
antirez 180cfaae8e Added a define for most configuration defaults.
Also the logfile option was modified to always have an explicit value
and to log to stdout when an empty string is used as log file.

Previously there was special handling of the string "stdout" that set
the logfile to NULL, this always required some special handling.
2013-05-15 12:00:43 +02:00
antirez 417253afc3 CONFIG REWRITE: Use sane perms when creating redis.conf from scratch. 2013-05-15 12:00:38 +02:00
antirez 8feb3d261a CONFIG REWRITE: actually rewrite the config file, atomically. 2013-05-15 12:00:32 +02:00
antirez a461376ca9 CONFIG REWRITE: remove orphaned lines. 2013-05-15 12:00:28 +02:00
antirez 8cf0b66606 CONFIG REWRITE: strip multiple empty lines. 2013-05-15 12:00:24 +02:00
antirez cb8433f313 CONFIG REWRITE: support for client-output-buffer-limit. 2013-05-15 12:00:21 +02:00
antirez f62851aea9 CONFIG REWRITE: support for dir and slaveof. 2013-05-15 12:00:17 +02:00
antirez 91ef10ef45 CONFIG REWRITE: support for save and syslog-facility. 2013-05-15 12:00:13 +02:00
antirez 973f793b04 CONFIG REWRITE: Initial support code and design. 2013-05-15 12:00:03 +02:00
antirez 7a5d3d91a1 Obtain absoute path of configuration file, expose it in INFO. 2013-05-15 11:59:26 +02:00
antirez d8dd70c2dd redis-cli: help.h updated. 2013-05-14 11:22:58 +02:00
antirez 41babac68d Test: more PSYNC tests (backlog TTL). 2013-05-09 12:52:16 +02:00
antirez cb55ad991b Version bumped to 2.7.1 2013-05-08 15:24:54 +02:00
antirez c847c73e78 Test: check that replication partial sync works if we break the link.
The test checks both successful syncs and unsuccessful ones by changing
the backlog size.
2013-05-08 13:02:53 +02:00
antirez 2865bb7f1f Test: various issues with the replication-4.tcl test fixed.
The test actually worked, but vars for master and slave were inverted
and sometimes used incorrectly.
2013-05-08 11:59:42 +02:00
Jiahao Huang 3d93dffd5d in 32bit machine, popcount don't work with a input string length up to 512 MB,
bitcount commant may return negtive integer with string length more than 256 MB
2013-05-08 09:56:10 +02:00
antirez 85671d0e3b Added more info about 32 bit builds into README. 2013-05-08 09:48:46 +02:00
antirez b05d2516fe CONFIG SET server.masterauth aesthetic change.
This is just to make the code exactly like the above instance used for
requirepass. No actual change nor the original code violated the Redis
coding style.
2013-05-02 17:22:30 +02:00
Michel Martens b60465eb78 Reset masterauth if an empty string is configured. 2013-05-02 17:21:55 +02:00
charsyam a94db7908a Fix AOF bug: expire could be removed from key on AOF rewrite.
There was a race condition in the AOF rewrite code that, with bad enough
timing, could cause a volatile key just about to expire to be turned
into a non-volatile key. The bug was never reported to cause actualy
issues, but was found analytically by an user in the Redis mailing list:

https://groups.google.com/forum/?fromgroups=#!topic/redis-db/Kvh2FAGK4Uk

This commit fixes issue #1079.
2013-05-02 15:46:56 +02:00
antirez e7bcec829c Sentinel: changes to tilt mode.
Tilt mode was too aggressive (not processing INFO output), this
resulted in a few problems:

1) Redirections were not followed when in tilt mode. This opened a
   window to misinform clients about the current master when a Sentinel
   was in tilt mode and a fail over happened during the time it was not
   able to update the state.

2) It was possible for a Sentinel exiting tilt mode to detect a false
   fail over start, if a slave rebooted with a wrong configuration
   about at the same time. This used to happen since in tilt mode we
   lose the information that the runid changed (reboot).

   Now instead the Sentinel in tilt mode will still remove the instance
   from the list of slaves if it changes state AND runid at the same
   time.

Both are edge conditions but the changes should overall improve the
reliability of Sentinel.
2013-04-30 15:09:14 +02:00
antirez 4028a777b6 Sentinel: more sensible delay in master demote after tilt. 2013-04-30 15:09:10 +02:00
antirez 70845320cc Sentinel: only demote old master into slave under certain conditions.
We used to always turn a master into a slave if the DEMOTE flag was set,
as this was a resurrecting master instance.

However the following race condition is possible for a Sentinel that
got partitioned or internal issues (tilt mode), and was not able to
refresh the state in the meantime:

1) Sentinel X is running, master is instance "A".
3) "A" fails, sentinels will promote slave "B" as master.
2) Sentinel X goes down because of a network partition.
4) "A" returns available, Sentinels will demote it as a slave.
5) "B" fails, other Sentinels will promote slave "A" as master.
6) At this point Sentinel X comes back.

When "X" comes back he thinks that:

"B" is the master.
"A" is the slave to demote.

We want to avoid that Sentinel "X" will demote "A" into a slave.
We also want that Sentinel "X" will detect that the conditions changed
and will reconfigure itself to monitor the right master.

There are two main ways for the Sentinel to reconfigure itself after
this event:

1) If "B" is reachable and already configured as a slave by other
sentinels, "X" will perform a redirection to "A".
2) If there are not the conditions to demote "A", the fact that "A"
reports to be a master will trigger a failover detection in "X", that
will end into a reconfiguraiton to monitor "A".

However if the Sentinel was not reachable, its state may not be updated,
so in case it titled, or was partiitoned from the master instance of the
slave to demote, the new implementation waits some time (enough to
guarantee we can detect the new INFO, and new DOWN conditions).

If after some time still there are not the right condiitons to demote
the instance, the DEMOTE flag is cleared.
2013-04-30 15:09:06 +02:00
antirez 2b427a89fb Lua updated to version 5.1.5. 2013-04-29 12:02:01 +02:00
antirez d2ff5ed603 Sentinel: always redirect on master->slave transition.
Sentinel redirected to the master if the instance changed runid or it
was the first time we got INFO, and a role change was detected from
master to slave.

While this is a good idea in case of slave->master, since otherwise we
could detect a failover without good reasons just after a reboot with a
slave with a wrong configuration, in the case of master->slave
transition is much better to always perform the redirection for the
following reasons:

1) A Sentinel may go down for some time. When it is back online there is
no other way to understand there was a failover.
2) Pointing clients to a slave seems to be always the wrong thing to do.
3) There is no good rationale about handling things differently once an
instance is rebooted (runid change) in that case.
2013-04-24 11:34:02 +02:00
antirez b06f13e7b7 Config option to turn AOF rewrite incremental fsync on/off. 2013-04-24 10:57:35 +02:00
antirez 9ca306d874 AOF: sync data on disk every 32MB when rewriting.
This prevents the kernel from putting too much stuff in the output
buffers, doing too heavy I/O all at once. So the goal of this commit is
to split the disk pressure due to the AOF rewrite process into smaller
spikes.

Please see issue #1019 for more information.
2013-04-24 10:27:02 +02:00
antirez 5276996cf1 rio.c: added ability to fdatasync() from time to time while writing. 2013-04-24 10:26:58 +02:00
antirez e426ea5245 Test: fix RDB test checking file permissions.
When the test is executed using the root account, setting the permission
to 222 does not work as expected, as root can read files with 222
permission.

Now we skip the test if root is detected.

This fixes issue #1034 and the duplicated #1040 issue.

Thanks to Jan-Erik Rediger (@badboy on Github) for finding a way to reproduce the issue.
2013-04-23 14:16:47 +02:00
antirez d0c9a2a767 Sentinel: turn old master into a slave when it comes back. 2013-04-22 11:26:29 +02:00
antirez a500c120ba Test: split conceptually unrelated comments in RDB test. 2013-04-22 11:26:02 +02:00
antirez 3a865829a7 More explicit panic message on out of memory. 2013-04-19 15:11:55 +02:00
antirez 0e3baa5241 Redis/Jemalloc Gitignore were too aggressive.
Redis gitignore was too aggressive since simply broken.

Jemalloc gitignore was too agressive because it is conceived to just
keep the files that allow to generate all the rest in development
environments (so for instance the "configure" file is excluded).
2013-04-18 16:23:12 +02:00
antirez 42ba5d3788 redis-cli: raise error on bad command line switch.
Previously redis-cli never tried to raise an error when an unrecognized
switch was encountered, as everything after the initial options is to be
transmitted to the server.

However this is too liberal, as there are no commands starting with "-".
So the new behavior is to produce an error if there is an unrecognized
switch starting with "-". This should not break past redis-cli usages
but should prevent broken options to be silently discarded.

As far the first token not starting with "-" is encountered, all the
rest is considered to be part of the command, so you cna still use
strings starting with "-" as values, like in:

    redis-cli --port 6380 set foo --my-value
2013-04-11 13:19:52 +02:00
antirez 0d7b10ee6e redis-cli: --latency-history mode implemented. 2013-04-11 13:19:48 +02:00
antirez 8d81e68d18 Test: remove useless statements and comments from test default config. 2013-04-04 14:31:30 +02:00
antirez d83d72f380 Make rio.c comment 80-columns friendly. 2013-04-03 12:41:27 +02:00
antirez d6b0c18c51 Throttle BGSAVE attempt on saving error.
When a BGSAVE fails, Redis used to flood itself trying to BGSAVE at
every next cron call, that is either 10 or 100 times per second
depending on configuration and server version.

This commit does not allow a new automatic BGSAVE attempt to be
performed before a few seconds delay (currently 5).

This avoids both the auto-flood problem and filling the disk with
logs at a serious rate.

The five seconds limit, considering a log entry of 200 bytes, will use
less than 4 MB of disk space per day that is reasonable, the sysadmin
should notice before of catastrofic events especially since by default
Redis will stop serving write queries after the first failed BGSAVE.

This fixes issue #849
2013-04-02 14:12:28 +02:00
Johan Bergström 0bc7dbda1c use install as default installer (except on SunOS) 2013-04-02 11:54:20 +02:00
Johan Bergström 034d94193d Silence mkdir output 2013-04-02 11:30:16 +02:00
Johan Bergström 2094eb36e7 Only pass -rdynamic as linker option 2013-04-02 11:30:13 +02:00
Johan Bergström 31844fe138 Remove extra spaces 2013-04-02 11:29:56 +02:00
Johan Bergström c72459bf18 make check is a common naming convention for tests 2013-04-02 11:27:38 +02:00
Johan Bergström ca0b1c2436 Inherit CC for Lua 2013-04-02 11:26:50 +02:00
Johan Bergström 49eef7738e Spaces to tabs 2013-04-02 11:26:41 +02:00
Johan Bergström 0c8690d46e Slightly refactor CFLAGS/LDFLAGS/LIBS
This way, we can avoid -rdynamic and -pthread warnings on darwin.
2013-04-02 11:26:37 +02:00
charsyam cf8484b723 Support for case unsensitive SET options. 2013-03-29 10:37:29 +01:00
antirez 0c447d3506 Test: Extended SET tests. 2013-03-28 16:39:39 +01:00
antirez 24aa61785d Extended SET command implemented (issue #931). 2013-03-28 16:39:34 +01:00
antirez e6e07042a1 EXPIRE should not resurrect keys. Issue #1026. 2013-03-28 12:48:38 +01:00
antirez be832929c8 Test: regression test for issue #1026. 2013-03-28 12:48:35 +01:00
antirez 4de4080ea5 Better DEBUG error message when num of arguments is wrong. 2013-03-28 12:48:30 +01:00
antirez 978185bf67 Test: verify that lazy-expire works. 2013-03-28 12:48:26 +01:00
antirez 10d8e6a712 DEBUG set-active-expire added.
We need the ability to disable the activeExpireCycle() (active
expired key collection) call for testing purposes.
2013-03-28 12:48:19 +01:00
antirez c6a9a20d3b Test: test replication of MULTI/EXEC. 2013-03-27 12:05:22 +01:00
antirez 61b1d6da18 Test: Restore DB back to 9 after testing MULTI/EXEC with DB 5. 2013-03-27 12:05:19 +01:00
antirez 7009ff98b8 Test: new functions to capture and analyze the replication stream. 2013-03-27 12:05:15 +01:00
antirez a452b54849 TTL / PTTL commands: two bugs fixed.
This commit fixes two corner cases for the TTL command.

1) When the key was already logically expired (expire time older
than current time) the command returned -1 instead of -2.

2) When the key was existing and the expire was found to be exactly 0
(the key was just about to expire), the command reported -1 (that is, no
expire) instead of a TTL of zero (that is, about to expire).
2013-03-26 13:59:33 +01:00
antirez 10c6195e3f Flag PUBLISH as read-only in the command table. 2013-03-26 13:59:26 +01:00
antirez 2618101ad5 Transactions: propagate MULTI/EXEC only when needed.
MULTI/EXEC is now propagated to the AOF / Slaves only once we encounter
the first command that is not a read-only one inside the transaction.

The old behavior was to always propagate an empty MULTI/EXEC block when
the transaction was composed just of read only commands, or even
completely empty. This created two problems:

1) It's a bandwidth waste in the replication link and a space waste
   inside the AOF file.

2) We used to always increment server.dirty to force the propagation of
   the EXEC command, resulting into triggering RDB saves more often
   than needed.

Note: even read-only commands may also trigger writes that will be
propagated, when we access a key that is found expired and Redis will
synthesize a DEL operation. However there is no need for this to stay
inside the transaction itself, but only to be ordered.

So for instance something like:

    MULTI
    GET foo
    SET key zap
    EXEC

May be propagated into:

    DEL foo
    MULTI
    SET key zap
    EXEC

While the DEL is outside the transaction, the commands are delivered in
the right order and it is not possible for other commands to be inserted
between DEL and MULTI.
2013-03-26 13:59:21 +01:00
antirez 82516e8168 Transactions: use discardTransaction() in EXEC implementation. 2013-03-26 13:59:18 +01:00
antirez d91dfaf6dc Transactions: use the propagate() API to propagate MULTI.
The behavior is the same, but the code is now cleaner and uses the
proper interface instead of dealing directly with AOF/replication
functions.
2013-03-26 13:59:14 +01:00
antirez 150f7e43ca Allow SELECT while loading the DB.
Fixes issue #1024.
2013-03-26 13:59:05 +01:00
NanXiao 382420ec6e Update config.c
Fix bug in configGetCommand function: get correct masterauth value.
2013-03-25 19:32:20 +01:00
antirez 6b7562e204 Test: obuf-limits test false positive removed.
Fixes #621.
2013-03-25 11:56:31 +01:00
antirez ec18d4bfba redis-cli --stat, stolen from redis-tools.
Redis-tools is a connection of tools no longer mantained that was
intented as a way to economically make sense of Redis in the pre-vmware
sponsorship era. However there was a nice redis-stat utility, this
commit imports one of the functionalities of this tool here in redis-cli
as it seems to be pretty useful.

Usage: redis-cli --stat

The output is similar to vmstat in the format, but with Redis specific
stuff of course.

From the point of view of the monitored instance, only INFO is used in
order to grab data.
2013-03-25 11:52:25 +01:00
antirez 58708fa65a Replication: master_link_down_since_seconds initial value should be huge.
server.repl_down_since used to be initialized to the current time at
startup. This is wrong since the replication never started. Clients
testing this filed to check if data is uptodate should never believe
data is recent if we never ever connected to our master.
2013-03-13 12:55:02 +01:00
antirez ba8367ee49 Test: make sure broken RDB checksum is detected. 2013-03-13 11:15:31 +01:00
antirez 67a745515d Test: more RDB loading checks.
A test for issue #1001 is included.
2013-03-13 10:08:40 +01:00
antirez 7b6fb960cc Test: check that Redis starts empty without an RDB file. 2013-03-13 10:08:36 +01:00
antirez 64b91c1493 rdbLoad(): rework code to save vertical space. 2013-03-13 10:08:30 +01:00
Damian Janowski edb3c10361 Abort when opening the RDB file results in an error other than ENOENT.
This fixes cases where the RDB file does exist but can't be accessed for
any reason. For instance, when the Redis process doesn't have enough
permissions on the file.
2013-03-13 10:08:26 +01:00
antirez b2e42a90d3 Set default for stop_writes_on_bgsave_err in initServerConfig().
It was placed for error in initServer() that's called after the
configuation is already loaded, causing issue #1000.
2013-03-12 18:36:02 +01:00
antirez 378fcaad55 redis-cli --bigkeys: don't crash with empty DBs. 2013-03-12 09:57:57 +01:00
antirez 8e7d962291 activeExpireCycle() smarter with many DBs and under expire pressure.
activeExpireCycle() tries to test just a few DBs per iteration so that
it scales if there are many configured DBs in the Redis instance.
However this commit makes it a bit smarter when one a few of those DBs
are under expiration pressure and there are many many keys to expire.

What we do is to remember if in the last iteration had to return because
we ran out of time. In that case the next iteration we'll test all the
configured DBs so that we are sure we'll test again the DB under
pressure.

Before of this commit after some mass-expire in a given DB the function
tested just a few of the next DBs, possibly empty, a few per iteration,
so it took a long time for the function to reach again the DB under
pressure. This resulted in a lot of memory being used by already expired
keys and never accessed by clients.
2013-03-11 11:30:13 +01:00
antirez c5afbb6e2a In databasesCron() never test more DBs than we have. 2013-03-11 11:30:09 +01:00
antirez 7e7ee815b0 Make comment name match var name in activeExpireCycle(). 2013-03-11 11:30:04 +01:00
antirez 6a8288766c Optimize inner loop of activeExpireCycle() for no-expires case. 2013-03-11 11:30:01 +01:00
antirez 9afb7789b3 REDIS_DBCRON_DBS_PER_SEC -> REDIS_DBCRON_DBS_PER_CALL 2013-03-11 11:29:57 +01:00
antirez 1a73260dce activeExpireCycle(): process only a small number of DBs per iteration.
This small number of DBs is set to 16 so actually in the default
configuraiton Redis should behave exactly like in the past.
However the difference is that when the user configures a very large
number of DBs we don't do an O(N) operation, consuming a non trivial
amount of CPU per serverCron() iteration.
2013-03-11 11:29:53 +01:00
antirez 8abfe5fe8b Use unsigned integers for DB ids, for defined wrap-to-zero. 2013-03-11 11:29:49 +01:00
antirez a4bb4b29fb Only resize/rehash a few databases per cron iteration.
This is the first step to lower the CPU usage when many databases are
configured. The other is to also process a limited number of DBs per
call in the active expire cycle.
2013-03-11 11:29:45 +01:00
antirez aa7f74c7e9 Actually call databasesCron() inside serverCron(). 2013-03-11 11:29:41 +01:00
antirez 21822fd0e9 Move Redis databases background processing to databasesCron(). 2013-03-11 11:29:34 +01:00
Gengliang Wang 6ae8fb477a Removed useless "return" statements in pubsub.c
(original commit message edited)
2013-03-06 16:50:53 +01:00
antirez bc1b2e8f96 API to lookup commands with their original name.
A new server.orig_commands table was added to the server structure, this
contains a copy of the commant table unaffected by rename-command
statements in redis.conf.

A new API lookupCommandOrOriginal() was added that checks both tables,
new first, old later, so that rewriteClientCommandVector() and friends
can lookup commands with their new or original name in order to fix the
client->cmd pointer when the argument vector is renamed.

This fixes the segfault of issue #986, but does not fix a wider range of
problems resulting from renaming commands that actually operate on data
and are registered into the AOF file or propagated to slaves... That is
command renaming should be handled with care.
2013-03-06 16:36:57 +01:00
antirez deccd104d8 Add a warning about command renaming in redis.conf. 2013-03-06 16:36:57 +01:00
antirez 5bcfa2ebbc Handle a non-impossible empty argv in loadServerConfigFromString().
Usually this does not happens since we trim for " \t\r\n", but if there
are other chars that return true with isspace(), we may end with an
empty argv. Better to handle the condition in an explicit way.
2013-03-06 12:43:49 +01:00
antirez 00a5e86e44 redis-cli: use sdsfreesplitres() instead of hand-coding it. 2013-03-06 12:43:45 +01:00
antirez f72a3406a7 sds.c: sdssplitargs_free() removed as it was a duplicate. 2013-03-06 12:43:41 +01:00
antirez 68532cf01e More specific error message in loadServerConfigFromString(). 2013-03-06 12:43:37 +01:00
antirez a70e3ffb16 sdssplitargs(): on error set *argc to 0.
This makes programs not checking the return value for NULL much safer
since with this change:

1) It is still possible to iterate the zero-length result without
crashes.
2) sdssplitargs_free will work against NULL and 0 count.
2013-03-06 12:43:32 +01:00
antirez a6f557657c sdssplitargs(): now returns NULL only on error.
An empty input string also resulted into the function returning NULL
making it harder for the caller to distinguish between error and empty
string without checking the original input string length.
2013-03-06 12:43:27 +01:00
charsyam 5aeb1f71a3 Don't segfault on unbalanced quotes. 2013-03-06 12:43:22 +01:00
antirez aadb8aaa08 Allow AUTH while loading the DB in memory.
While Redis is loading the AOF or RDB file in memory only a subset of
commands are allowed. This commit adds AUTH to this subset.
2013-03-06 11:51:23 +01:00
antirez df3b492045 redis-cli: use keepalive socket option.
This should improve things in two ways:

1) Prevent timeouts caused by the execution of long commands.
2) Improve detection of real connection errors.

This is mostly effective only on Linux because of the bogus default
keepalive settings. In Linux we have OS-specific calls to set the
keepalive interval to reasonable values.
2013-03-04 11:16:21 +01:00
0x20h e618eb4fb3 suppress external diff program when using git diff. 2013-03-04 10:58:02 +01:00
Stam He a74056f1e0 point 2 of slave-serve-stale-data miss '-' between 'stale' and 'data' 2013-03-04 10:49:19 +01:00
antirez 02cd545f7d A comment in main() clarified. 2013-02-27 12:47:51 +01:00
antirez b148513fec Remove warning when printing redisBuildId(). 2013-02-27 12:47:38 +01:00
antirez 5e9e96999f Remove too agressive/spamming log in rdb.c. 2013-02-27 12:47:33 +01:00
antirez d2a37badc2 Use GCC printf format attribute for redisLog().
This commit also fixes redisLog() statements producing warnings.
2013-02-27 12:47:16 +01:00
antirez 0d8d7f106a Better panic message for failed time event creation. 2013-02-27 12:00:51 +01:00
Stam He 438dfdd13d add a check for aeCreateTimeEvent
1) Add a check for aeCreateTimeEvent in function initServer.
2013-02-27 12:00:48 +01:00
Stam He 6f96ac1c1c Set proctitle: avoid the use of __attribute__((constructor)).
This cased a segfault in some Linux system and was GCC-specific.

Commit modified by @antirez:

1) Stripped away the part to set the proc title via config for now.
2) Handle initialization of setproctitle only when the replacement
   is used.
3) Don't require GCC now that the attribute constructor is no
   longer used.
2013-02-27 12:00:43 +01:00
antirez f69b0a0db8 setproctitle.c: declar tmp as static so valgrind will not detect a leak. 2013-02-26 15:51:15 +01:00
antirez ac3100bc3b Set process name in ps output to make operations safer.
This commit allows Redis to set a process name that includes the binding
address and the port number in order to make operations simpler.

Redis children processes doing AOF rewrites or RDB saving change the
name into redis-aof-rewrite and redis-rdb-bgsave respectively.

This in general makes harder to kill the wrong process because of an
error and makes simpler to identify saving children.

This feature was suggested by Arnaud GRANAL in the Redis Google Group,
Arnaud also pointed me to the setproctitle.c implementation includeed in
this commit.

This feature should work on all the Linux, OSX, and all the three major
BSD systems.
2013-02-26 12:03:48 +01:00
Arnaud Granal fedcd51185 Fix error "repl-backlog-size must be 1 or greater"
The parameter repl-backlog-size is not parsed correctly in the configuration file. argv[0] is parsed instead of argv[1].
2013-02-25 18:38:48 +01:00
antirez ff56772115 PSYNC: another change to unexpected reply from PSYNC. 2013-02-13 18:43:45 +01:00
antirez 964ee00de0 PSYNC: More robust handling of unexpected reply to PSYNC. 2013-02-13 18:34:18 +01:00
antirez 3b4c0d80d5 Avoid compiler warning by casting to match printf() specifier. 2013-02-13 13:38:32 +01:00
antirez d96a66f531 Replication: more strict error checking for master PING reply. 2013-02-12 16:59:27 +01:00
antirez 31f0a6ec50 Replication: added new stats counting full and partial resynchronizations. 2013-02-12 16:26:42 +01:00
antirez 5fe2577a19 Return a specific NOAUTH error if authentication is required. 2013-02-12 16:25:47 +01:00
antirez 9854252798 Test: avoid false positives in CLIENT SETNAME closed connection test. 2013-02-12 13:27:30 +01:00
Steven Penny 5a8cf340a4 Format to fit 80 columns
This makes it readable on GitHub and editors without auto wrapping.
2013-02-12 13:11:44 +01:00
antirez 0ae1a6b1c3 Add missing bracket removed for error after rebase of PSYNC. 2013-02-12 12:58:07 +01:00
antirez 2b1398e870 PSYNC: debugging printf() calls are now logs at DEBUG level. 2013-02-12 12:58:03 +01:00
antirez 5a4ef3e5b6 Remove harmless warning in slaveTryPartialResynchronization(). 2013-02-12 12:57:59 +01:00
antirez 4fe7672dfc PSYNC: don't use the client buffer to send +CONTINUE and +FULLRESYNC.
When we are preparing an handshake with the slave we can't touch the
connection buffer as it'll be used to accumulate differences between
the sent RDB file and what arrives next from clients.

So in short we can't use addReply() family functions.

However we just use write(2) because we know that the socket buffer is
empty, since a prerequisite for SYNC to work is that the static buffer
and the output list are empty, and in general it is not expected that a
client SYNCs after doing some heavy I/O with the master.

However a short write connection is explicitly handled to avoid
fragility (we simply close the connection and the slave will retry).
2013-02-12 12:57:56 +01:00
antirez 8529dd218f SYNC not allowed with pending data on the static output buffer. 2013-02-12 12:57:52 +01:00
antirez 6726ea5b53 Log the unexpected string received in place of the SYNC payload length. 2013-02-12 12:57:48 +01:00
antirez f5edd535d1 After SLAVEOF <newslave> don't allow chained slaves to PSYNC. 2013-02-12 12:57:44 +01:00
antirez 700e5eb4fc PSYNC: work in progress, preview #2, rebased to unstable. 2013-02-12 12:57:40 +01:00
antirez 4d8655cfd3 Use the new unified protocol to send SELECT to slaves.
SELECT was still transmitted to slaves using the inline protocol, that
is conceived mostly for humans to type into telnet sessions, and is
notably not understood by redis-cli --slave.

Now the new protocol is used instead.
2013-02-12 12:57:36 +01:00
antirez 01c21f9943 Use replicationFeedSlaves() to send PING to slaves.
A Redis master sends PING commands to slaves from time to time: doing
this ensures that even if absence of writes, the master->slave channel
remains active and the slave can feel the master presence, instead of
closing the connection for timeout.

This commit changes the way PINGs are sent to slaves in order to use the
standard interface used to replicate all the other commands, that is,
the function replicationFeedSlaves().

With this change the stream of commands sent to every slave is exactly
the same regardless of their exact state (Transferring RDB for first
synchronization or slave already online). With the previous
implementation the PING was only sent to online slaves, with the result
that the output stream from master to slaves was not identical for all
the slaves: this is a problem if we want to implement partial resyncs in
the future using a global replication stream offset.

TL;DR: this commit should not change the behaviour in practical terms,
but is just something in preparation for partial resynchronization
support.
2013-02-12 12:57:31 +01:00
antirez 5a35e485f9 Emit SELECT to slaves in a centralized way.
Before this commit every Redis slave had its own selected database ID
state. This was not actually useful as the emitted stream of commands
is identical for all the slaves.

Now the the currently selected database is a global state that is set to
-1 when a new slave is attached, in order to force the SELECT command to
be re-emitted for all the slaves.

This change is useful in order to implement replication partial
resynchronization in the future, as makes sure that the stream of
commands received by slaves, including SELECT commands, are exactly the
same for every slave connected, at any time.

In this way we could have a global offset that can identify a specific
piece of the master -> slaves stream of commands.
2013-02-12 12:57:26 +01:00
antirez c970816e4d Makefile: valgrind target added (forces -O0 and libc malloc). 2013-02-11 12:11:26 +01:00
antirez 8a22934c68 TCP keep-alive. Better documentation in redis.conf. 2013-02-11 11:44:35 +01:00
antirez b06b90b5d8 Tcp keep-alive: send three probes before detectin an error.
Otherwise we end with less reliable connections because it's too easy
that a single packet gets lost.
2013-02-11 11:44:31 +01:00
antirez 0a14a6542c tcp-keepalive option documented in redis.conf. 2013-02-11 11:44:27 +01:00
antirez 2ed3fc1502 Set SO_KEEPALIVE on client sockets if configured to do so. 2013-02-11 11:44:23 +01:00
antirez f2817cbd9e Add SO_KEEPALIVE support to anet.c. 2013-02-11 11:44:18 +01:00
antirez fcfdbda104 Sentinel: advertise the promoted slave address only after successful setup. 2013-02-11 11:44:14 +01:00
Pierre Chapuis 0d470b4c43 fix comments forgotten in #285 (zipmap -> ziplist) 2013-02-11 11:44:06 +01:00
antirez cc55a4525a Make all WATCHers dirty when the slave reloads the DB. 2013-02-08 10:27:21 +01:00
antirez 5eb0ec142d LASTSAVE is a "random" command. 2013-02-07 19:13:06 +01:00
antirez 5f7dff4d16 TCP_NODELAY after SYNC: changes to the implementation. 2013-02-05 12:05:39 +01:00
charsyam 1d80acae54 Turn off TCP_NODELAY on the slave socket after SYNC.
Further details from @antirez:

It was reported by @StopForumSpam on Twitter that the Redis replication
link was strangely using multiple TCP packets for multiple commands.
This wastes a lot of bandwidth and is due to the TCP_NODELAY option we
enable on the socket after accepting a new connection.

However the master -> slave channel is a one-way channel since Redis
replication is asynchronous, so there is no point in trying to reduce
the latency, we should aim to reduce the bandwidth. For this reason this
commit introduces the ability to disable the nagle algorithm on the
socket after a successful SYNC.

This feature is off by default because the delay can be up to 40
milliseconds with normally configured Linux kernels.
2013-02-05 12:05:24 +01:00
antirez 14daa01c52 Test: No clients timeout while testing. 2013-02-05 12:02:41 +01:00
Johan Bergström d2a8bca82b Use info nameofexectuable to find current executable 2013-02-05 11:44:55 +01:00
Johan Bergström 1124cda37a Enforce tcl 8.5 or newer 2013-02-05 11:44:51 +01:00
Johan Bergström e92edd3cee Check available tcl versions 2013-02-05 11:44:44 +01:00
Rock Li 2543fa6476 retval doesn't initalized
If each if conditions are all fail, variable retval will under uninitlized
2013-02-05 10:49:24 +01:00
David Celis 44d0eac568 Fix a few typos and improve grammar of redis.conf
Make several edits to the example redis.conf configuration file for
improved flow and grammar.

Signed-off-by: David Celis <me@davidcel.is>
2013-02-04 10:34:05 +01:00
Gengliang Wang 57e411c687 Fix a bug in srandmemberWithCountCommand()
In CASE 2, the call sunionDiffGenericCommand will involve the string "srandmember"
> sadd foo one
(integer 1)
> sadd srandmember two
(integer 2)
> srandmember foo 3
1)"one"
2)"two"
2013-02-04 10:33:21 +01:00
antirez 8024de7eb0 Z*STORE event fixed: generate del only if resulting sorted set is empty. 2013-01-29 13:50:09 +01:00
antirez ca8e7d4f8a Generate del events when S*STORE commands delete the destination key. 2013-01-29 13:43:24 +01:00
antirez 664de412af Tests for keyspace notifications. 2013-01-28 13:19:04 +01:00
antirez d3cf778d82 Send 'expired' events when a key expires by lookup. 2013-01-28 13:18:57 +01:00
antirez 9db8fbcfdd Keyspace notifications: fixed a leak and a bug introduced in the latest commit. 2013-01-28 13:18:53 +01:00
antirez b9bc4f9132 Keyspace events: it is now possible to select subclasses of events.
When keyspace events are enabled, the overhead is not sever but
noticeable, so this commit introduces the ability to select subclasses
of events in order to avoid to generate events the user is not
interested in.

The events can be selected using redis.conf or CONFIG SET / GET.
2013-01-28 13:18:36 +01:00
antirez 6de052cd77 decrRefCount -> decrRefCountVoid in list constructor. 2013-01-28 13:17:37 +01:00
antirez 81af92b023 Enable keyspace events notification when testing. 2013-01-28 13:17:33 +01:00
antirez 4ff138fbbe Keyspace events added for more commands. 2013-01-28 13:17:30 +01:00
antirez 2825f21fd8 Fix decrRefCount() prototype from void to robj pointer.
decrRefCount used to get its argument as a void* pointer in order to be
used as destructor where a 'void free_object(void*)' prototype is
expected. However this made simpler to introduce bugs by freeing the
wrong pointer. This commit fixes the argument type and introduces a new
wrapper called decrRefCountVoid() that can be used when the void*
argument is needed.
2013-01-28 13:17:26 +01:00
antirez a64383c861 notifyKeyspaceEvent(): release channel names using the right pointers. 2013-01-28 13:17:22 +01:00
antirez fdfb59beae Initial test events for the new keyspace notification API. 2013-01-28 13:17:18 +01:00
antirez dd2ce743ca Fixed over-80-cols comment in db.c 2013-01-28 13:17:15 +01:00
antirez 6e64525cc2 Two fixes to initial keyspace notifications API. 2013-01-28 13:17:11 +01:00
antirez 212edbc409 Keyspace events notification API. 2013-01-28 13:17:00 +01:00
antirez 153766e137 Lua struct library updated to version 0.2.
There was a bug in the previous version of this library that caused a
crash under the circumstances described in issue #901.

The newer version of the library appears to be fixed (I tested it
manually with valgrind and everything seems fine now).

For more information about this library please visit this web site:

    http://www.inf.puc-rio.br/~roberto/struct/
2013-01-23 10:53:31 +01:00
antirez 767a53aa84 redis-cli --bigkeys output is now simpler to understand. 2013-01-21 19:16:11 +01:00
antirez 3ff75e58e8 UNSUBSCRIBE and PUNSUBSCRIBE: always provide a reply.
UNSUBSCRIBE and PUNSUBSCRIBE commands are designed to mass-unsubscribe
the client respectively all the channels and patters if called without
arguments.

However when these functions are called without arguments, but there are
no channels or patters we are subscribed to, the old behavior was to
don't reply at all.

This behavior is broken, as every command should always reply.
Also it is possible that we are no longer subscribed to a channels but we
are subscribed to patters or the other way around, and the client should
be notified with the correct number of subscriptions.

Also it is not pretty that sometimes we did not receive a reply at all
in a redis-cli session from these commands, blocking redis-cli trying
to read the reply.

This fixes issue #714.
2013-01-21 19:02:24 +01:00
antirez 850117a8a5 Fixed a bug in memtest progress bar, that had no actual effects.
This closes issue #859, thanks to @erbenmo.
2013-01-21 12:38:46 +01:00
Bilal Husain 2f1318ab29 s/adiacent/adjacent/
fixed typo in a comment (step 2 memcheck)
2013-01-21 12:20:07 +01:00
antirez f6f43d7da0 Not every __sun has backtrace().
I don't know how to test for Open Solaris that has support for
backtrace() so for now removing the #ifdef that breaks compilation under
other Solaris flavors.
2013-01-21 12:07:48 +01:00
antirez 635c532c89 Additionally two typos fixed thanks to @jodal 2013-01-19 13:46:22 +01:00
antirez 39f0a33f78 Whitelist SIGUSR1 to avoid auto-triggering errors.
This commit fixes issue #875 that was caused by the following events:

1) There is an active child doing BGSAVE.
2) flushall is called (or any other condition that makes Redis killing
the saving child process).
3) An error is sensed by Redis as the child exited with an error (killed
by a singal), that stops accepting write commands until a BGSAVE happens
to be executed with success.

Whitelisting SIGUSR1 and making sure Redis always uses this signal in
order to kill its own children fixes the issue.
2013-01-19 13:30:46 +01:00
antirez 1e20c939fe Clear server.shutdown_asap on failed shutdown.
When a SIGTERM is received Redis schedules a shutdown. However if it
fails to perform the shutdown it must be clear the shutdown_asap flag
otehrwise it will try again and again possibly making the server
unusable.
2013-01-19 13:20:56 +01:00
antirez d766907cfb Slowlog: don't log EXEC but just the executed commands.
The Redis Slow Log always used to log the slow commands executed inside
a MULTI/EXEC block. However also EXEC was logged at the end, which is
perfectly useless.

Now EXEC is no longer logged and a test was added to test this behavior.

This fixes issue #759.
2013-01-19 12:55:15 +01:00
guiquanz 1caf09399e Fixed many typos.
Conflicts fixed, mainly because 2.8 has no cluster support / files:
	00-RELEASENOTES
	src/cluster.c
	src/crc16.c
	src/redis-trib.rb
	src/redis.h
2013-01-19 11:03:19 +01:00
charsyam ff1e4d22a6 redis-cli prompt bug fix 2013-01-19 10:34:22 +01:00
Jan-Erik Rediger a8f9cec16a Always exit if connection fails.
This avoids unnecessary core dumps. Fixes antirez/redis#894
2013-01-19 10:29:42 +01:00
bitterb aadcda9977 Fix an error reply for CLIENT command 2013-01-19 10:26:32 +01:00
Nathan Parry f2bc198d40 redis-cli --rdb fails if server sends a ping
Redis pings slaves in "pre-synchronization stage" with newlines. (See
https://github.com/antirez/redis/blob/2.6.9/src/replication.c#L814)
However, redis-cli does not expect this - it sees the newline as the end
of the bulk length line, and ends up returning 0 as bulk the length.
This manifests as the following when running redis-cli:

    $ ./src/redis-cli --rdb some_file
    SYNC sent to master, writing 0 bytes to 'some_file'
    Transfer finished with success.

With this commit, we just ignore leading newlines while reading the bulk
length line.

To reproduce the problem, load enough data into Redis so that the
preparation of the RDB snapshot takes long enough for a ping to occur
while redis-cli is waiting for the data.
2013-01-18 11:50:06 +01:00
antirez c48584b85d redis-cli: save an RDB dump from remote server to local file. 2013-01-16 19:48:30 +01:00
antirez 7897e0a0d6 Tests for CLIENT GETNAME/SETNAME. 2013-01-15 13:34:26 +01:00
antirez f31d10b9a6 Typo fixed, ASCI -> ASCII. 2013-01-15 13:34:24 +01:00
antirez 786bd3938e CLIENT GETNAME and CLIENT SETNAME introduced.
Sometimes it is much simpler to debug complex Redis installations if it
is possible to assign clients a name that is displayed in the CLIENT
LIST output.

This is the case, for example, for "leaked" connections. The ability to
provide a name to the client makes it quite trivial to understand what
is the part of the code implementing the client not releasing the
resources appropriately.

Behavior:

    CLIENT SETNAME: set a name for the client, or remove the current
                    name if an empty name is set.
    CLIENT GETNAME: get the current name, or a nil.
    CLIENT LIST: now displays the client name if any.

Thanks to Mark Gravell for pushing this idea forward.
2013-01-15 13:34:22 +01:00
antirez aa9497fdb3 Undo slave-master handshake when SLAVEOF sets a new slave.
Issue #828 shows how Redis was not correctly undoing a non-blocking
connection attempt with the previous master when the master was set to a
new address using the SLAVEOF command.

This was also a result of lack of refactoring, so now there is a
function to cancel the non blocking handshake with the master.
The new function is now used when SLAVEOF NO ONE is called or when
SLAVEOF is used to set the master to a different address.
2013-01-15 13:33:27 +01:00
antirez 64ee9c861f Makefile.dep updated. 2013-01-11 23:51:12 +01:00
antirez 8a70007f9e Comment in the call() function clarified a bit. 2013-01-10 12:04:24 +01:00
antirez e2e36cf19b Test: added regression for issue #872. 2013-01-10 12:04:19 +01:00
antirez 414e06653c Multiple fixes for EVAL (issue #872).
1) The event handler was no restored after a timeout condition if the
   command was eventually executed with success.
2) The command was not converted to EVAL in case of errors in the middle
   of the execution.
3) Terrible duplication of code without any apparent reason.
2013-01-10 12:04:15 +01:00
antirez cefff3a1b3 Better error reporting when fd event creation fails. 2013-01-03 14:32:32 +01:00
antirez 6570d2f89e ae.c: set errno when error is not a failing syscall.
In this way the caller is able to perform better error checking or to
use strerror() without the risk of meaningless error messages being
displayed.
2013-01-03 14:32:27 +01:00
antirez 858b5576ac Fix overflow in mstime() in redis-cli and benchmark.
The problem does not exist in the Redis server implementation of mstime()
but is only limited to redis-cli and redis-benchmark.

Thix fixes issue #839.
2012-12-20 15:21:40 +01:00
antirez 61fb0aacf5 CONTRIBUTING updated with request to add BSD license. 2012-12-17 11:17:55 +01:00
antirez 6fa2610ac9 Added missing license and copyright in deps/hiredis. 2012-12-17 11:11:36 +01:00
antirez a6d117b6c0 serverCron() frequency is now a runtime parameter (was REDIS_HZ).
REDIS_HZ is the frequency our serverCron() function is called with.
A more frequent call to this function results into less latency when the
server is trying to handle very expansive background operations like
mass expires of a lot of keys at the same time.

Redis 2.4 used to have an HZ of 10. This was good enough with almost
every setup, but the incremental key expiration algorithm was working a
bit better under *extreme* pressure when HZ was set to 100 for Redis
2.6.

However for most users a latency spike of 30 milliseconds when million
of keys are expiring at the same time is acceptable, on the other hand a
default HZ of 100 in Redis 2.6 was causing idle instances to use some
CPU time compared to Redis 2.4. The CPU usage was in the order of 0.3%
for an idle instance, however this is a shame as more energy is consumed
by the server, if not important resources.

This commit introduces HZ as a runtime parameter, that can be queried by
INFO or CONFIG GET, and can be modified with CONFIG SET. At the same
time the default frequency is set back to 10.

In this way we default to a sane value of 10, but allows users to
easily switch to values up to 500 for near real-time applications if
needed and if they are willing to pay this small CPU usage penalty.
2012-12-14 17:20:21 +01:00
Patrick TJ McPhee 5207c03c49 Define _XOPEN_SOURCE appropriately on NetBSD. 2012-12-12 18:42:41 +01:00
antirez bbee226ecd Fix config.h endianess detection to work on Linux / PPC64.
Config.h performs endianess detection including OS-specific headers to
define the endianess macros, or when this is not possible, checking the
processor type via ifdefs.

Sometimes when the OS-specific macro is included, only __BYTE_ORDER is
defined, while BYTE_ORDER remains undefined. There is code at the end of
config.h endianess detection in order to define the macros without the
underscore, but it was not working correctly.

This commit fixes endianess detection fixing Redis on Linux / PPC64 and
possibly other systems.
2012-12-11 17:19:54 +01:00
Brian J. McManus 17e31eb03a Issue 804 Add Default-Start and Default-Stop LSB tags for RedHat startup and update-rc.d compatability. 2012-12-03 12:31:12 +01:00
antirez 124cb6dda1 Memory leak fixed: release client's bpop->keys dictionary.
Refactoring performed after issue #801 resolution (see commit
2f87cf8b01) introduced a memory leak that
is fixed by this commit.

I simply forgot to free the new allocated dictionary in the client
structure trusting the output of "make test" on OSX.

However due to changes in the "leaks" utility the test was no longer
testing memory leaks. This problem was also fixed.

Fortunately the CI test running at ci.redis.io spotted the bug in the
valgrind run.

The leak never ended into a stable release.
2012-12-03 12:17:33 +01:00
antirez e39735214d Test: fixed osx "leaks" support in test.
Due to changes in recent releases of osx leaks utility, the osx leak
detection no longer worked. Now it is fixed in a way that should be
backward compatible.
2012-12-03 12:17:29 +01:00
antirez 07a9f85405 Blocking POP: use a dictionary to store keys clinet side.
To store the keys we block for during a blocking pop operation, in the
case the client is blocked for more data to arrive, we used a simple
linear array of redis objects, in the blockingState structure:

    robj **keys;
    int count;

However in order to fix issue #801 we also use a dictionary in order to
avoid to end in the blocked clients queue for the same key multiple
times with the same client.

The dictionary was only temporary, just to avoid duplicates, but since
we create / destroy it there is no point in doing this duplicated work,
so this commit simply use a dictionary as the main structure to store
the keys we are blocked for. So instead of the previous fields we now
just have:

    dict *keys;

This simplifies the code and reduces the work done by the server during
a blocking POP operation.
2012-12-02 20:42:59 +01:00
antirez fbf3e33d18 Test: regression for issue #801. 2012-12-02 20:42:56 +01:00
antirez 64e69c0d5f Client should not block multiple times on the same key.
Sending a command like:

BLPOP foo foo foo foo 0

Resulted into a crash before this commit since the client ended being
inserted in the waiting list for this key multiple times.
This resulted into the function handleClientsBlockedOnLists() to fail
because we have code like that:

    if (de) {
        list *clients = dictGetVal(de);
        int numclients = listLength(clients);

        while(numclients--) {
            listNode *clientnode = listFirst(clients);

            /* server clients here... */
        }
    }

The code to serve clients used to remove the served client from the
waiting list, so if a client is blocking multiple times, eventually the
call to listFirst() will return NULL or worse will access random memory
since the list may no longer exist as it is removed by the function
unblockClientWaitingData() if there are no more clients waiting for this
list.

To avoid making the rest of the implementation more complex, this commit
modifies blockForKeys() so that a client will be put just a single time
into the waiting list for a given key.

Since it is Saturday, I hope this fixes issue #801.
2012-12-02 20:42:51 +01:00
antirez c1eda786d6 SDIFF fuzz test added. 2012-11-30 17:14:08 +01:00
antirez ccc974d90b SDIFF is now able to select between two algorithms for speed.
SDIFF used an algorithm that was O(N) where N is the total number
of elements of all the sets involved in the operation.

The algorithm worked like that:

ALGORITHM 1:

1) For the first set, add all the members to an auxiliary set.
2) For all the other sets, remove all the members of the set from the
auxiliary set.

So it is an O(N) algorithm where N is the total number of elements in
all the sets involved in the diff operation.

Cristobal Viedma suggested to modify the algorithm to the following:

ALGORITHM 2:

1) Iterate all the elements of the first set.
2) For every element, check if the element also exists in all the other
remaining sets.
3) Add the element to the auxiliary set only if it does not exist in any
of the other sets.

The complexity of this algorithm on the worst case is O(N*M) where N is
the size of the first set and M the total number of sets involved in the
operation.

However when there are elements in common, with this algorithm we stop
the computation for a given element as long as we find a duplicated
element into another set.

I (antirez) added an additional step to algorithm 2 to make it faster,
that is to sort the set to subtract from the biggest to the
smallest, so that it is more likely to find a duplicate in a larger sets
that are checked before the smaller ones.

WHAT IS BETTER?

None of course, for instance if the first set is much larger than the
other sets the second algorithm does a lot more work compared to the
first algorithm.

Similarly if the first set is much smaller than the other sets, the
original algorithm will less work.

So this commit makes Redis able to guess the number of operations
required by each algorithm, and select the best at runtime according
to the input received.

However, since the second algorithm has better constant times and can do
less work if there are duplicated elements, an advantage is given to the
second algorithm.
2012-11-30 17:13:34 +01:00
antirez 2572bb13c6 redis-benchmark: seed the PRNG with time() at startup. 2012-11-30 17:13:25 +01:00
antirez e34c14df1a Make an EXEC test more latency proof. 2012-11-29 16:12:23 +01:00
antirez 3b71404d70 Introduced the Build ID in INFO and --version output.
The idea is to be able to identify a build in a unique way, so for
instance after a bug report we can recognize that the build is the one
of a popular Linux distribution and perform the debugging in the same
environment.
2012-11-29 14:22:15 +01:00
antirez cd99c14e38 On crash memory test rewrote so that it actaully works.
1) We no longer test location by location, otherwise the CPU write cache
completely makes our business useless.
2) We still need a memory test that operates in steps from the first to
the last location in order to never hit the cache, but that is still
able to retain the memory content.

This was tested using a Linux box containing a bad memory module with a
zingle bit error (always zero).

So the final solution does has an error propagation step that is:

1) Invert bits at every location.
2) Swap adiacent locations.
3) Swap adiacent locations again.
4) Invert bits at every location.
5) Swap adiacent locations.
6) Swap adiacent locations again.

Before and after these steps, and after step 4, a CRC64 checksum is computed.
If the three CRC64 checksums don't match, a memory error was detected.
2012-11-29 10:24:41 +01:00
antirez 053f1f357d Jemalloc updated to version 3.2.0. 2012-11-28 18:42:35 +01:00
charsyam 1f0d0b094a Remove unnecessary condition in _dictExpandIfNeeded (dict.c) 2012-11-28 11:45:52 +01:00
Matt Arsenault ccb500cf36 It's a watchdog, not a watchdong. 2012-11-28 11:42:24 +01:00
charsyam ed48550fe6 remove compile warning bioKillThreads 2012-11-28 11:42:20 +01:00
antirez d0570c9693 EVALSHA is now case insensitive.
EVALSHA used to crash if the SHA1 was not lowercase (Issue #783).
Fixed using a case insensitive dictionary type for the sha -> script
map used for replication of scripts.
2012-11-22 15:51:03 +01:00
antirez cc85ed41df Fix integer overflow in zunionInterGenericCommand().
This fixes issue #761.
2012-11-22 15:28:48 +01:00
antirez ca9321afe2 Test: MULTI state is cleared after EXECABORT error. 2012-11-22 10:36:06 +01:00
antirez a527235f33 Test: make sure EXEC fails after previous transaction errors. 2012-11-22 10:36:01 +01:00
antirez 53600e34db Test: MULTI/EXEC tests moved into multi.tcl. 2012-11-22 10:35:50 +01:00
antirez 60f9dac672 Safer handling of MULTI/EXEC on errors.
After the transcation starts with a MULIT, the previous behavior was to
return an error on problems such as maxmemory limit reached. But still
to execute the transaction with the subset of queued commands on EXEC.

While it is true that the client was able to check for errors
distinguish QUEUED by an error reply, MULTI/EXEC in most client
implementations uses pipelining for speed, so all the commands and EXEC
are sent without caring about replies.

With this change:

1) EXEC fails if at least one command was not queued because of an
error. The EXECABORT error is used.
2) A generic error is always reported on EXEC.
3) The client DISCARDs the MULTI state after a failed EXEC, otherwise
pipelining multiple transactions would be basically impossible:
After a failed EXEC the next transaction would be simply queued as
the tail of the previous transaction.
2012-11-22 10:35:47 +01:00
antirez dff1ec4a36 Make bio.c threads killable ASAP if needed.
We use this new bio.c feature in order to stop our I/O threads if there
is a memory test to do on crash. In this case we don't want anything
else than the main thread to run, otherwise the other threads may mess
with the heap and the memory test will report a false positive.
2012-11-22 10:28:53 +01:00
antirez d4b5c4803b Fast memory test on Redis crash. 2012-11-22 10:28:48 +01:00
antirez dd905417ec Use more fine grained HAVE macros instead of HAVE_PROCFS. 2012-11-22 10:28:43 +01:00
antirez c342b075df Children creating AOF or RDB files now report memory used by COW.
Finally Redis is able to report the amount of memory used by
copy-on-write while saving an RDB or writing an AOF file in background.

Note that this information is currently only logged (at NOTICE level)
and not shown in INFO because this is less trivial (but surely doable
with some minor form of interprocess communication).

The reason we can't capture this information on the parent before we
call wait3() is that the Linux kernel will release the child memory
ASAP, and only retain the minimal state for the process that is useful
to report the child termination to the parent.

The COW size is obtained by summing all the Private_Dirty fields found
in the "smap" file inside the proc filesystem for the process.

All this is Linux specific and is not available on other systems.
2012-11-19 15:26:02 +01:00
antirez 1d8af6074c zmalloc_get_private_dirty() function added (Linux only).
For non Linux systmes it just returns 0.

This function is useful to estimate copy-on-write because of childs
saving stuff on disk.
2012-11-19 15:25:57 +01:00
antirez 1a706c729a zmalloc: kill unused __size parameter in update_zmalloc_stat_alloc() macro. 2012-11-14 13:07:54 +01:00
antirez 50c41de752 TTL API change: TTL returns -2 for non existing keys.
The previous behavior was to return -1 if:

1) Existing key but without an expire set.
2) Non existing key.

Now the second case is handled in a different, and TTL will return -2
if the key does not exist at all.

PTTL follows the same behavior as well.
2012-11-12 23:05:56 +01:00
antirez 388cc20418 Copyright date fixed in COPYING file. 2012-11-08 19:14:37 +01:00
antirez cda5c0ba06 Make clear that contributing code to the Redis project means to release it under the terms of the BSD license. 2012-11-08 18:43:41 +01:00
antirez 8ddb23b90c BSD license added to every C source and header file. 2012-11-08 18:34:04 +01:00
antirez 46c5d39660 Type mismatch errors are now prefixed with WRONGTYPE.
So instead to reply with a generic error like:

-ERR ... wrong kind of value ...

now it replies with:

-WRONGTYPE ... wrong kind of value ...

This makes this particular error easy to check without resorting to
(fragile) pattern matching of the error string (however the error string
used to be consistent already).

Client libraries should return a specific exeption type for this error.

Most of the commit is about fixing unit tests.
2012-11-06 20:28:15 +01:00
Runzhen Wang 2b28ef0e61 fix a typo in redis.h line 595 comment 2012-11-02 12:12:08 +01:00
antirez 64be5e365a More robust handling of AOF rewrite child.
After the wait3() syscall we used to do something like that:

    if (pid == server.rdb_child_pid) {
        backgroundSaveDoneHandler(exitcode,bysignal);
    } else {
        ....
    }

So the AOF rewrite was handled in the else branch without actually
checking if the pid really matches. This commit makes the check explicit
and logs at WARNING level if the pid returned by wait3() does not match
neither the RDB or AOF rewrite child.
2012-11-01 22:41:54 +01:00
Yecheng Fu fecc8797c2 fix typo in comments (redis.c, networking.c) 2012-11-01 22:26:49 +01:00
antirez d775b35715 Unix socket clients properly displayed in MONITOR and CLIENT LIST.
This also fixes issue #745.
2012-11-01 22:12:50 +01:00
antirez 655e6838fb 32 bit build fixed on Linux.
It failed because of the way jemalloc was compiled (without passing the
right flags to make, but just to configure). Now the same set of flags
are also passed to the make command, fixing the issue.

This fixes issue #744
2012-11-01 15:40:46 +01:00
YAMAMOTO Takashi 428b706308 fix a typo in a comment 2012-10-31 09:30:00 +01:00
antirez 9fab63b334 Invert two sides of if expression in SET to avoid a lookup.
Because of the short circuit behavior of && inverting the two sides of
the if expression avoids an hash table lookup if the non-EX variant of
SET is called.

Thanks to Weibin Yao (@yaoweibin on github) for spotting this.
2012-10-31 09:27:46 +01:00
antirez 537235bbbb No longer used macro rdbIsOpcode() removed. 2012-10-30 19:12:01 +01:00
antirez 38272f961a help.h update (adds bitop, bitcount, evalsha...) 2012-10-30 19:11:57 +01:00
antirez 6c7e957d17 Ctrl+w support in linenoise. 2012-10-30 19:11:46 +01:00
antirez 6bd105032c Marginally more robust glibc version test for sync_file_range detection. 2012-10-30 19:11:41 +01:00
charsyam 72f42cf40c patch config.h for sync_file_range 2012-10-30 19:11:34 +01:00
antirez 2a49aa1da2 Fix compilation on Linux kernels or glibc versions lacking sync_file_range().
This fixes issue #667.

Many thanks to Didier Spezia for the fix.
2012-10-30 19:11:29 +01:00
antirez 24ee20e5ca Update memory peak stats while loading RDB / AOF. 2012-10-30 19:11:23 +01:00
antirez f7b42b1749 2.7.0 branch created as a fork of 2.6.0. 2012-10-22 23:32:26 +02:00
192 changed files with 12928 additions and 4738 deletions
+7 -2
View File
@@ -1,8 +1,13 @@
.*.swp
*.o
*.rdb
*.log
redis-*
dump.rdb
redis-benchmark
redis-check-aof
redis-check-dump
redis-cli
redis-sentinel
redis-server
doc-tools
release
misc/*
+103 -192
View File
@@ -1,9 +1,9 @@
Redis 2.6 release notes
Redis 2.8 release notes
=======================
** IMPORTANT ** Check the 'Migrating from 2.4 to 2.6' section at the end of
this file for information about what changed between 2.4 and
2.6 and how this may affect your application.
** IMPORTANT ** Check the 'Migrating from 2.6 to 2.8' section at the end of
this file for information about what changed between 2.6 and
2.8 and how this may affect your application.
--------------------------------------------------------------------------------
Upgrade urgency levels:
@@ -14,232 +14,143 @@ HIGH: There is a critical bug that may affect a subset of users. Upgrade!
CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
--------------------------------------------------------------------------------
---[ Redis 2.6.0 ]
--[ Redis 2.8.0 ] Release date: 22 Nov 2013
* [BUGFIX] Allow AUTH when server is in -BUSY state because of a slow script.
* [BUGFIX] MULTI/EXEC flow now makes sense when observed in MONITOR
* [BUGFIX] SCRIPT KILL now uses different error prefixes for different errors.
* [BUGFIX] Default memory limit for 32bit archs lowered from 3.5 to 3 GB.
* [BUGFIX] redis-check-dump is now compatible with RDB files generated by 2.6.
* [IMPROVED] New field in INFO: slave_read_only.
# UPGRADE URGENCY: LOW, unless you want to upgrade to new Sentinel code.
---[ Redis 2.5.14 (2.6 Release Candidate 8) ]
* [FIX] Fixed an error in rdbWriteRaw() that should have no practical impact.
* [NEW] Log the new master when SLAVEOF command is used.
* [NEW] Sentinel code synchronized with the unstable branch, the new Sentinel
is a reimplementation that uses more reliable algorithms.
* [BUGFIX] Fixed compilation on FreeBSD.
* [IMPROVED] SRANDMEMBER <count> that returns multiple random elements.
* [IMPROVED] Sentinel backported to 2.6. It will be taken in sync with 2.8.
* [IMPROVED] Helper function for scripting to return errors and status replies.
* [IMPROVED] SORT by nosort [ASC|DESC] uses sorted set elements ordering.
* [BUGFIX] Better resistence to system clock skew.
* [IMPROVED] Warn the user when the configured maxmemory seems odd.
* [BUGFIX] Hashing function is now murmurhash2 for security purposes.
* [IMPROVED] Install script no longer uses a template but redis.conf itself.
--[ Redis 2.8 Release Candidate 6 (2.7.106) ] Release date: 6 Nov 2013
---[ Redis 2.5.13 (2.6 Release Candidate 7) ]
This is the 6th release candidate of Redis 2.8 (official version is 2.7.106).
UPGRADE URGENCY: HIGH
# UPGRADE URGENCY: LOW, only new features back ported, no fixes.
* [BUGFIX] Theoretical bug in ziplist fixed.
* [BUGFIX] Better out of memory handling (Log produced in log file).
* [BUGFIX] Incrementally flush RDB file on slave side while performing the
first synchronization with the master. This makes Redis less
blocking in environments where disk I/O is slow.
* [BUGFIX] Don't crash with Lua's redis.call() without arguments.
* [BUGFIX] Don't crash after a big number of Lua calls on 32 bit systems
because of a failed assertion.
* [BUGFIX] Fix SORT behaviour when called from scripting.
* [BUGFIX] Adjust slave PING period accordingly to REDIS_HZ define.
* [BUGFIX] BITCOUNT: fix crash on overflowing arguments.
* [BUGFIX] Return an error when SELECT argument is not an integer.
* [BUGFIX] Blocking operations on lists were completely reimplemented for
correctness. Now blocking list ops and pushes originated from
Lua scripts will play well together and will be replicated
and transmitted to the AOF correctly.
* [IMPROVED] Send async PING before starting replication to avoid blocking if
master allows us to connect but it is actually not able to reply.
* [IMPROVED] Support slave-priority for Redis Sentinel.
* [IMPROVED] Hiredis library updated.
* [NEW] SCAN, SSCAN, HSCAN, ZSCAN commands.
---[ Redis 2.5.12 (2.6 Release Candidate 6) ]
--[ Redis 2.8 Release Candidate 5 (2.7.105) ] Release date: 9 Oct 2013
UPGRADE URGENCY: MODERATE.
This is the 5th release candidate of Redis 2.8 (official version is 2.7.105).
Important bugs fixed inside.
* [BUGFIX] Fixed a timing attack on AUTH (Issue #560).
* [BUGFIX] Don't assume that "char" is signed.
* [BUGFIX] Check that we have connection before enabling pipe mode.
* [BUGFIX] Use the optimized version of the function to convert a double to
its string representation. Compilation was disabled because of
a typo in the #if statement.
* [IMPROVED} REPLCONF internal command introduced, now INFO shows slaves with
correct port numbers. This makes 2.5.12 Redis Sentinel compatible.
* [IMPROVED] Truncate short write from the AOF for a cleaner restart. On short
writes (for instance out of space) Redis will now try to remove
the half-written data so that the next restart will work without
the need for the "redis-check-aof" utility.
* [IMPROVED] New in INFO: aof_last_bgrewrite_status
* [IMPROVED] Allow Pub/Sub in contexts where other commands are blocked.
* [BUGFIX] mark fd as writable when EPOLLERR or EPOLLHUP is returned by
epoll_wait.
# UPGRADE URGENCY: HIGH because of many non critical replication bugs fixed.
---[ Redis 2.5.11 (2.6 Release Candidate 5) ]
* [FIX] redis-cli: don't crash with --bigkeys when the key no longer exist.
* [FIX] Allow AUTH / PING when disconnected from slave and serve-stale-data is no.
* [FIX] PSYNC: safer handling of PSYNC requests with offsets in the future.
* [FIX] Replication: Fix master timeout detection.
* [FIX] Replication: Correctly install the write handler after successful PSYNC.
UPGRADE URGENCY: HIGH.
--[ Redis 2.8 Release Candidate 4 (2.7.104) ] Release date: 30 Aug 2013
* [BUGFIX] Fixed Hash corruption when loading an RDB file generated by
previous versions of Redis that encoded hashes using
a different ziplist encoding format for small integers.
All the fileds that are integers in the range 0-255 may not
be recognized, or duplicated un updates, causing a crash
when the ziplist is converted to a real hash. (Issue #547).
* [BUGFIX] Fixed the count of memory used by output buffers in the
setDeferredMultiBulkLength() function.
This is the fourth release candidate of Redis 2.8 (official version is 2.7.104).
Important bugs fixed inside.
---[ Redis 2.5.10 (2.6 Release Candidate 4) ]
# UPGRADE URGENCY: HIGH because of the EVAL memory leak.
UPGRADE URGENCY: HIGH.
* [FIX] Fixed a serious EVAL memory leak in the Lua stack.
* [FIX] Fixed server startup when no IPv6 address exists in any interface.
* [FIX] Send MISCONFIG error when BGSAVE fails because can't fork.
* [FIX] Memory efficiency with large (> a few kbytes) values improved considerably.
* [NEW] DEBUG SDSLEN for sds memory debugging.
* [BUGFIX] Allow PREFIX to be overwritten on "make install".
* [BUGFIX] Run the test with just one client if the computer is slow.
* [BUGFIX] Event port support in our event driven libray.
* [BUGFIX] Jemalloc updated to 3.0.0. This fixes a possibly AOF rewrite issue.
See https://github.com/antirez/redis/issues/504 for info.
* [BUGFIX] Fixed issue #516: ZINTERSTORE / ZUNIONSTORE with mixed sets/zsets.
* [BUGFIX] Set fd to writable when poll(2) detects POLLERR or POLLHUP event.
* [BUGFIX] Fixed RESTORE hash failure (Issue #532).
* [IMPROVED] Allow an AOF rewrite buffer > 2GB (Related to issue #504).
* [IMPROVED] Server cron function frequency is now configurable (REDIS_HZ).
* [IMPROVED] Better, less blocking expired keys collection algorithm.
* [FEATURE] New commands: BITOP and BITCOUNT.
* [FEATURE] redis-cli --pipe for mass import.
--[ Redis 2.8 Release Candidate 3 (2.7.103) ] Release date: 19 Aug 2013
What's new in Redis 2.5.9 (aka 2.6 Release Candidate 3)
=======================================================
This is the third release candidate of Redis 2.8 (official version is 2.7.103).
Important bugs fixed inside.
UPGRADE URGENCY: critical, upgrade ASAP.
# UPGRADE URGENCY: HIGH
* [BUGFIX] Fix for issue #500 (https://github.com/antirez/redis/pull/500).
Redis 2.6-RC1 and RC2 may corrupt ziplist-encoded sorted sets
produced by Redis 2.4.x.
* [BUGFIX] Fixed several bugs in init.d script.
* [BUGFIX] syncio.c functions modified for speed and correctness. On osx
(and possibly other BSD-based systems) the slave would block on
replication to send the SYNC command when the master was not
available. This is fixed now, but was not affecting Linux installs.
* Now when slave-serve-stale-data is set to yes and the master is down, instead
of reporting a generic error Redis replies with -MASTERDOWN.
* [FIX] Improved expired keys collection algorithm. Even under heavy load keys
to be expired can't accumulate because of lack of CPU time.
* [FIX] Replication speed regression fixed (issue #1238).
* [FIX] Fixed an hard to trigger PSYNC bug.
* [FIX] Fixed Issue #1240, ZUNIONSTORE could lead to wrong result.
* [NEW] Add per-db average TTL information in INFO output.
* [NEW] redis-benchmark improvements.
* [NEW] dict.c API wrong usage detection.
What's new in Redis 2.5.8 (aka 2.6 Release Candidate 2)
=======================================================
--[ Redis 2.8 Release Candidate 2 (2.7.102) ] Release date: 30 Jul 2013
UPGRADE URGENCY: high for all the users of the KEYS command, otherwise low.
This is the second release candidate of Redis 2.8 (official version is 2.7.102).
Important bugs fixed inside.
* [BUGFIX] Fix for KEYS command: if the DB contains keys with expires the KEYS
command may return the wrong output, having duplicated or missing
keys. See issue #487 and #488 on github for details.
# UPGRADE URGENCY: HIGH
What's new in Redis 2.5.7 (aka 2.6 Release Candidate 1)
=======================================================
* [FIX] Fixed a critical replication bug, see issue #1221.
* [NEW] The new inline protocol now accepts quoted strings like, for example
you can now type in a telnet session: set 'foo bar' "hello world\n".
UPGRADE URGENCY: upgrade not recommended because this is an RC release.
--[ Redis 2.8 Release Candidate 1 (2.7.101) ] Release date: 18 Jul 2013
* This is the first release candidate for Redis 2.6. We are not aware of
bugs, but part of this code is young and was never tested in production
environments, so handle with care.
This is the first release candidate of Redis 2.8 (official version is 2.7.101).
An overview of new features and changes in Redis 2.6.x
======================================================
The following is a list of improvements in Redis 2.8, compared to Redis 2.6.
* 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, ...).
* Better memory usage for "small" lists, ziplists and hashes when fields or
values contain small integers.
* Read only slaves.
* New bit opeations: BITCOUNT and BITOP commands.
* Clients max output buffer soft and hard limits. You can specifiy different
limits for different classes of clients (normal,pubsub,slave).
* More incremental (less blocking) expired keys collection algorithm, in
practical terms this means that Redis is more responsive when a very
big number of keys expire about at the same time.
* 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.
* Integrated memory test, see redis-server --test-memory.
* INCRBYFLOAT and HINCRBYFLOAT commands.
* New DUMP, RESTORE, MIGRATE commands (back ported from Redis Cluster to 2.6).
* CRC64 checksump in RDB files.
* Better MONITOR output and behavior (now commands are logged before execution).
* "Software Watchdog" feature to debug latency issues.
* 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.
* Better support for big endian and *BSD systems.
* Build system improved.
* [NEW] Slaves are now able to partially resynchronize with the master, so most
of the times a full resynchronization with the RDB creation in the master
side is not needed when the master-slave link is disconnected for a short
amount of time.
* [NEW] Experimental IPv6 support.
* [NEW] Slaves explicitly ping masters now, a master is able to detect a timed out
slave independently.
* [NEW] Masters can stop accepting writes if not enough slaves with a given
maximum latency are connected.
* [NEW] Keyspace changes notifications via Pub/Sub.
* [NEW] CONFIG SET maxclients is now available.
* [NEW] Ability to bind multiple IP addresses.
* [NEW] Set process names so that you can recognize, in the "ps" command output,
the listening port of an instance, or if it is a saving child.
* [NEW] Automatic memory check on crash.
* [NEW] CONFIG REWRITE is able to materialize the changes in the configuration
operated using CONFIG SET into the redis.conf file.
* [NEW] More NetBSD friendly code base.
* [NEW] PUBSUB command for Pub/Sub introspection capabilities.
* [NEW] EVALSHA can now be replicated as such, without requiring to be expanded
to a full EVAL for the replication link.
* [NEW] Better Lua scripts error reporting.
* [NEW] SDIFF performance improved.
* [FIX] A number of bugfixes.
Migrating from 2.4 to 2.6
Migrating from 2.6 to 2.8
=========================
Redis 2.4 is mostly a strict subset of 2.6. However there are a few things
Redis 2.6 is mostly a strict subset of 2.8. 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.6 slaves can be attached to 2.4 masters, but not the contrary, and only
for the time needed to perform the version upgrade.
The following commands changed behavior:
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.
* Slaves are only read-only by default (but you can change this easily
setting the "slave-read-only" configuration option to "no" editing your
redis.conf or using CONFIG SET.
The following INFO fields were renamed for consistency:
changes_since_last_save -> rdb_changes_since_last_save
bgsave_in_progress -> rdb_bgsave_in_progress
last_save_time -> rdb_last_save_time
last_bgsave_status -> rdb_last_bgsave_status
bgrewriteaof_in_progress -> aof_rewrite_in_progress
bgrewriteaof_scheduled -> aof_rewrite_scheduled
* SORT with ALPHA now sorts according to local collation locale if no STORE
option is used.
* ZADD/ZINCRBY are now able to accept a bigger range of values as valid
scores, that is, all the values you may end having as a result of
calling ZINCRBY multiple times.
* Many errors are now prefixed by a more specific error code instead of
the generic -ERR, for example -WRONGTYPE, -NOAUTH, ...
* PUBLISH called inside Lua scripts is now correctly propagated to slaves.
The following redis.conf and CONFIG GET / SET parameters changed:
* hash-max-zipmap-entries, now replaced by hash-max-ziplist-entries
* hash-max-zipmap-value, now replaced by hash-max-ziplist-value
* glueoutputbuf option was now completely removed (was deprecated)
* logfile now uses the empty string in order to log to standard output,
so 'logfile stdout' is now invalid, use 'logfile ""' instead.
The following INFO fields changed format in a non-backward compatible way:
* The list of slaves in INFO is now in field=value format.
Replication:
Redis 2.8 can be used as slave for Redis 2.6, but doing this is only
a good idea for the short amount of time needed to upgrade your servers.
We suggest to update both master and slaves at about the same time.
--------------------------------------------------------------------------------
Credits: Where not specified the implementation and design are done by
Salvatore Sanfilippo and Pieter Noordhuis. Thanks to VMware for making all
Credits: Where not specified the implementation and design is done by
Salvatore Sanfilippo. Thanks to VMware and Pivotal for making all
this possible. Also many thanks to all the other contributors and the amazing
community we have.
+7
View File
@@ -1,3 +1,10 @@
Note: by contributing code to the Redis project in any form, including sending
a pull request via Github, a code fragment or patch via private email or
public discussion groups, you agree to release your code under the terms
of the BSD license that you can find in the COPYING file included in the Redis
source distribution. You will include BSD license in the COPYING file within
each source file that you contribute.
# IMPORTANT: HOW TO USE REDIS GITHUB ISSUES
* Github issues SHOULD ONLY BE USED to report bugs, and for DETAILED feature
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2006-2009, Salvatore Sanfilippo
Copyright (c) 2006-2012, Salvatore Sanfilippo
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-1032
View File
File diff suppressed because it is too large Load Diff
+55 -8
View File
@@ -4,17 +4,64 @@
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.
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.
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.
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.
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.
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.
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.
+26 -3
View File
@@ -26,9 +26,20 @@ After building Redis is a good idea to test it, using:
% make test
NOTE: if after building Redis with a 32 bit target you need to rebuild it
with a 64 bit target you need to perform a "make clean" in the root
directory of the Redis distribution.
Fixing problems building 32 bit binaries
---------
If after building Redis with a 32 bit target you need to rebuild it
with a 64 bit target, or the other way around, you need to perform a
"make distclean" in the root directory of the Redis distribution.
In case of build errors when trying to build a 32 bit binary of Redis, try
the following steps:
* Install the packages libc6-dev-i386 (also try g++-multilib).
* Try using the following command line instead of "make 32bit":
make CFLAGS="-m32 -march=native" LDFLAGS="-m32"
Allocator
---------
@@ -128,4 +139,16 @@ system reboots.
You'll be able to stop and start Redis using the script named
/etc/init.d/redis_<portnumber>, for instance /etc/init.d/redis_6379.
Code contributions
---
Note: by contributing code to the Redis project in any form, including sending
a pull request via Github, a code fragment or patch via private email or
public discussion groups, you agree to release your code under the terms
of the BSD license that you can find in the COPYING file included in the Redis
source distribution.
Please see the CONTRIBUTING file in this source distribution for more
information.
Enjoy!
+3 -3
View File
@@ -54,8 +54,8 @@ linenoise: .make-prerequisites
.PHONY: linenoise
ifeq ($(uname_S),SunOS)
# Make isinf() available
LUA_CFLAGS= -D__C99FEATURES__=1
# Make isinf() available
LUA_CFLAGS= -D__C99FEATURES__=1
endif
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI $(CFLAGS)
@@ -73,6 +73,6 @@ JEMALLOC_LDFLAGS= $(LDFLAGS)
jemalloc: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd jemalloc && ./configure --with-jemalloc-prefix=je_ --enable-cc-silence CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)"
cd jemalloc && $(MAKE) lib/libjemalloc.a
cd jemalloc && $(MAKE) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
.PHONY: jemalloc
+30
View File
@@ -1,3 +1,33 @@
/*
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis 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 __HIREDIS_AE_H__
#define __HIREDIS_AE_H__
#include <sys/types.h>
+30
View File
@@ -1,3 +1,33 @@
/*
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis 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 __HIREDIS_LIBEV_H__
#define __HIREDIS_LIBEV_H__
#include <stdlib.h>
+30
View File
@@ -1,3 +1,33 @@
/*
* Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis 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 __HIREDIS_LIBEVENT_H__
#define __HIREDIS_LIBEVENT_H__
#include <event.h>
+1 -1
View File
@@ -7,7 +7,7 @@
#if defined(__sun__)
#define _POSIX_C_SOURCE 200112L
#elif defined(__linux__)
#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE
+2 -2
View File
@@ -650,7 +650,7 @@ int redisReaderGetReply(redisReader *r, void **reply) {
/* Discard part of the buffer when we've consumed at least 1k, to avoid
* doing unnecessary calls to memmove() in sds.c. */
if (r->pos >= 1024) {
r->buf = sdsrange(r->buf,r->pos,-1);
sdsrange(r->buf,r->pos,-1);
r->pos = 0;
r->len = sdslen(r->buf);
}
@@ -1125,7 +1125,7 @@ int redisBufferWrite(redisContext *c, int *done) {
sdsfree(c->obuf);
c->obuf = sdsempty();
} else {
c->obuf = sdsrange(c->obuf,nwritten,-1);
sdsrange(c->obuf,nwritten,-1);
}
}
}
+10 -2
View File
@@ -215,9 +215,17 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
/* Try with IPv6 if no IPv4 address was found. We do it in this order since
* in a Redis client you can't afford to test if you have IPv6 connectivity
* as this would add latency to every connect. Otherwise a more sensible
* route could be: Use IPv6 if both addresses are available and there is IPv6
* connectivity. */
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
return REDIS_ERR;
hints.ai_family = AF_INET6;
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
__redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv));
return REDIS_ERR;
}
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
+386 -109
View File
@@ -1,6 +1,6 @@
/* SDSLib, A C dynamic strings library
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,52 +32,76 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "sds.h"
#include "zmalloc.h"
#ifdef SDS_ABORT_ON_OOM
static void sdsOomAbort(void) {
fprintf(stderr,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
abort();
}
#endif
/* Create a new sds string with the content specified by the 'init' pointer
* and 'initlen'.
* If NULL is used for 'init' the string is initialized with zero bytes.
*
* The string is always null-termined (all the sds strings are, always) so
* even if you create an sds string with:
*
* mystring = sdsnewlen("abc",3");
*
* You can print the string with printf() as there is an implicit \0 at the
* end of the string. However the string is binary safe and can contain
* \0 characters in the middle, as the length is stored in the sds header. */
sds sdsnewlen(const void *init, size_t initlen) {
struct sdshdr *sh;
sh = malloc(sizeof(struct sdshdr)+initlen+1);
#ifdef SDS_ABORT_ON_OOM
if (sh == NULL) sdsOomAbort();
#else
if (init) {
sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
} else {
sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
}
if (sh == NULL) return NULL;
#endif
sh->len = initlen;
sh->free = 0;
if (initlen) {
if (init) memcpy(sh->buf, init, initlen);
else memset(sh->buf,0,initlen);
}
if (initlen && init)
memcpy(sh->buf, init, initlen);
sh->buf[initlen] = '\0';
return (char*)sh->buf;
}
/* Create an empty (zero length) sds string. Even in this case the string
* always has an implicit null term. */
sds sdsempty(void) {
return sdsnewlen("",0);
}
/* Create a new sds string starting from a null termined C string. */
sds sdsnew(const char *init) {
size_t initlen = (init == NULL) ? 0 : strlen(init);
return sdsnewlen(init, initlen);
}
/* Duplicate an sds string. */
sds sdsdup(const sds s) {
return sdsnewlen(s, sdslen(s));
}
/* Free an sds string. No operation is performed if 's' is NULL. */
void sdsfree(sds s) {
if (s == NULL) return;
free(s-sizeof(struct sdshdr));
zfree(s-sizeof(struct sdshdr));
}
/* Set the sds string length to the length as obtained with strlen(), so
* considering as content only up to the first null term character.
*
* This function is useful when the sds string is hacked manually in some
* way, like in the following example:
*
* s = sdsnew("foobar");
* s[2] = '\0';
* sdsupdatelen(s);
* printf("%d\n", sdslen(s));
*
* The output will be "2", but if we comment out the call to sdsupdatelen()
* the output will be "6" as the string was modified but the logical length
* remains 6 bytes. */
void sdsupdatelen(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
int reallen = strlen(s);
@@ -85,7 +109,24 @@ void sdsupdatelen(sds s) {
sh->len = reallen;
}
static sds sdsMakeRoomFor(sds s, size_t addlen) {
/* Modify an sds string on-place to make it empty (zero length).
* However all the existing buffer is not discarded but set as free space
* so that next append operations will not require allocations up to the
* number of bytes previously available. */
void sdsclear(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
sh->free += sh->len;
sh->len = 0;
sh->buf[0] = '\0';
}
/* Enlarge the free space at the end of the sds string so that the caller
* is sure that after calling this function can overwrite up to addlen
* bytes after the end of the string, plus one more byte for nul term.
*
* Note: this does not change the *length* of the sds string as returned
* by sdslen(), but only the free buffer space we have. */
sds sdsMakeRoomFor(sds s, size_t addlen) {
struct sdshdr *sh, *newsh;
size_t free = sdsavail(s);
size_t len, newlen;
@@ -93,20 +134,84 @@ static sds sdsMakeRoomFor(sds s, size_t addlen) {
if (free >= addlen) return s;
len = sdslen(s);
sh = (void*) (s-(sizeof(struct sdshdr)));
newlen = (len+addlen)*2;
newsh = realloc(sh, sizeof(struct sdshdr)+newlen+1);
#ifdef SDS_ABORT_ON_OOM
if (newsh == NULL) sdsOomAbort();
#else
newlen = (len+addlen);
if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
else
newlen += SDS_MAX_PREALLOC;
newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);
if (newsh == NULL) return NULL;
#endif
newsh->free = newlen - len;
return newsh->buf;
}
/* Reallocate the sds string so that it has no free space at the end. The
* contained string remains not altered, but next concatenation operations
* will require a reallocation.
*
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds sdsRemoveFreeSpace(sds s) {
struct sdshdr *sh;
sh = (void*) (s-(sizeof(struct sdshdr)));
sh = zrealloc(sh, sizeof(struct sdshdr)+sh->len+1);
sh->free = 0;
return sh->buf;
}
/* Return the total size of the allocation of the specifed sds string,
* including:
* 1) The sds header before the pointer.
* 2) The string.
* 3) The free buffer at the end if any.
* 4) The implicit null term.
*/
size_t sdsAllocSize(sds s) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
return sizeof(*sh)+sh->len+sh->free+1;
}
/* Increment the sds length and decrements the left free space at the
* end of the string according to 'incr'. Also set the null term
* in the new end of the string.
*
* This function is used in order to fix the string length after the
* user calls sdsMakeRoomFor(), writes something after the end of
* the current string, and finally needs to set the new length.
*
* Note: it is possible to use a negative increment in order to
* right-trim the string.
*
* Usage example:
*
* Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
* following schema, to cat bytes coming from the kernel to the end of an
* sds string without copying into an intermediate buffer:
*
* oldlen = sdslen(s);
* s = sdsMakeRoomFor(s, BUFFER_SIZE);
* nread = read(fd, s+oldlen, BUFFER_SIZE);
* ... check for nread <= 0 and handle it ...
* sdsIncrLen(s, nread);
*/
void sdsIncrLen(sds s, int incr) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
assert(sh->free >= incr);
sh->len += incr;
sh->free -= incr;
assert(sh->free >= 0);
s[sh->len] = '\0';
}
/* Grow the sds to have the specified length. Bytes that were not part of
* the original length of the sds will be set to zero. */
* the original length of the sds will be set to zero.
*
* if the specified length is smaller than the current length, no operation
* is performed. */
sds sdsgrowzero(sds s, size_t len) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
size_t totlen, curlen = sh->len;
@@ -124,6 +229,11 @@ sds sdsgrowzero(sds s, size_t len) {
return s;
}
/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
* end of the specified sds string 's'.
*
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds sdscatlen(sds s, const void *t, size_t len) {
struct sdshdr *sh;
size_t curlen = sdslen(s);
@@ -138,11 +248,25 @@ sds sdscatlen(sds s, const void *t, size_t len) {
return s;
}
/* Append the specified null termianted C string to the sds string 's'.
*
* After the call, the passed sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds sdscat(sds s, const char *t) {
return sdscatlen(s, t, strlen(t));
}
sds sdscpylen(sds s, char *t, size_t len) {
/* Append the specified sds 't' to the existing sds 's'.
*
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds sdscatsds(sds s, const sds t) {
return sdscatlen(s, t, sdslen(t));
}
/* Destructively modify the sds string 's' to hold the specified binary
* safe string pointed by 't' of length 'len' bytes. */
sds sdscpylen(sds s, const char *t, size_t len) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
size_t totlen = sh->free+sh->len;
@@ -159,37 +283,52 @@ sds sdscpylen(sds s, char *t, size_t len) {
return s;
}
sds sdscpy(sds s, char *t) {
/* Like sdscpylen() but 't' must be a null-termined string so that the length
* of the string is obtained with strlen(). */
sds sdscpy(sds s, const char *t) {
return sdscpylen(s, t, strlen(t));
}
/* Like sdscatpritf() but gets va_list instead of being variadic. */
sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
va_list cpy;
char *buf, *t;
size_t buflen = 16;
while(1) {
buf = malloc(buflen);
#ifdef SDS_ABORT_ON_OOM
if (buf == NULL) sdsOomAbort();
#else
buf = zmalloc(buflen);
if (buf == NULL) return NULL;
#endif
buf[buflen-2] = '\0';
va_copy(cpy,ap);
vsnprintf(buf, buflen, fmt, cpy);
if (buf[buflen-2] != '\0') {
free(buf);
zfree(buf);
buflen *= 2;
continue;
}
break;
}
t = sdscat(s, buf);
free(buf);
zfree(buf);
return t;
}
/* Append to the sds string 's' a string obtained using printf-alike format
* specifier.
*
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call.
*
* Example:
*
* s = sdsempty("Sum is: ");
* s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
*
* Often you need to create a string from scratch with the printf-alike
* format. When this is the need, just use sdsempty() as the target string:
*
* s = sdscatprintf(sdsempty(), "... your format ...", args);
*/
sds sdscatprintf(sds s, const char *fmt, ...) {
va_list ap;
char *t;
@@ -199,6 +338,20 @@ sds sdscatprintf(sds s, const char *fmt, ...) {
return t;
}
/* Remove the part of the string from left and from right composed just of
* contiguous characters found in 'cset', that is a null terminted C string.
*
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call.
*
* Example:
*
* s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
* s = sdstrim(s,"A. :");
* printf("%s\n", s);
*
* Output will be just "Hello World".
*/
sds sdstrim(sds s, const char *cset) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
char *start, *end, *sp, *ep;
@@ -216,11 +369,27 @@ sds sdstrim(sds s, const char *cset) {
return s;
}
sds sdsrange(sds s, int start, int end) {
/* Turn the string into a smaller (or equal) string containing only the
* substring specified by the 'start' and 'end' indexes.
*
* start and end can be negative, where -1 means the last character of the
* string, -2 the penultimate character, and so forth.
*
* The interval is inclusive, so the start and end characters will be part
* of the resulting string.
*
* The string is modified in-place.
*
* Example:
*
* s = sdsnew("Hello World");
* sdstrim(s,1,-1); => "ello Worl"
*/
void sdsrange(sds s, int start, int end) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
size_t newlen, len = sdslen(s);
if (len == 0) return s;
if (len == 0) return;
if (start < 0) {
start = len+start;
if (start < 0) start = 0;
@@ -244,22 +413,34 @@ sds sdsrange(sds s, int start, int end) {
sh->buf[newlen] = 0;
sh->free = sh->free+(sh->len-newlen);
sh->len = newlen;
return s;
}
/* Apply tolower() to every character of the sds string 's'. */
void sdstolower(sds s) {
int len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = tolower(s[j]);
}
/* Apply toupper() to every character of the sds string 's'. */
void sdstoupper(sds s) {
int len = sdslen(s), j;
for (j = 0; j < len; j++) s[j] = toupper(s[j]);
}
int sdscmp(sds s1, sds s2) {
/* Compare two sds strings s1 and s2 with memcmp().
*
* Return value:
*
* 1 if s1 > s2.
* -1 if s1 < s2.
* 0 if s1 and s2 are exactly the same binary string.
*
* If two strings share exactly the same prefix, but one of the two has
* additional characters, the longer string is considered to be greater than
* the smaller one. */
int sdscmp(const sds s1, const sds s2) {
size_t l1, l2, minlen;
int cmp;
@@ -287,14 +468,15 @@ int sdscmp(sds s1, sds s2) {
* requires length arguments. sdssplit() is just the
* same function but for zero-terminated strings.
*/
sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
int elements = 0, slots = 5, start = 0, j;
sds *tokens;
if (seplen < 1 || len < 0) return NULL;
tokens = zmalloc(sizeof(sds)*slots);
if (tokens == NULL) return NULL;
sds *tokens = malloc(sizeof(sds)*slots);
#ifdef SDS_ABORT_ON_OOM
if (tokens == NULL) sdsOomAbort();
#endif
if (seplen < 1 || len < 0 || tokens == NULL) return NULL;
if (len == 0) {
*count = 0;
return tokens;
@@ -305,26 +487,14 @@ sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
sds *newtokens;
slots *= 2;
newtokens = realloc(tokens,sizeof(sds)*slots);
if (newtokens == NULL) {
#ifdef SDS_ABORT_ON_OOM
sdsOomAbort();
#else
goto cleanup;
#endif
}
newtokens = zrealloc(tokens,sizeof(sds)*slots);
if (newtokens == NULL) goto cleanup;
tokens = newtokens;
}
/* search the separator */
if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
tokens[elements] = sdsnewlen(s+start,j-start);
if (tokens[elements] == NULL) {
#ifdef SDS_ABORT_ON_OOM
sdsOomAbort();
#else
goto cleanup;
#endif
}
if (tokens[elements] == NULL) goto cleanup;
elements++;
start = j+seplen;
j = j+seplen-1; /* skip the separator */
@@ -332,35 +502,33 @@ sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count) {
}
/* Add the final element. We are sure there is room in the tokens array. */
tokens[elements] = sdsnewlen(s+start,len-start);
if (tokens[elements] == NULL) {
#ifdef SDS_ABORT_ON_OOM
sdsOomAbort();
#else
goto cleanup;
#endif
}
if (tokens[elements] == NULL) goto cleanup;
elements++;
*count = elements;
return tokens;
#ifndef SDS_ABORT_ON_OOM
cleanup:
{
int i;
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
free(tokens);
zfree(tokens);
*count = 0;
return NULL;
}
#endif
}
/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
void sdsfreesplitres(sds *tokens, int count) {
if (!tokens) return;
while(count--)
sdsfree(tokens[count]);
free(tokens);
zfree(tokens);
}
/* Create an sds string from a long long value. It is much faster than:
*
* sdscatprintf(sdsempty(),"%lld\n", value);
*/
sds sdsfromlonglong(long long value) {
char buf[32], *p;
unsigned long long v;
@@ -376,10 +544,14 @@ sds sdsfromlonglong(long long value) {
return sdsnewlen(p,32-(p-buf));
}
sds sdscatrepr(sds s, char *p, size_t len) {
/* Append to the sds string "s" an escaped string representation where
* all the non-printable characters (tested with isprint()) are turned into
* escapes in the form "\n\r\a...." or "\x<hex-number>".
*
* After the call, the modified sds string is no longer valid and all the
* references must be substituted with the new pointer returned by the call. */
sds sdscatrepr(sds s, const char *p, size_t len) {
s = sdscatlen(s,"\"",1);
if (s == NULL) return NULL;
while(len--) {
switch(*p) {
case '\\':
@@ -399,27 +571,64 @@ sds sdscatrepr(sds s, char *p, size_t len) {
break;
}
p++;
if (s == NULL) return NULL;
}
return sdscatlen(s,"\"",1);
}
/* Helper function for sdssplitargs() that returns non zero if 'c'
* is a valid hex digit. */
int is_hex_digit(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F');
}
/* Helper function for sdssplitargs() that converts an hex digit into an
* integer from 0 to 15 */
int hex_digit_to_int(char c) {
switch(c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default: return 0;
}
}
/* Split a line into arguments, where every argument can be in the
* following programming-language REPL-alike form:
*
* foo bar "newline are supported\n" and "\xff\x00otherstuff"
*
* The number of arguments is stored into *argc, and an array
* of sds is returned. The caller should sdsfree() all the returned
* strings and finally free() the array itself.
* of sds is returned.
*
* The caller should free the resulting array of sds strings with
* sdsfreesplitres().
*
* Note that sdscatrepr() is able to convert back a string into
* a quoted string in the same format sdssplitargs() is able to parse.
*
* The function returns the allocated tokens on success, even when the
* input string is empty, or NULL if the input contains unbalanced
* quotes or closed quotes followed by non space characters
* as in: "foo"bar or "foo'
*/
sds *sdssplitargs(char *line, int *argc) {
char *p = line;
sds *sdssplitargs(const char *line, int *argc) {
const char *p = line;
char *current = NULL;
char **vector = NULL, **_vector = NULL;
char **vector = NULL;
*argc = 0;
while(1) {
@@ -427,17 +636,24 @@ sds *sdssplitargs(char *line, int *argc) {
while(*p && isspace(*p)) p++;
if (*p) {
/* get a token */
int inq=0; /* set to 1 if we are in "quotes" */
int inq=0; /* set to 1 if we are in "quotes" */
int insq=0; /* set to 1 if we are in 'single quotes' */
int done=0;
if (current == NULL) {
current = sdsempty();
if (current == NULL) goto err;
}
if (current == NULL) current = sdsempty();
while(!done) {
if (inq) {
if (*p == '\\' && *(p+1)) {
if (*p == '\\' && *(p+1) == 'x' &&
is_hex_digit(*(p+2)) &&
is_hex_digit(*(p+3)))
{
unsigned char byte;
byte = (hex_digit_to_int(*(p+2))*16)+
hex_digit_to_int(*(p+3));
current = sdscatlen(current,(char*)&byte,1);
p += 3;
} else if (*p == '\\' && *(p+1)) {
char c;
p++;
@@ -451,7 +667,23 @@ sds *sdssplitargs(char *line, int *argc) {
}
current = sdscatlen(current,&c,1);
} else if (*p == '"') {
/* closing quote must be followed by a space */
/* closing quote must be followed by a space or
* nothing at all. */
if (*(p+1) && !isspace(*(p+1))) goto err;
done=1;
} else if (!*p) {
/* unterminated quotes */
goto err;
} else {
current = sdscatlen(current,p,1);
}
} else if (insq) {
if (*p == '\\' && *(p+1) == '\'') {
p++;
current = sdscatlen(current,"'",1);
} else if (*p == '\'') {
/* closing quote must be followed by a space or
* nothing at all. */
if (*(p+1) && !isspace(*(p+1))) goto err;
done=1;
} else if (!*p) {
@@ -472,23 +704,24 @@ sds *sdssplitargs(char *line, int *argc) {
case '"':
inq=1;
break;
case '\'':
insq=1;
break;
default:
current = sdscatlen(current,p,1);
break;
}
}
if (*p) p++;
if (current == NULL) goto err;
}
/* add the token to the vector */
_vector = realloc(vector,((*argc)+1)*sizeof(char*));
if (_vector == NULL) goto err;
vector = _vector;
vector = zrealloc(vector,((*argc)+1)*sizeof(char*));
vector[*argc] = current;
(*argc)++;
current = NULL;
} else {
/* Even on empty input string return something not NULL. */
if (vector == NULL) vector = zmalloc(sizeof(void*));
return vector;
}
}
@@ -496,30 +729,55 @@ sds *sdssplitargs(char *line, int *argc) {
err:
while((*argc)--)
sdsfree(vector[*argc]);
if (vector != NULL) free(vector);
if (current != NULL) sdsfree(current);
zfree(vector);
if (current) sdsfree(current);
*argc = 0;
return NULL;
}
/* Modify the string substituting all the occurrences of the set of
* characters specified in the 'from' string to the corresponding character
* in the 'to' array.
*
* For instance: sdsmapchars(mystring, "ho", "01", 2)
* will have the effect of turning the string "hello" into "0ell1".
*
* The function returns the sds string pointer, that is always the same
* as the input pointer since no resize is needed. */
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
size_t j, i, l = sdslen(s);
for (j = 0; j < l; j++) {
for (i = 0; i < setlen; i++) {
if (s[j] == from[i]) {
s[j] = to[i];
break;
}
}
}
return s;
}
/* Join an array of C strings using the specified separator (also a C string).
* Returns the result as an sds string. */
sds sdsjoin(char **argv, int argc, char *sep) {
sds join = sdsempty();
int j;
for (j = 0; j < argc; j++) {
join = sdscat(join, argv[j]);
if (j != argc-1) join = sdscat(join,sep);
}
return join;
}
#ifdef SDS_TEST_MAIN
#include <stdio.h>
int __failed_tests = 0;
int __test_num = 0;
#define test_cond(descr,_c) do { \
__test_num++; printf("%d - %s: ", __test_num, descr); \
if(_c) printf("PASSED\n"); else {printf("FAILED\n"); __failed_tests++;} \
} while(0);
#define test_report() do { \
printf("%d tests, %d passed, %d failed\n", __test_num, \
__test_num-__failed_tests, __failed_tests); \
if (__failed_tests) { \
printf("=== WARNING === We have failed tests here...\n"); \
} \
} while(0);
#include "testhelp.h"
int main(void) {
{
struct sdshdr *sh;
sds x = sdsnew("foo"), y;
test_cond("Create a string and obtain the length",
@@ -599,7 +857,26 @@ int main(void) {
x = sdsnew("aar");
y = sdsnew("bar");
test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
{
int oldfree;
sdsfree(x);
x = sdsnew("0");
sh = (void*) (x-(sizeof(struct sdshdr)));
test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0);
x = sdsMakeRoomFor(x,1);
sh = (void*) (x-(sizeof(struct sdshdr)));
test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0);
oldfree = sh->free;
x[1] = '1';
sdsIncrLen(x,1);
test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1');
test_cond("sdsIncrLen() -- len", sh->len == 2);
test_cond("sdsIncrLen() -- free", sh->free == oldfree-1);
}
}
test_report()
return 0;
}
#endif
+20 -8
View File
@@ -31,6 +31,8 @@
#ifndef __SDS_H
#define __SDS_H
#define SDS_MAX_PREALLOC (1024*1024)
#include <sys/types.h>
#include <stdarg.h>
@@ -58,12 +60,13 @@ sds sdsempty(void);
size_t sdslen(const sds s);
sds sdsdup(const sds s);
void sdsfree(sds s);
size_t sdsavail(sds s);
size_t sdsavail(const sds s);
sds sdsgrowzero(sds s, size_t len);
sds sdscatlen(sds s, const void *t, size_t len);
sds sdscat(sds s, const char *t);
sds sdscpylen(sds s, char *t, size_t len);
sds sdscpy(sds s, char *t);
sds sdscatsds(sds s, const sds t);
sds sdscpylen(sds s, const char *t, size_t len);
sds sdscpy(sds s, const char *t);
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
#ifdef __GNUC__
@@ -74,15 +77,24 @@ sds sdscatprintf(sds s, const char *fmt, ...);
#endif
sds sdstrim(sds s, const char *cset);
sds sdsrange(sds s, int start, int end);
void sdsrange(sds s, int start, int end);
void sdsupdatelen(sds s);
int sdscmp(sds s1, sds s2);
sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count);
void sdsclear(sds s);
int sdscmp(const sds s1, const sds s2);
sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
void sdsfreesplitres(sds *tokens, int count);
void sdstolower(sds s);
void sdstoupper(sds s);
sds sdsfromlonglong(long long value);
sds sdscatrepr(sds s, char *p, size_t len);
sds *sdssplitargs(char *line, int *argc);
sds sdscatrepr(sds s, const char *p, size_t len);
sds *sdssplitargs(const char *line, int *argc);
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
sds sdsjoin(char **argv, int argc, char *sep);
/* Low level functions exposed to the user API */
sds sdsMakeRoomFor(sds s, size_t addlen);
void sdsIncrLen(sds s, int incr);
sds sdsRemoveFreeSpace(sds s);
size_t sdsAllocSize(sds s);
#endif
+13
View File
@@ -0,0 +1,13 @@
/* Drop in replacement for zmalloc.h in order to just use libc malloc without
* any wrappering. */
#ifndef ZMALLOC_H
#define ZMALLOC_H
#define zmalloc malloc
#define zrealloc realloc
#define zcalloc(x) calloc(x,1)
#define zfree free
#define zstrdup strdup
#endif
+1 -6
View File
@@ -2,24 +2,19 @@
/config.stamp
/config.log
/config.status
/configure
/doc/html.xsl
/doc/manpages.xsl
/doc/jemalloc.xml
/doc/jemalloc.html
/doc/jemalloc.3
/lib/
/Makefile
/include/jemalloc/internal/jemalloc_internal\.h
/include/jemalloc/internal/size_classes\.h
/include/jemalloc/jemalloc\.h
/include/jemalloc/jemalloc_defs\.h
/test/jemalloc_test\.h
/src/*.[od]
/test/*.[od]
/test/*.out
/test/[a-z]*
/test/[a-zA-Z_]*
!test/*.c
!test/*.exp
/VERSION
/bin/jemalloc.sh
+41
View File
@@ -6,6 +6,47 @@ found in the git revision history:
http://www.canonware.com/cgi-bin/gitweb.cgi?p=jemalloc.git
git://canonware.com/jemalloc.git
* 3.2.0 (November 9, 2012)
In addition to a couple of bug fixes, this version modifies page run
allocation and dirty page purging algorithms in order to better control
page-level virtual memory fragmentation.
Incompatible changes:
- Change the "opt.lg_dirty_mult" default from 5 to 3 (32:1 to 8:1).
Bug fixes:
- Fix dss/mmap allocation precedence code to use recyclable mmap memory only
after primary dss allocation fails.
- Fix deadlock in the "arenas.purge" mallctl. This regression was introduced
in 3.1.0 by the addition of the "arena.<i>.purge" mallctl.
* 3.1.0 (October 16, 2012)
New features:
- Auto-detect whether running inside Valgrind, thus removing the need to
manually specify MALLOC_CONF=valgrind:true.
- Add the "arenas.extend" mallctl, which allows applications to create
manually managed arenas.
- Add the ALLOCM_ARENA() flag for {,r,d}allocm().
- Add the "opt.dss", "arena.<i>.dss", and "stats.arenas.<i>.dss" mallctls,
which provide control over dss/mmap precedence.
- Add the "arena.<i>.purge" mallctl, which obsoletes "arenas.purge".
- Define LG_QUANTUM for hppa.
Incompatible changes:
- Disable tcache by default if running inside Valgrind, in order to avoid
making unallocated objects appear reachable to Valgrind.
- Drop const from malloc_usable_size() argument on Linux.
Bug fixes:
- Fix heap profiling crash if sampled object is freed via realloc(p, 0).
- Remove const from __*_hook variable declarations, so that glibc can modify
them during process forking.
- Fix mlockall(2)/madvise(2) interaction.
- Fix fork(2)-related deadlocks.
- Fix error return value for "thread.tcache.enabled" mallctl.
* 3.0.0 (May 11, 2012)
Although this version adds some major new features, the primary focus is on
+3 -3
View File
@@ -101,9 +101,9 @@ DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.html)
DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(srcroot)%.3)
DOCS := $(DOCS_HTML) $(DOCS_MAN3)
CTESTS := $(srcroot)test/aligned_alloc.c $(srcroot)test/allocated.c \
$(srcroot)test/bitmap.c $(srcroot)test/mremap.c \
$(srcroot)test/posix_memalign.c $(srcroot)test/thread_arena.c \
$(srcroot)test/thread_tcache_enabled.c
$(srcroot)test/ALLOCM_ARENA.c $(srcroot)test/bitmap.c \
$(srcroot)test/mremap.c $(srcroot)test/posix_memalign.c \
$(srcroot)test/thread_arena.c $(srcroot)test/thread_tcache_enabled.c
ifeq ($(enable_experimental), 1)
CTESTS += $(srcroot)test/allocm.c $(srcroot)test/rallocm.c
endif
+1 -1
View File
@@ -1 +1 @@
3.0.0-0-gfc9b1dbf69f59d7ecfc4ac68da9847e017e1d046
3.2.0-0-g87499f6748ebe4817571e817e9f680ccb5bf54a9
+6
View File
@@ -4426,6 +4426,7 @@ MKLIB='ar crus $@'
CC_MM=1
default_munmap="1"
JEMALLOC_USABLE_SIZE_CONST="const"
case "${host}" in
*-*-darwin*)
CFLAGS="$CFLAGS"
@@ -4455,6 +4456,7 @@ case "${host}" in
$as_echo "#define JEMALLOC_THREADED_INIT " >>confdefs.h
JEMALLOC_USABLE_SIZE_CONST=""
default_munmap="0"
;;
*-*-netbsd*)
@@ -4530,6 +4532,10 @@ $as_echo "Unsupported operating system: ${host}" >&6; }
abi="elf"
;;
esac
cat >>confdefs.h <<_ACEOF
#define JEMALLOC_USABLE_SIZE_CONST $JEMALLOC_USABLE_SIZE_CONST
_ACEOF
+3
View File
@@ -237,6 +237,7 @@ dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the
dnl definitions need to be seen before any headers are included, which is a pain
dnl to make happen otherwise.
default_munmap="1"
JEMALLOC_USABLE_SIZE_CONST="const"
case "${host}" in
*-*-darwin*)
CFLAGS="$CFLAGS"
@@ -262,6 +263,7 @@ case "${host}" in
abi="elf"
AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ])
AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
JEMALLOC_USABLE_SIZE_CONST=""
default_munmap="0"
;;
*-*-netbsd*)
@@ -323,6 +325,7 @@ case "${host}" in
abi="elf"
;;
esac
AC_DEFINE_UNQUOTED([JEMALLOC_USABLE_SIZE_CONST], [$JEMALLOC_USABLE_SIZE_CONST])
AC_SUBST([abi])
AC_SUBST([RPATH])
AC_SUBST([LD_PRELOAD_VAR])
+62 -27
View File
@@ -2,12 +2,12 @@
.\" Title: JEMALLOC
.\" Author: Jason Evans
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
.\" Date: 05/11/2012
.\" Date: 11/09/2012
.\" Manual: User Manual
.\" Source: jemalloc 3.0.0-0-gfc9b1dbf69f59d7ecfc4ac68da9847e017e1d046
.\" Source: jemalloc 3.2.0-0-g87499f6748ebe4817571e817e9f680ccb5bf54a9
.\" Language: English
.\"
.TH "JEMALLOC" "3" "05/11/2012" "jemalloc 3.0.0-0-gfc9b1dbf69f5" "User Manual"
.TH "JEMALLOC" "3" "11/09/2012" "jemalloc 3.2.0-0-g87499f6748eb" "User Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -31,7 +31,7 @@
jemalloc \- general purpose memory allocation functions
.SH "LIBRARY"
.PP
This manual describes jemalloc 3\&.0\&.0\-0\-gfc9b1dbf69f59d7ecfc4ac68da9847e017e1d046\&. More information can be found at the
This manual describes jemalloc 3\&.2\&.0\-0\-g87499f6748ebe4817571e817e9f680ccb5bf54a9\&. More information can be found at the
\m[blue]\fBjemalloc website\fR\m[]\&\s-2\u[1]\d\s+2\&.
.SH "SYNOPSIS"
.sp
@@ -294,6 +294,14 @@ Initialize newly allocated memory to contain zero bytes\&. In the growing reallo
For reallocation, fail rather than moving the object\&. This constraint can apply to both growth and shrinkage\&.
.RE
.PP
\fBALLOCM_ARENA(\fR\fB\fIa\fR\fR\fB) \fR
.RS 4
Use the arena specified by the index
\fIa\fR\&. This macro does not validate that
\fIa\fR
specifies an arena in the valid range\&.
.RE
.PP
The
\fBallocm\fR\fB\fR
function allocates at least
@@ -631,16 +639,23 @@ is specified during configuration, in which case it is enabled by default\&.
Virtual memory chunk size (log base 2)\&. The default chunk size is 4 MiB (2^22)\&.
.RE
.PP
"opt\&.dss" (\fBconst char *\fR) r\-
.RS 4
dss (\fBsbrk\fR(2)) allocation precedence as related to
\fBmmap\fR(2)
allocation\&. The following settings are supported: \(lqdisabled\(rq, \(lqprimary\(rq, and \(lqsecondary\(rq (default)\&.
.RE
.PP
"opt\&.narenas" (\fBsize_t\fR) r\-
.RS 4
Maximum number of arenas to use\&. The default maximum number of arenas is four times the number of CPUs, or one if there is a single CPU\&.
Maximum number of arenas to use for automatic multiplexing of threads and arenas\&. The default is four times the number of CPUs, or one if there is a single CPU\&.
.RE
.PP
"opt\&.lg_dirty_mult" (\fBssize_t\fR) r\-
.RS 4
Per\-arena minimum ratio (log base 2) of active to dirty pages\&. Some dirty unused pages may be allowed to accumulate, within the limit set by the ratio (or one chunk worth of dirty pages, whichever is greater), before informing the kernel about some of those pages via
\fBmadvise\fR(2)
or a similar system call\&. This provides the kernel with sufficient information to recycle dirty pages if physical memory becomes scarce and the pages remain unused\&. The default minimum ratio is 32:1 (2^5:1); an option value of \-1 will disable dirty page purging\&.
or a similar system call\&. This provides the kernel with sufficient information to recycle dirty pages if physical memory becomes scarce and the pages remain unused\&. The default minimum ratio is 8:1 (2^3:1); an option value of \-1 will disable dirty page purging\&.
.RE
.PP
"opt\&.stats_print" (\fBbool\fR) r\-
@@ -660,7 +675,8 @@ Junk filling enabled/disabled\&. If enabled, each byte of uninitialized allocate
0xa5\&. All deallocated memory will be initialized to
0x5a\&. This is intended for debugging and will impact performance negatively\&. This option is disabled by default unless
\fB\-\-enable\-debug\fR
is specified during configuration, in which case it is enabled by default\&.
is specified during configuration, in which case it is enabled by default unless running inside
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2\&.
.RE
.PP
"opt\&.quarantine" (\fBsize_t\fR) r\- [\fB\-\-enable\-fill\fR]
@@ -668,7 +684,7 @@ is specified during configuration, in which case it is enabled by default\&.
Per thread quarantine size in bytes\&. If non\-zero, each thread maintains a FIFO object quarantine that stores up to the specified number of bytes of memory\&. The quarantined memory is not freed until it is released from quarantine, though it is immediately junk\-filled if the
"opt\&.junk"
option is enabled\&. This feature is of particular use in combination with
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2, which can detect attempts to access quarantined objects\&. This is intended for debugging and will impact performance negatively\&. The default quarantine size is 0\&.
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2, which can detect attempts to access quarantined objects\&. This is intended for debugging and will impact performance negatively\&. The default quarantine size is 0 unless running inside Valgrind, in which case the default is 16 MiB\&.
.RE
.PP
"opt\&.redzone" (\fBbool\fR) r\- [\fB\-\-enable\-fill\fR]
@@ -676,7 +692,7 @@ option is enabled\&. This feature is of particular use in combination with
Redzones enabled/disabled\&. If enabled, small allocations have redzones before and after them\&. Furthermore, if the
"opt\&.junk"
option is enabled, the redzones are checked for corruption during deallocation\&. However, the primary intended purpose of this feature is to be used in combination with
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2, which needs redzones in order to do effective buffer overflow/underflow detection\&. This option is intended for debugging and will impact performance negatively\&. This option is disabled by default\&.
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2, which needs redzones in order to do effective buffer overflow/underflow detection\&. This option is intended for debugging and will impact performance negatively\&. This option is disabled by default unless running inside Valgrind\&.
.RE
.PP
"opt\&.zero" (\fBbool\fR) r\- [\fB\-\-enable\-fill\fR]
@@ -698,15 +714,7 @@ enabled/disabled\&. This option is disabled by default\&.
"opt\&.valgrind" (\fBbool\fR) r\- [\fB\-\-enable\-valgrind\fR]
.RS 4
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2
support enabled/disabled\&. If enabled, several other options are automatically modified during options processing to work well with Valgrind:
"opt\&.junk"
and
"opt\&.zero"
are set to false,
"opt\&.quarantine"
is set to 16 MiB, and
"opt\&.redzone"
is set to true\&. This option is disabled by default\&.
support enabled/disabled\&. This option is vestigal because jemalloc auto\-detects whether it is running inside Valgrind\&. This option is disabled by default, unless running inside Valgrind\&.
.RE
.PP
"opt\&.xmalloc" (\fBbool\fR) r\- [\fB\-\-enable\-xmalloc\fR]
@@ -733,7 +741,8 @@ This option is disabled by default\&.
.RS 4
Thread\-specific caching enabled/disabled\&. When there are multiple threads, each thread uses a thread\-specific cache for objects up to a certain size\&. Thread\-specific caching allows many allocations to be satisfied without performing any thread synchronization, at the cost of increased memory use\&. See the
"opt\&.lg_tcache_max"
option for related tuning information\&. This option is enabled by default\&.
option for related tuning information\&. This option is enabled by default unless running inside
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2\&.
.RE
.PP
"opt\&.lg_tcache_max" (\fBsize_t\fR) r\- [\fB\-\-enable\-tcache\fR]
@@ -829,9 +838,7 @@ option for information on analyzing heap profile output\&. This option is disabl
.PP
"thread\&.arena" (\fBunsigned\fR) rw
.RS 4
Get or set the arena associated with the calling thread\&. The arena index must be less than the maximum number of arenas (see the
"arenas\&.narenas"
mallctl)\&. If the specified arena was not initialized beforehand (see the
Get or set the arena associated with the calling thread\&. If the specified arena was not initialized beforehand (see the
"arenas\&.initialized"
mallctl), it will be automatically initialized as a side effect of calling this interface\&.
.RE
@@ -875,9 +882,23 @@ Enable/disable calling thread\*(Aqs tcache\&. The tcache is implicitly flushed a
Flush calling thread\*(Aqs tcache\&. This interface releases all cached objects and internal data structures associated with the calling thread\*(Aqs thread\-specific cache\&. Ordinarily, this interface need not be called, since automatic periodic incremental garbage collection occurs, and the thread cache is automatically discarded when a thread exits\&. However, garbage collection is triggered by allocation activity, so it is possible for a thread that stops allocating/deallocating to retain its cache indefinitely, in which case the developer may find manual flushing useful\&.
.RE
.PP
"arena\&.<i>\&.purge" (\fBunsigned\fR) \-\-
.RS 4
Purge unused dirty pages for arena <i>, or for all arenas if <i> equals
"arenas\&.narenas"\&.
.RE
.PP
"arena\&.<i>\&.dss" (\fBconst char *\fR) rw
.RS 4
Set the precedence of dss allocation as related to mmap allocation for arena <i>, or for all arenas if <i> equals
"arenas\&.narenas"\&. See
"opt\&.dss"
for supported settings\&.
.RE
.PP
"arenas\&.narenas" (\fBunsigned\fR) r\-
.RS 4
Maximum number of arenas\&.
Current limit on number of arenas\&.
.RE
.PP
"arenas\&.initialized" (\fBbool *\fR) r\-
@@ -942,6 +963,11 @@ Maximum size supported by this large size class\&.
Purge unused dirty pages for the specified arena, or for all arenas if none is specified\&.
.RE
.PP
"arenas\&.extend" (\fBunsigned\fR) r\-
.RS 4
Extend the array of arenas by appending a new arena, and returning the new arena index\&.
.RE
.PP
"prof\&.active" (\fBbool\fR) rw [\fB\-\-enable\-prof\fR]
.RS 4
Control whether sampling is currently active\&. See the
@@ -981,7 +1007,9 @@ Total number of bytes allocated by the application\&.
"stats\&.active" (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR]
.RS 4
Total number of bytes in active pages allocated by the application\&. This is a multiple of the page size, and greater than or equal to
"stats\&.allocated"\&.
"stats\&.allocated"\&. This does not include
"stats\&.arenas\&.<i>\&.pdirty"
and pages entirely devoted to allocator metadata\&.
.RE
.PP
"stats\&.mapped" (\fBsize_t\fR) r\- [\fB\-\-enable\-stats\fR]
@@ -1020,6 +1048,15 @@ Cumulative number of huge allocation requests\&.
Cumulative number of huge deallocation requests\&.
.RE
.PP
"stats\&.arenas\&.<i>\&.dss" (\fBconst char *\fR) r\-
.RS 4
dss (\fBsbrk\fR(2)) allocation precedence as related to
\fBmmap\fR(2)
allocation\&. See
"opt\&.dss"
for details\&.
.RE
.PP
"stats\&.arenas\&.<i>\&.nthreads" (\fBunsigned\fR) r\-
.RS 4
Number of threads currently assigned to arena\&.
@@ -1181,9 +1218,7 @@ This implementation does not provide much detail about the problems it detects,
\m[blue]\fBValgrind\fR\m[]\&\s-2\u[2]\d\s+2
tool if the
\fB\-\-enable\-valgrind\fR
configuration option is enabled and the
"opt\&.valgrind"
option is enabled\&.
configuration option is enabled\&.
.SH "DIAGNOSTIC MESSAGES"
.PP
If any of the memory allocation/deallocation functions detect an error or warning condition, a message will be printed to file descriptor
+91 -50
View File
File diff suppressed because one or more lines are too long
+98 -29
View File
@@ -368,6 +368,15 @@ for (i = 0; i < nbins; i++) {
object. This constraint can apply to both growth and
shrinkage.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>ALLOCM_ARENA(<parameter>a</parameter>)
</constant></term>
<listitem><para>Use the arena specified by the index
<parameter>a</parameter>. This macro does not validate that
<parameter>a</parameter> specifies an arena in the valid
range.</para></listitem>
</varlistentry>
</variablelist>
</para>
@@ -785,15 +794,29 @@ for (i = 0; i < nbins; i++) {
chunk size is 4 MiB (2^22).</para></listitem>
</varlistentry>
<varlistentry id="opt.dss">
<term>
<mallctl>opt.dss</mallctl>
(<type>const char *</type>)
<literal>r-</literal>
</term>
<listitem><para>dss (<citerefentry><refentrytitle>sbrk</refentrytitle>
<manvolnum>2</manvolnum></citerefentry>) allocation precedence as
related to <citerefentry><refentrytitle>mmap</refentrytitle>
<manvolnum>2</manvolnum></citerefentry> allocation. The following
settings are supported: &ldquo;disabled&rdquo;, &ldquo;primary&rdquo;,
and &ldquo;secondary&rdquo; (default).</para></listitem>
</varlistentry>
<varlistentry id="opt.narenas">
<term>
<mallctl>opt.narenas</mallctl>
(<type>size_t</type>)
<literal>r-</literal>
</term>
<listitem><para>Maximum number of arenas to use. The default maximum
number of arenas is four times the number of CPUs, or one if there is a
single CPU.</para></listitem>
<listitem><para>Maximum number of arenas to use for automatic
multiplexing of threads and arenas. The default is four times the
number of CPUs, or one if there is a single CPU.</para></listitem>
</varlistentry>
<varlistentry id="opt.lg_dirty_mult">
@@ -810,7 +833,7 @@ for (i = 0; i < nbins; i++) {
<manvolnum>2</manvolnum></citerefentry> or a similar system call. This
provides the kernel with sufficient information to recycle dirty pages
if physical memory becomes scarce and the pages remain unused. The
default minimum ratio is 32:1 (2^5:1); an option value of -1 will
default minimum ratio is 8:1 (2^3:1); an option value of -1 will
disable dirty page purging.</para></listitem>
</varlistentry>
@@ -846,7 +869,9 @@ for (i = 0; i < nbins; i++) {
<literal>0x5a</literal>. This is intended for debugging and will
impact performance negatively. This option is disabled by default
unless <option>--enable-debug</option> is specified during
configuration, in which case it is enabled by default.</para></listitem>
configuration, in which case it is enabled by default unless running
inside <ulink
url="http://valgrind.org/">Valgrind</ulink>.</para></listitem>
</varlistentry>
<varlistentry id="opt.quarantine">
@@ -865,8 +890,9 @@ for (i = 0; i < nbins; i++) {
enabled. This feature is of particular use in combination with <ulink
url="http://valgrind.org/">Valgrind</ulink>, which can detect attempts
to access quarantined objects. This is intended for debugging and will
impact performance negatively. The default quarantine size is
0.</para></listitem>
impact performance negatively. The default quarantine size is 0 unless
running inside Valgrind, in which case the default is 16
MiB.</para></listitem>
</varlistentry>
<varlistentry id="opt.redzone">
@@ -885,7 +911,7 @@ for (i = 0; i < nbins; i++) {
which needs redzones in order to do effective buffer overflow/underflow
detection. This option is intended for debugging and will impact
performance negatively. This option is disabled by
default.</para></listitem>
default unless running inside Valgrind.</para></listitem>
</varlistentry>
<varlistentry id="opt.zero">
@@ -926,15 +952,9 @@ for (i = 0; i < nbins; i++) {
[<option>--enable-valgrind</option>]
</term>
<listitem><para><ulink url="http://valgrind.org/">Valgrind</ulink>
support enabled/disabled. If enabled, several other options are
automatically modified during options processing to work well with
Valgrind: <link linkend="opt.junk"><mallctl>opt.junk</mallctl></link>
and <link linkend="opt.zero"><mallctl>opt.zero</mallctl></link> are set
to false, <link
linkend="opt.quarantine"><mallctl>opt.quarantine</mallctl></link> is
set to 16 MiB, and <link
linkend="opt.redzone"><mallctl>opt.redzone</mallctl></link> is set to
true. This option is disabled by default.</para></listitem>
support enabled/disabled. This option is vestigal because jemalloc
auto-detects whether it is running inside Valgrind. This option is
disabled by default, unless running inside Valgrind.</para></listitem>
</varlistentry>
<varlistentry id="opt.xmalloc">
@@ -972,7 +992,8 @@ malloc_conf = "xmalloc:true";]]></programlisting>
<link
linkend="opt.lg_tcache_max"><mallctl>opt.lg_tcache_max</mallctl></link>
option for related tuning information. This option is enabled by
default.</para></listitem>
default unless running inside <ulink
url="http://valgrind.org/">Valgrind</ulink>.</para></listitem>
</varlistentry>
<varlistentry id="opt.lg_tcache_max">
@@ -1151,11 +1172,8 @@ malloc_conf = "xmalloc:true";]]></programlisting>
<literal>rw</literal>
</term>
<listitem><para>Get or set the arena associated with the calling
thread. The arena index must be less than the maximum number of arenas
(see the <link
linkend="arenas.narenas"><mallctl>arenas.narenas</mallctl></link>
mallctl). If the specified arena was not initialized beforehand (see
the <link
thread. If the specified arena was not initialized beforehand (see the
<link
linkend="arenas.initialized"><mallctl>arenas.initialized</mallctl></link>
mallctl), it will be automatically initialized as a side effect of
calling this interface.</para></listitem>
@@ -1247,13 +1265,40 @@ malloc_conf = "xmalloc:true";]]></programlisting>
the developer may find manual flushing useful.</para></listitem>
</varlistentry>
<varlistentry id="arena.i.purge">
<term>
<mallctl>arena.&lt;i&gt;.purge</mallctl>
(<type>unsigned</type>)
<literal>--</literal>
</term>
<listitem><para>Purge unused dirty pages for arena &lt;i&gt;, or for
all arenas if &lt;i&gt; equals <link
linkend="arenas.narenas"><mallctl>arenas.narenas</mallctl></link>.
</para></listitem>
</varlistentry>
<varlistentry id="arena.i.dss">
<term>
<mallctl>arena.&lt;i&gt;.dss</mallctl>
(<type>const char *</type>)
<literal>rw</literal>
</term>
<listitem><para>Set the precedence of dss allocation as related to mmap
allocation for arena &lt;i&gt;, or for all arenas if &lt;i&gt; equals
<link
linkend="arenas.narenas"><mallctl>arenas.narenas</mallctl></link>. See
<link linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for supported
settings.
</para></listitem>
</varlistentry>
<varlistentry id="arenas.narenas">
<term>
<mallctl>arenas.narenas</mallctl>
(<type>unsigned</type>)
<literal>r-</literal>
</term>
<listitem><para>Maximum number of arenas.</para></listitem>
<listitem><para>Current limit on number of arenas.</para></listitem>
</varlistentry>
<varlistentry id="arenas.initialized">
@@ -1372,6 +1417,16 @@ malloc_conf = "xmalloc:true";]]></programlisting>
for all arenas if none is specified.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<mallctl>arenas.extend</mallctl>
(<type>unsigned</type>)
<literal>r-</literal>
</term>
<listitem><para>Extend the array of arenas by appending a new arena,
and returning the new arena index.</para></listitem>
</varlistentry>
<varlistentry id="prof.active">
<term>
<mallctl>prof.active</mallctl>
@@ -1457,7 +1512,9 @@ malloc_conf = "xmalloc:true";]]></programlisting>
application. This is a multiple of the page size, and greater than or
equal to <link
linkend="stats.allocated"><mallctl>stats.allocated</mallctl></link>.
</para></listitem>
This does not include <link linkend="stats.arenas.i.pdirty">
<mallctl>stats.arenas.&lt;i&gt;.pdirty</mallctl></link> and pages
entirely devoted to allocator metadata.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1540,6 +1597,20 @@ malloc_conf = "xmalloc:true";]]></programlisting>
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<mallctl>stats.arenas.&lt;i&gt;.dss</mallctl>
(<type>const char *</type>)
<literal>r-</literal>
</term>
<listitem><para>dss (<citerefentry><refentrytitle>sbrk</refentrytitle>
<manvolnum>2</manvolnum></citerefentry>) allocation precedence as
related to <citerefentry><refentrytitle>mmap</refentrytitle>
<manvolnum>2</manvolnum></citerefentry> allocation. See <link
linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for details.
</para></listitem>
</varlistentry>
<varlistentry>
<term>
<mallctl>stats.arenas.&lt;i&gt;.nthreads</mallctl>
@@ -1559,7 +1630,7 @@ malloc_conf = "xmalloc:true";]]></programlisting>
<listitem><para>Number of pages in active runs.</para></listitem>
</varlistentry>
<varlistentry>
<varlistentry id="stats.arenas.i.pdirty">
<term>
<mallctl>stats.arenas.&lt;i&gt;.pdirty</mallctl>
(<type>size_t</type>)
@@ -1865,9 +1936,7 @@ malloc_conf = "xmalloc:true";]]></programlisting>
it detects, because the performance impact for storing such information
would be prohibitive. However, jemalloc does integrate with the most
excellent <ulink url="http://valgrind.org/">Valgrind</ulink> tool if the
<option>--enable-valgrind</option> configuration option is enabled and the
<link linkend="opt.valgrind"><mallctl>opt.valgrind</mallctl></link> option
is enabled.</para>
<option>--enable-valgrind</option> configuration option is enabled.</para>
</refsect1>
<refsect1 id="diagnostic_messages">
<title>DIAGNOSTIC MESSAGES</title>
+34 -34
View File
@@ -38,10 +38,10 @@
*
* (nactive >> opt_lg_dirty_mult) >= ndirty
*
* So, supposing that opt_lg_dirty_mult is 5, there can be no less than 32
* times as many active pages as dirty pages.
* So, supposing that opt_lg_dirty_mult is 3, there can be no less than 8 times
* as many active pages as dirty pages.
*/
#define LG_DIRTY_MULT_DEFAULT 5
#define LG_DIRTY_MULT_DEFAULT 3
typedef struct arena_chunk_map_s arena_chunk_map_t;
typedef struct arena_chunk_s arena_chunk_t;
@@ -69,7 +69,7 @@ struct arena_chunk_map_s {
/*
* Linkage for run trees. There are two disjoint uses:
*
* 1) arena_t's runs_avail_{clean,dirty} trees.
* 1) arena_t's runs_avail tree.
* 2) arena_run_t conceptually uses this linkage for in-use
* non-full runs, rather than directly embedding linkage.
*/
@@ -162,20 +162,24 @@ typedef rb_tree(arena_chunk_map_t) arena_run_tree_t;
/* Arena chunk header. */
struct arena_chunk_s {
/* Arena that owns the chunk. */
arena_t *arena;
arena_t *arena;
/* Linkage for the arena's chunks_dirty list. */
ql_elm(arena_chunk_t) link_dirty;
/*
* True if the chunk is currently in the chunks_dirty list, due to
* having at some point contained one or more dirty pages. Removal
* from chunks_dirty is lazy, so (dirtied && ndirty == 0) is possible.
*/
bool dirtied;
/* Linkage for tree of arena chunks that contain dirty runs. */
rb_node(arena_chunk_t) dirty_link;
/* Number of dirty pages. */
size_t ndirty;
size_t ndirty;
/* Number of available runs. */
size_t nruns_avail;
/*
* Number of available run adjacencies. Clean and dirty available runs
* are not coalesced, which causes virtual memory fragmentation. The
* ratio of (nruns_avail-nruns_adjac):nruns_adjac is used for tracking
* this fragmentation.
* */
size_t nruns_adjac;
/*
* Map of pages within chunk that keeps track of free/large/small. The
@@ -183,7 +187,7 @@ struct arena_chunk_s {
* need to be tracked in the map. This omission saves a header page
* for common chunk sizes (e.g. 4 MiB).
*/
arena_chunk_map_t map[1]; /* Dynamically sized. */
arena_chunk_map_t map[1]; /* Dynamically sized. */
};
typedef rb_tree(arena_chunk_t) arena_chunk_tree_t;
@@ -331,8 +335,10 @@ struct arena_s {
uint64_t prof_accumbytes;
/* List of dirty-page-containing chunks this arena manages. */
ql_head(arena_chunk_t) chunks_dirty;
dss_prec_t dss_prec;
/* Tree of dirty-page-containing chunks this arena manages. */
arena_chunk_tree_t chunks_dirty;
/*
* In order to avoid rapid chunk allocation/deallocation when an arena
@@ -367,18 +373,9 @@ struct arena_s {
/*
* Size/address-ordered trees of this arena's available runs. The trees
* are used for first-best-fit run allocation. The dirty tree contains
* runs with dirty pages (i.e. very likely to have been touched and
* therefore have associated physical pages), whereas the clean tree
* contains runs with pages that either have no associated physical
* pages, or have pages that the kernel may recycle at any time due to
* previous madvise(2) calls. The dirty tree is used in preference to
* the clean tree for allocations, because using dirty pages reduces
* the amount of dirty purging necessary to keep the active:dirty page
* ratio below the purge threshold.
* are used for first-best-fit run allocation.
*/
arena_avail_tree_t runs_avail_clean;
arena_avail_tree_t runs_avail_dirty;
arena_avail_tree_t runs_avail;
/* bins is used to store trees of free regions. */
arena_bin_t bins[NBINS];
@@ -422,13 +419,16 @@ void arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr,
void arena_dalloc_large_locked(arena_t *arena, arena_chunk_t *chunk,
void *ptr);
void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr);
void arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
arena_stats_t *astats, malloc_bin_stats_t *bstats,
malloc_large_stats_t *lstats);
void *arena_ralloc_no_move(void *ptr, size_t oldsize, size_t size,
size_t extra, bool zero);
void *arena_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
size_t alignment, bool zero, bool try_tcache);
void *arena_ralloc(arena_t *arena, void *ptr, size_t oldsize, size_t size,
size_t extra, size_t alignment, bool zero, bool try_tcache_alloc,
bool try_tcache_dalloc);
dss_prec_t arena_dss_prec_get(arena_t *arena);
void arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
void arena_stats_merge(arena_t *arena, const char **dss, size_t *nactive,
size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats,
malloc_large_stats_t *lstats);
bool arena_new(arena_t *arena, unsigned ind);
void arena_boot(void);
void arena_prefork(arena_t *arena);
+7 -1
View File
@@ -28,6 +28,7 @@
#ifdef JEMALLOC_H_EXTERNS
extern size_t opt_lg_chunk;
extern const char *opt_dss;
/* Protects stats_chunks; currently not used for any other purpose. */
extern malloc_mutex_t chunks_mtx;
@@ -42,9 +43,14 @@ extern size_t chunk_npages;
extern size_t map_bias; /* Number of arena chunk header pages. */
extern size_t arena_maxclass; /* Max size class for arenas. */
void *chunk_alloc(size_t size, size_t alignment, bool base, bool *zero);
void *chunk_alloc(size_t size, size_t alignment, bool base, bool *zero,
dss_prec_t dss_prec);
void chunk_unmap(void *chunk, size_t size);
void chunk_dealloc(void *chunk, size_t size, bool unmap);
bool chunk_boot(void);
void chunk_prefork(void);
void chunk_postfork_parent(void);
void chunk_postfork_child(void);
#endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/
+14
View File
@@ -1,14 +1,28 @@
/******************************************************************************/
#ifdef JEMALLOC_H_TYPES
typedef enum {
dss_prec_disabled = 0,
dss_prec_primary = 1,
dss_prec_secondary = 2,
dss_prec_limit = 3
} dss_prec_t ;
#define DSS_PREC_DEFAULT dss_prec_secondary
#define DSS_DEFAULT "secondary"
#endif /* JEMALLOC_H_TYPES */
/******************************************************************************/
#ifdef JEMALLOC_H_STRUCTS
extern const char *dss_prec_names[];
#endif /* JEMALLOC_H_STRUCTS */
/******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS
dss_prec_t chunk_dss_prec_get(void);
bool chunk_dss_prec_set(dss_prec_t dss_prec);
void *chunk_alloc_dss(size_t size, size_t alignment, bool *zero);
bool chunk_in_dss(void *chunk);
bool chunk_dss_boot(void);
+1 -1
View File
@@ -9,7 +9,7 @@
/******************************************************************************/
#ifdef JEMALLOC_H_EXTERNS
void pages_purge(void *addr, size_t length);
bool pages_purge(void *addr, size_t length);
void *chunk_alloc_mmap(size_t size, size_t alignment, bool *zero);
bool chunk_dealloc_mmap(void *chunk, size_t size);
+5
View File
@@ -33,6 +33,7 @@ struct ctl_indexed_node_s {
struct ctl_arena_stats_s {
bool initialized;
unsigned nthreads;
const char *dss;
size_t pactive;
size_t pdirty;
arena_stats_t astats;
@@ -61,6 +62,7 @@ struct ctl_stats_s {
uint64_t nmalloc; /* huge_nmalloc */
uint64_t ndalloc; /* huge_ndalloc */
} huge;
unsigned narenas;
ctl_arena_stats_t *arenas; /* (narenas + 1) elements. */
};
@@ -75,6 +77,9 @@ int ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp);
int ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen);
bool ctl_boot(void);
void ctl_prefork(void);
void ctl_postfork_parent(void);
void ctl_postfork_child(void);
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
if (je_mallctl(name, oldp, oldlenp, newp, newlen) \
+3
View File
@@ -23,6 +23,9 @@ struct extent_node_s {
/* Total region size. */
size_t size;
/* True if zero-filled; used by chunk recycling code. */
bool zeroed;
};
typedef rb_tree(extent_node_t) extent_tree_t;
+1 -1
View File
@@ -22,7 +22,7 @@ void *huge_palloc(size_t size, size_t alignment, bool zero);
void *huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size,
size_t extra);
void *huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
size_t alignment, bool zero);
size_t alignment, bool zero, bool try_tcache_dalloc);
void huge_dalloc(void *ptr, bool unmap);
size_t huge_salloc(const void *ptr);
prof_ctx_t *huge_prof_ctx_get(const void *ptr);
+105 -26
View File
@@ -270,6 +270,9 @@ static const bool config_ivsalloc =
# ifdef __arm__
# define LG_QUANTUM 3
# endif
# ifdef __hppa__
# define LG_QUANTUM 4
# endif
# ifdef __mips__
# define LG_QUANTUM 3
# endif
@@ -424,6 +427,7 @@ static const bool config_ivsalloc =
VALGRIND_FREELIKE_BLOCK(ptr, rzsize); \
} while (0)
#else
#define RUNNING_ON_VALGRIND ((unsigned)0)
#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)
#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB)
#define VALGRIND_FREELIKE_BLOCK(addr, rzB)
@@ -510,13 +514,19 @@ extern size_t opt_narenas;
/* Number of CPUs. */
extern unsigned ncpus;
extern malloc_mutex_t arenas_lock; /* Protects arenas initialization. */
/* Protects arenas initialization (arenas, arenas_total). */
extern malloc_mutex_t arenas_lock;
/*
* Arenas that are used to service external requests. Not all elements of the
* arenas array are necessarily used; arenas are created lazily as needed.
*
* arenas[0..narenas_auto) are used for automatic multiplexing of threads and
* arenas. arenas[narenas_auto..narenas_total) are only used if the application
* takes some action to create them and allocate from them.
*/
extern arena_t **arenas;
extern unsigned narenas;
extern unsigned narenas_total;
extern unsigned narenas_auto; /* Read-only after initialization. */
arena_t *arenas_extend(unsigned ind);
void arenas_cleanup(void *arg);
@@ -571,6 +581,7 @@ malloc_tsd_protos(JEMALLOC_ATTR(unused), arenas, arena_t *)
size_t s2u(size_t size);
size_t sa2u(size_t size, size_t alignment);
unsigned narenas_total_get(void);
arena_t *choose_arena(arena_t *arena);
#endif
@@ -675,6 +686,18 @@ sa2u(size_t size, size_t alignment)
}
}
JEMALLOC_INLINE unsigned
narenas_total_get(void)
{
unsigned narenas;
malloc_mutex_lock(&arenas_lock);
narenas = narenas_total;
malloc_mutex_unlock(&arenas_lock);
return (narenas);
}
/* Choose an arena based on a per-thread value. */
JEMALLOC_INLINE arena_t *
choose_arena(arena_t *arena)
@@ -710,15 +733,24 @@ choose_arena(arena_t *arena)
#include "jemalloc/internal/quarantine.h"
#ifndef JEMALLOC_ENABLE_INLINE
void *imallocx(size_t size, bool try_tcache, arena_t *arena);
void *imalloc(size_t size);
void *icallocx(size_t size, bool try_tcache, arena_t *arena);
void *icalloc(size_t size);
void *ipallocx(size_t usize, size_t alignment, bool zero, bool try_tcache,
arena_t *arena);
void *ipalloc(size_t usize, size_t alignment, bool zero);
size_t isalloc(const void *ptr, bool demote);
size_t ivsalloc(const void *ptr, bool demote);
size_t u2rz(size_t usize);
size_t p2rz(const void *ptr);
void idallocx(void *ptr, bool try_tcache);
void idalloc(void *ptr);
void iqallocx(void *ptr, bool try_tcache);
void iqalloc(void *ptr);
void *irallocx(void *ptr, size_t size, size_t extra, size_t alignment,
bool zero, bool no_move, bool try_tcache_alloc, bool try_tcache_dalloc,
arena_t *arena);
void *iralloc(void *ptr, size_t size, size_t extra, size_t alignment,
bool zero, bool no_move);
malloc_tsd_protos(JEMALLOC_ATTR(unused), thread_allocated, thread_allocated_t)
@@ -726,29 +758,44 @@ malloc_tsd_protos(JEMALLOC_ATTR(unused), thread_allocated, thread_allocated_t)
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_))
JEMALLOC_INLINE void *
imalloc(size_t size)
imallocx(size_t size, bool try_tcache, arena_t *arena)
{
assert(size != 0);
if (size <= arena_maxclass)
return (arena_malloc(NULL, size, false, true));
return (arena_malloc(arena, size, false, try_tcache));
else
return (huge_malloc(size, false));
}
JEMALLOC_INLINE void *
imalloc(size_t size)
{
return (imallocx(size, true, NULL));
}
JEMALLOC_INLINE void *
icallocx(size_t size, bool try_tcache, arena_t *arena)
{
if (size <= arena_maxclass)
return (arena_malloc(arena, size, true, try_tcache));
else
return (huge_malloc(size, true));
}
JEMALLOC_INLINE void *
icalloc(size_t size)
{
if (size <= arena_maxclass)
return (arena_malloc(NULL, size, true, true));
else
return (huge_malloc(size, true));
return (icallocx(size, true, NULL));
}
JEMALLOC_INLINE void *
ipalloc(size_t usize, size_t alignment, bool zero)
ipallocx(size_t usize, size_t alignment, bool zero, bool try_tcache,
arena_t *arena)
{
void *ret;
@@ -756,11 +803,11 @@ ipalloc(size_t usize, size_t alignment, bool zero)
assert(usize == sa2u(usize, alignment));
if (usize <= arena_maxclass && alignment <= PAGE)
ret = arena_malloc(NULL, usize, zero, true);
ret = arena_malloc(arena, usize, zero, try_tcache);
else {
if (usize <= arena_maxclass) {
ret = arena_palloc(choose_arena(NULL), usize, alignment,
zero);
ret = arena_palloc(choose_arena(arena), usize,
alignment, zero);
} else if (alignment <= chunksize)
ret = huge_malloc(usize, zero);
else
@@ -771,6 +818,13 @@ ipalloc(size_t usize, size_t alignment, bool zero)
return (ret);
}
JEMALLOC_INLINE void *
ipalloc(size_t usize, size_t alignment, bool zero)
{
return (ipallocx(usize, alignment, zero, true, NULL));
}
/*
* Typical usage:
* void *ptr = [...]
@@ -829,7 +883,7 @@ p2rz(const void *ptr)
}
JEMALLOC_INLINE void
idalloc(void *ptr)
idallocx(void *ptr, bool try_tcache)
{
arena_chunk_t *chunk;
@@ -837,24 +891,38 @@ idalloc(void *ptr)
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
if (chunk != ptr)
arena_dalloc(chunk->arena, chunk, ptr, true);
arena_dalloc(chunk->arena, chunk, ptr, try_tcache);
else
huge_dalloc(ptr, true);
}
JEMALLOC_INLINE void
idalloc(void *ptr)
{
idallocx(ptr, true);
}
JEMALLOC_INLINE void
iqallocx(void *ptr, bool try_tcache)
{
if (config_fill && opt_quarantine)
quarantine(ptr);
else
idallocx(ptr, try_tcache);
}
JEMALLOC_INLINE void
iqalloc(void *ptr)
{
if (config_fill && opt_quarantine)
quarantine(ptr);
else
idalloc(ptr);
iqallocx(ptr, true);
}
JEMALLOC_INLINE void *
iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
bool no_move)
irallocx(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
bool no_move, bool try_tcache_alloc, bool try_tcache_dalloc, arena_t *arena)
{
void *ret;
size_t oldsize;
@@ -877,7 +945,7 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
usize = sa2u(size + extra, alignment);
if (usize == 0)
return (NULL);
ret = ipalloc(usize, alignment, zero);
ret = ipallocx(usize, alignment, zero, try_tcache_alloc, arena);
if (ret == NULL) {
if (extra == 0)
return (NULL);
@@ -885,7 +953,8 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
usize = sa2u(size, alignment);
if (usize == 0)
return (NULL);
ret = ipalloc(usize, alignment, zero);
ret = ipallocx(usize, alignment, zero, try_tcache_alloc,
arena);
if (ret == NULL)
return (NULL);
}
@@ -896,7 +965,7 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
*/
copysize = (size < oldsize) ? size : oldsize;
memcpy(ret, ptr, copysize);
iqalloc(ptr);
iqallocx(ptr, try_tcache_dalloc);
return (ret);
}
@@ -910,15 +979,25 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
}
} else {
if (size + extra <= arena_maxclass) {
return (arena_ralloc(ptr, oldsize, size, extra,
alignment, zero, true));
return (arena_ralloc(arena, ptr, oldsize, size, extra,
alignment, zero, try_tcache_alloc,
try_tcache_dalloc));
} else {
return (huge_ralloc(ptr, oldsize, size, extra,
alignment, zero));
alignment, zero, try_tcache_dalloc));
}
}
}
JEMALLOC_INLINE void *
iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
bool no_move)
{
return (irallocx(ptr, size, extra, alignment, zero, no_move, true, true,
NULL));
}
malloc_tsd_externs(thread_allocated, thread_allocated_t)
malloc_tsd_funcs(JEMALLOC_INLINE, thread_allocated, thread_allocated_t,
THREAD_ALLOCATED_INITIALIZER, malloc_tsd_no_cleanup)
+34 -6
View File
@@ -12,6 +12,8 @@
#define arena_dalloc_large JEMALLOC_N(arena_dalloc_large)
#define arena_dalloc_large_locked JEMALLOC_N(arena_dalloc_large_locked)
#define arena_dalloc_small JEMALLOC_N(arena_dalloc_small)
#define arena_dss_prec_get JEMALLOC_N(arena_dss_prec_get)
#define arena_dss_prec_set JEMALLOC_N(arena_dss_prec_set)
#define arena_malloc JEMALLOC_N(arena_malloc)
#define arena_malloc_large JEMALLOC_N(arena_malloc_large)
#define arena_malloc_small JEMALLOC_N(arena_malloc_small)
@@ -51,14 +53,13 @@
#define arena_stats_merge JEMALLOC_N(arena_stats_merge)
#define arena_tcache_fill_small JEMALLOC_N(arena_tcache_fill_small)
#define arenas JEMALLOC_N(arenas)
#define arenas_bin_i_index JEMALLOC_N(arenas_bin_i_index)
#define arenas_booted JEMALLOC_N(arenas_booted)
#define arenas_cleanup JEMALLOC_N(arenas_cleanup)
#define arenas_extend JEMALLOC_N(arenas_extend)
#define arenas_initialized JEMALLOC_N(arenas_initialized)
#define arenas_lock JEMALLOC_N(arenas_lock)
#define arenas_lrun_i_index JEMALLOC_N(arenas_lrun_i_index)
#define arenas_tls JEMALLOC_N(arenas_tls)
#define arenas_tsd JEMALLOC_N(arenas_tsd)
#define arenas_tsd_boot JEMALLOC_N(arenas_tsd_boot)
#define arenas_tsd_cleanup_wrapper JEMALLOC_N(arenas_tsd_cleanup_wrapper)
#define arenas_tsd_get JEMALLOC_N(arenas_tsd_get)
@@ -101,9 +102,15 @@
#define chunk_dss_boot JEMALLOC_N(chunk_dss_boot)
#define chunk_dss_postfork_child JEMALLOC_N(chunk_dss_postfork_child)
#define chunk_dss_postfork_parent JEMALLOC_N(chunk_dss_postfork_parent)
#define chunk_dss_prec_get JEMALLOC_N(chunk_dss_prec_get)
#define chunk_dss_prec_set JEMALLOC_N(chunk_dss_prec_set)
#define chunk_dss_prefork JEMALLOC_N(chunk_dss_prefork)
#define chunk_in_dss JEMALLOC_N(chunk_in_dss)
#define chunk_npages JEMALLOC_N(chunk_npages)
#define chunk_postfork_child JEMALLOC_N(chunk_postfork_child)
#define chunk_postfork_parent JEMALLOC_N(chunk_postfork_parent)
#define chunk_prefork JEMALLOC_N(chunk_prefork)
#define chunk_unmap JEMALLOC_N(chunk_unmap)
#define chunks_mtx JEMALLOC_N(chunks_mtx)
#define chunks_rtree JEMALLOC_N(chunks_rtree)
#define chunksize JEMALLOC_N(chunksize)
@@ -129,6 +136,10 @@
#define ctl_bymib JEMALLOC_N(ctl_bymib)
#define ctl_byname JEMALLOC_N(ctl_byname)
#define ctl_nametomib JEMALLOC_N(ctl_nametomib)
#define ctl_postfork_child JEMALLOC_N(ctl_postfork_child)
#define ctl_postfork_parent JEMALLOC_N(ctl_postfork_parent)
#define ctl_prefork JEMALLOC_N(ctl_prefork)
#define dss_prec_names JEMALLOC_N(dss_prec_names)
#define extent_tree_ad_first JEMALLOC_N(extent_tree_ad_first)
#define extent_tree_ad_insert JEMALLOC_N(extent_tree_ad_insert)
#define extent_tree_ad_iter JEMALLOC_N(extent_tree_ad_iter)
@@ -161,6 +172,7 @@
#define extent_tree_szad_reverse_iter_recurse JEMALLOC_N(extent_tree_szad_reverse_iter_recurse)
#define extent_tree_szad_reverse_iter_start JEMALLOC_N(extent_tree_szad_reverse_iter_start)
#define extent_tree_szad_search JEMALLOC_N(extent_tree_szad_search)
#define get_errno JEMALLOC_N(get_errno)
#define hash JEMALLOC_N(hash)
#define huge_allocated JEMALLOC_N(huge_allocated)
#define huge_boot JEMALLOC_N(huge_boot)
@@ -180,11 +192,17 @@
#define huge_salloc JEMALLOC_N(huge_salloc)
#define iallocm JEMALLOC_N(iallocm)
#define icalloc JEMALLOC_N(icalloc)
#define icallocx JEMALLOC_N(icallocx)
#define idalloc JEMALLOC_N(idalloc)
#define idallocx JEMALLOC_N(idallocx)
#define imalloc JEMALLOC_N(imalloc)
#define imallocx JEMALLOC_N(imallocx)
#define ipalloc JEMALLOC_N(ipalloc)
#define ipallocx JEMALLOC_N(ipallocx)
#define iqalloc JEMALLOC_N(iqalloc)
#define iqallocx JEMALLOC_N(iqallocx)
#define iralloc JEMALLOC_N(iralloc)
#define irallocx JEMALLOC_N(irallocx)
#define isalloc JEMALLOC_N(isalloc)
#define isthreaded JEMALLOC_N(isthreaded)
#define ivsalloc JEMALLOC_N(ivsalloc)
@@ -212,7 +230,9 @@
#define map_bias JEMALLOC_N(map_bias)
#define mb_write JEMALLOC_N(mb_write)
#define mutex_boot JEMALLOC_N(mutex_boot)
#define narenas JEMALLOC_N(narenas)
#define narenas_auto JEMALLOC_N(narenas_auto)
#define narenas_total JEMALLOC_N(narenas_total)
#define narenas_total_get JEMALLOC_N(narenas_total_get)
#define ncpus JEMALLOC_N(ncpus)
#define nhbins JEMALLOC_N(nhbins)
#define opt_abort JEMALLOC_N(opt_abort)
@@ -254,6 +274,9 @@
#define prof_lookup JEMALLOC_N(prof_lookup)
#define prof_malloc JEMALLOC_N(prof_malloc)
#define prof_mdump JEMALLOC_N(prof_mdump)
#define prof_postfork_child JEMALLOC_N(prof_postfork_child)
#define prof_postfork_parent JEMALLOC_N(prof_postfork_parent)
#define prof_prefork JEMALLOC_N(prof_prefork)
#define prof_promote JEMALLOC_N(prof_promote)
#define prof_realloc JEMALLOC_N(prof_realloc)
#define prof_sample_accum_update JEMALLOC_N(prof_sample_accum_update)
@@ -264,6 +287,7 @@
#define prof_tdata_init JEMALLOC_N(prof_tdata_init)
#define prof_tdata_initialized JEMALLOC_N(prof_tdata_initialized)
#define prof_tdata_tls JEMALLOC_N(prof_tdata_tls)
#define prof_tdata_tsd JEMALLOC_N(prof_tdata_tsd)
#define prof_tdata_tsd_boot JEMALLOC_N(prof_tdata_tsd_boot)
#define prof_tdata_tsd_cleanup_wrapper JEMALLOC_N(prof_tdata_tsd_cleanup_wrapper)
#define prof_tdata_tsd_get JEMALLOC_N(prof_tdata_tsd_get)
@@ -278,12 +302,13 @@
#define rtree_get JEMALLOC_N(rtree_get)
#define rtree_get_locked JEMALLOC_N(rtree_get_locked)
#define rtree_new JEMALLOC_N(rtree_new)
#define rtree_postfork_child JEMALLOC_N(rtree_postfork_child)
#define rtree_postfork_parent JEMALLOC_N(rtree_postfork_parent)
#define rtree_prefork JEMALLOC_N(rtree_prefork)
#define rtree_set JEMALLOC_N(rtree_set)
#define s2u JEMALLOC_N(s2u)
#define sa2u JEMALLOC_N(sa2u)
#define stats_arenas_i_bins_j_index JEMALLOC_N(stats_arenas_i_bins_j_index)
#define stats_arenas_i_index JEMALLOC_N(stats_arenas_i_index)
#define stats_arenas_i_lruns_j_index JEMALLOC_N(stats_arenas_i_lruns_j_index)
#define set_errno JEMALLOC_N(set_errno)
#define stats_cactive JEMALLOC_N(stats_cactive)
#define stats_cactive_add JEMALLOC_N(stats_cactive_add)
#define stats_cactive_get JEMALLOC_N(stats_cactive_get)
@@ -311,6 +336,7 @@
#define tcache_enabled_initialized JEMALLOC_N(tcache_enabled_initialized)
#define tcache_enabled_set JEMALLOC_N(tcache_enabled_set)
#define tcache_enabled_tls JEMALLOC_N(tcache_enabled_tls)
#define tcache_enabled_tsd JEMALLOC_N(tcache_enabled_tsd)
#define tcache_enabled_tsd_boot JEMALLOC_N(tcache_enabled_tsd_boot)
#define tcache_enabled_tsd_cleanup_wrapper JEMALLOC_N(tcache_enabled_tsd_cleanup_wrapper)
#define tcache_enabled_tsd_get JEMALLOC_N(tcache_enabled_tsd_get)
@@ -325,6 +351,7 @@
#define tcache_stats_merge JEMALLOC_N(tcache_stats_merge)
#define tcache_thread_cleanup JEMALLOC_N(tcache_thread_cleanup)
#define tcache_tls JEMALLOC_N(tcache_tls)
#define tcache_tsd JEMALLOC_N(tcache_tsd)
#define tcache_tsd_boot JEMALLOC_N(tcache_tsd_boot)
#define tcache_tsd_cleanup_wrapper JEMALLOC_N(tcache_tsd_cleanup_wrapper)
#define tcache_tsd_get JEMALLOC_N(tcache_tsd_get)
@@ -332,6 +359,7 @@
#define thread_allocated_booted JEMALLOC_N(thread_allocated_booted)
#define thread_allocated_initialized JEMALLOC_N(thread_allocated_initialized)
#define thread_allocated_tls JEMALLOC_N(thread_allocated_tls)
#define thread_allocated_tsd JEMALLOC_N(thread_allocated_tsd)
#define thread_allocated_tsd_boot JEMALLOC_N(thread_allocated_tsd_boot)
#define thread_allocated_tsd_cleanup_wrapper JEMALLOC_N(thread_allocated_tsd_cleanup_wrapper)
#define thread_allocated_tsd_get JEMALLOC_N(thread_allocated_tsd_get)
+4 -1
View File
@@ -223,6 +223,9 @@ void prof_tdata_cleanup(void *arg);
void prof_boot0(void);
void prof_boot1(void);
bool prof_boot2(void);
void prof_prefork(void);
void prof_postfork_parent(void);
void prof_postfork_child(void);
#endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/
@@ -506,7 +509,7 @@ prof_realloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt,
if ((uintptr_t)cnt > (uintptr_t)1U) {
prof_ctx_set(ptr, cnt->ctx);
cnt->epoch++;
} else
} else if (ptr != NULL)
prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
/*********/
mb_write();
+3
View File
@@ -36,6 +36,9 @@ struct rtree_s {
#ifdef JEMALLOC_H_EXTERNS
rtree_t *rtree_new(unsigned bits);
void rtree_prefork(rtree_t *rtree);
void rtree_postfork_parent(rtree_t *rtree);
void rtree_postfork_child(rtree_t *rtree);
#endif /* JEMALLOC_H_EXTERNS */
/******************************************************************************/
+4 -1
View File
@@ -25,6 +25,8 @@ extern "C" {
#endif
#define ALLOCM_ZERO ((int)0x40)
#define ALLOCM_NO_MOVE ((int)0x80)
/* Bias arena index bits so that 0 encodes "ALLOCM_ARENA() unspecified". */
#define ALLOCM_ARENA(a) ((int)(((a)+1) << 8))
#define ALLOCM_SUCCESS 0
#define ALLOCM_ERR_OOM 1
@@ -59,7 +61,8 @@ JEMALLOC_EXPORT void * je_memalign(size_t alignment, size_t size)
JEMALLOC_EXPORT void * je_valloc(size_t size) JEMALLOC_ATTR(malloc);
#endif
JEMALLOC_EXPORT size_t je_malloc_usable_size(const void *ptr);
JEMALLOC_EXPORT size_t je_malloc_usable_size(
JEMALLOC_USABLE_SIZE_CONST void *ptr);
JEMALLOC_EXPORT void je_malloc_stats_print(void (*write_cb)(void *,
const char *), void *je_cbopaque, const char *opts);
JEMALLOC_EXPORT int je_mallctl(const char *name, void *oldp,
+9
View File
@@ -221,6 +221,15 @@
#undef JEMALLOC_OVERRIDE_MEMALIGN
#undef JEMALLOC_OVERRIDE_VALLOC
/*
* At least Linux omits the "const" in:
*
* size_t malloc_usable_size(const void *ptr);
*
* Match the operating system's prototype.
*/
#undef JEMALLOC_USABLE_SIZE_CONST
/*
* Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
*/
+427 -272
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -32,7 +32,8 @@ base_pages_alloc(size_t minsize)
assert(minsize != 0);
csize = CHUNK_CEILING(minsize);
zero = false;
base_pages = chunk_alloc(csize, chunksize, true, &zero);
base_pages = chunk_alloc(csize, chunksize, true, &zero,
chunk_dss_prec_get());
if (base_pages == NULL)
return (true);
base_next_addr = base_pages;
+116 -49
View File
@@ -4,7 +4,8 @@
/******************************************************************************/
/* Data. */
size_t opt_lg_chunk = LG_CHUNK_DEFAULT;
const char *opt_dss = DSS_DEFAULT;
size_t opt_lg_chunk = LG_CHUNK_DEFAULT;
malloc_mutex_t chunks_mtx;
chunk_stats_t stats_chunks;
@@ -15,8 +16,10 @@ chunk_stats_t stats_chunks;
* address space. Depending on function, different tree orderings are needed,
* which is why there are two trees with the same contents.
*/
static extent_tree_t chunks_szad;
static extent_tree_t chunks_ad;
static extent_tree_t chunks_szad_mmap;
static extent_tree_t chunks_ad_mmap;
static extent_tree_t chunks_szad_dss;
static extent_tree_t chunks_ad_dss;
rtree_t *chunks_rtree;
@@ -30,19 +33,23 @@ size_t arena_maxclass; /* Max size class for arenas. */
/******************************************************************************/
/* Function prototypes for non-inline static functions. */
static void *chunk_recycle(size_t size, size_t alignment, bool base,
static void *chunk_recycle(extent_tree_t *chunks_szad,
extent_tree_t *chunks_ad, size_t size, size_t alignment, bool base,
bool *zero);
static void chunk_record(void *chunk, size_t size);
static void chunk_record(extent_tree_t *chunks_szad,
extent_tree_t *chunks_ad, void *chunk, size_t size);
/******************************************************************************/
static void *
chunk_recycle(size_t size, size_t alignment, bool base, bool *zero)
chunk_recycle(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size,
size_t alignment, bool base, bool *zero)
{
void *ret;
extent_node_t *node;
extent_node_t key;
size_t alloc_size, leadsize, trailsize;
bool zeroed;
if (base) {
/*
@@ -61,7 +68,7 @@ chunk_recycle(size_t size, size_t alignment, bool base, bool *zero)
key.addr = NULL;
key.size = alloc_size;
malloc_mutex_lock(&chunks_mtx);
node = extent_tree_szad_nsearch(&chunks_szad, &key);
node = extent_tree_szad_nsearch(chunks_szad, &key);
if (node == NULL) {
malloc_mutex_unlock(&chunks_mtx);
return (NULL);
@@ -72,13 +79,13 @@ chunk_recycle(size_t size, size_t alignment, bool base, bool *zero)
trailsize = node->size - leadsize - size;
ret = (void *)((uintptr_t)node->addr + leadsize);
/* Remove node from the tree. */
extent_tree_szad_remove(&chunks_szad, node);
extent_tree_ad_remove(&chunks_ad, node);
extent_tree_szad_remove(chunks_szad, node);
extent_tree_ad_remove(chunks_ad, node);
if (leadsize != 0) {
/* Insert the leading space as a smaller chunk. */
node->size = leadsize;
extent_tree_szad_insert(&chunks_szad, node);
extent_tree_ad_insert(&chunks_ad, node);
extent_tree_szad_insert(chunks_szad, node);
extent_tree_ad_insert(chunks_ad, node);
node = NULL;
}
if (trailsize != 0) {
@@ -101,23 +108,24 @@ chunk_recycle(size_t size, size_t alignment, bool base, bool *zero)
}
node->addr = (void *)((uintptr_t)(ret) + size);
node->size = trailsize;
extent_tree_szad_insert(&chunks_szad, node);
extent_tree_ad_insert(&chunks_ad, node);
extent_tree_szad_insert(chunks_szad, node);
extent_tree_ad_insert(chunks_ad, node);
node = NULL;
}
malloc_mutex_unlock(&chunks_mtx);
if (node != NULL)
zeroed = false;
if (node != NULL) {
if (node->zeroed) {
zeroed = true;
*zero = true;
}
base_node_dealloc(node);
#ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
/* Pages are zeroed as a side effect of pages_purge(). */
*zero = true;
#else
if (*zero) {
}
if (zeroed == false && *zero) {
VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
memset(ret, 0, size);
}
#endif
return (ret);
}
@@ -128,7 +136,8 @@ chunk_recycle(size_t size, size_t alignment, bool base, bool *zero)
* advantage of them if they are returned.
*/
void *
chunk_alloc(size_t size, size_t alignment, bool base, bool *zero)
chunk_alloc(size_t size, size_t alignment, bool base, bool *zero,
dss_prec_t dss_prec)
{
void *ret;
@@ -137,17 +146,26 @@ chunk_alloc(size_t size, size_t alignment, bool base, bool *zero)
assert(alignment != 0);
assert((alignment & chunksize_mask) == 0);
ret = chunk_recycle(size, alignment, base, zero);
if (ret != NULL)
/* "primary" dss. */
if (config_dss && dss_prec == dss_prec_primary) {
if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size,
alignment, base, zero)) != NULL)
goto label_return;
if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL)
goto label_return;
}
/* mmap. */
if ((ret = chunk_recycle(&chunks_szad_mmap, &chunks_ad_mmap, size,
alignment, base, zero)) != NULL)
goto label_return;
ret = chunk_alloc_mmap(size, alignment, zero);
if (ret != NULL)
if ((ret = chunk_alloc_mmap(size, alignment, zero)) != NULL)
goto label_return;
if (config_dss) {
ret = chunk_alloc_dss(size, alignment, zero);
if (ret != NULL)
/* "secondary" dss. */
if (config_dss && dss_prec == dss_prec_secondary) {
if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size,
alignment, base, zero)) != NULL)
goto label_return;
if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL)
goto label_return;
}
@@ -189,11 +207,13 @@ label_return:
}
static void
chunk_record(void *chunk, size_t size)
chunk_record(extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, void *chunk,
size_t size)
{
bool unzeroed;
extent_node_t *xnode, *node, *prev, key;
pages_purge(chunk, size);
unzeroed = pages_purge(chunk, size);
/*
* Allocate a node before acquiring chunks_mtx even though it might not
@@ -205,7 +225,7 @@ chunk_record(void *chunk, size_t size)
malloc_mutex_lock(&chunks_mtx);
key.addr = (void *)((uintptr_t)chunk + size);
node = extent_tree_ad_nsearch(&chunks_ad, &key);
node = extent_tree_ad_nsearch(chunks_ad, &key);
/* Try to coalesce forward. */
if (node != NULL && node->addr == key.addr) {
/*
@@ -213,10 +233,11 @@ chunk_record(void *chunk, size_t size)
* not change the position within chunks_ad, so only
* remove/insert from/into chunks_szad.
*/
extent_tree_szad_remove(&chunks_szad, node);
extent_tree_szad_remove(chunks_szad, node);
node->addr = chunk;
node->size += size;
extent_tree_szad_insert(&chunks_szad, node);
node->zeroed = (node->zeroed && (unzeroed == false));
extent_tree_szad_insert(chunks_szad, node);
if (xnode != NULL)
base_node_dealloc(xnode);
} else {
@@ -234,12 +255,13 @@ chunk_record(void *chunk, size_t size)
node = xnode;
node->addr = chunk;
node->size = size;
extent_tree_ad_insert(&chunks_ad, node);
extent_tree_szad_insert(&chunks_szad, node);
node->zeroed = (unzeroed == false);
extent_tree_ad_insert(chunks_ad, node);
extent_tree_szad_insert(chunks_szad, node);
}
/* Try to coalesce backward. */
prev = extent_tree_ad_prev(&chunks_ad, node);
prev = extent_tree_ad_prev(chunks_ad, node);
if (prev != NULL && (void *)((uintptr_t)prev->addr + prev->size) ==
chunk) {
/*
@@ -247,19 +269,34 @@ chunk_record(void *chunk, size_t size)
* not change the position within chunks_ad, so only
* remove/insert node from/into chunks_szad.
*/
extent_tree_szad_remove(&chunks_szad, prev);
extent_tree_ad_remove(&chunks_ad, prev);
extent_tree_szad_remove(chunks_szad, prev);
extent_tree_ad_remove(chunks_ad, prev);
extent_tree_szad_remove(&chunks_szad, node);
extent_tree_szad_remove(chunks_szad, node);
node->addr = prev->addr;
node->size += prev->size;
extent_tree_szad_insert(&chunks_szad, node);
node->zeroed = (node->zeroed && prev->zeroed);
extent_tree_szad_insert(chunks_szad, node);
base_node_dealloc(prev);
}
malloc_mutex_unlock(&chunks_mtx);
}
void
chunk_unmap(void *chunk, size_t size)
{
assert(chunk != NULL);
assert(CHUNK_ADDR2BASE(chunk) == chunk);
assert(size != 0);
assert((size & chunksize_mask) == 0);
if (config_dss && chunk_in_dss(chunk))
chunk_record(&chunks_szad_dss, &chunks_ad_dss, chunk, size);
else if (chunk_dealloc_mmap(chunk, size))
chunk_record(&chunks_szad_mmap, &chunks_ad_mmap, chunk, size);
}
void
chunk_dealloc(void *chunk, size_t size, bool unmap)
{
@@ -273,15 +310,13 @@ chunk_dealloc(void *chunk, size_t size, bool unmap)
rtree_set(chunks_rtree, (uintptr_t)chunk, NULL);
if (config_stats || config_prof) {
malloc_mutex_lock(&chunks_mtx);
assert(stats_chunks.curchunks >= (size / chunksize));
stats_chunks.curchunks -= (size / chunksize);
malloc_mutex_unlock(&chunks_mtx);
}
if (unmap) {
if ((config_dss && chunk_in_dss(chunk)) ||
chunk_dealloc_mmap(chunk, size))
chunk_record(chunk, size);
}
if (unmap)
chunk_unmap(chunk, size);
}
bool
@@ -301,8 +336,10 @@ chunk_boot(void)
}
if (config_dss && chunk_dss_boot())
return (true);
extent_tree_szad_new(&chunks_szad);
extent_tree_ad_new(&chunks_ad);
extent_tree_szad_new(&chunks_szad_mmap);
extent_tree_ad_new(&chunks_ad_mmap);
extent_tree_szad_new(&chunks_szad_dss);
extent_tree_ad_new(&chunks_ad_dss);
if (config_ivsalloc) {
chunks_rtree = rtree_new((ZU(1) << (LG_SIZEOF_PTR+3)) -
opt_lg_chunk);
@@ -312,3 +349,33 @@ chunk_boot(void)
return (false);
}
void
chunk_prefork(void)
{
malloc_mutex_lock(&chunks_mtx);
if (config_ivsalloc)
rtree_prefork(chunks_rtree);
chunk_dss_prefork();
}
void
chunk_postfork_parent(void)
{
chunk_dss_postfork_parent();
if (config_ivsalloc)
rtree_postfork_parent(chunks_rtree);
malloc_mutex_postfork_parent(&chunks_mtx);
}
void
chunk_postfork_child(void)
{
chunk_dss_postfork_child();
if (config_ivsalloc)
rtree_postfork_child(chunks_rtree);
malloc_mutex_postfork_child(&chunks_mtx);
}
+36 -1
View File
@@ -3,6 +3,16 @@
/******************************************************************************/
/* Data. */
const char *dss_prec_names[] = {
"disabled",
"primary",
"secondary",
"N/A"
};
/* Current dss precedence default, used when creating new arenas. */
static dss_prec_t dss_prec_default = DSS_PREC_DEFAULT;
/*
* Protects sbrk() calls. This avoids malloc races among threads, though it
* does not protect against races with threads that call sbrk() directly.
@@ -29,6 +39,31 @@ sbrk(intptr_t increment)
}
#endif
dss_prec_t
chunk_dss_prec_get(void)
{
dss_prec_t ret;
if (config_dss == false)
return (dss_prec_disabled);
malloc_mutex_lock(&dss_mtx);
ret = dss_prec_default;
malloc_mutex_unlock(&dss_mtx);
return (ret);
}
bool
chunk_dss_prec_set(dss_prec_t dss_prec)
{
if (config_dss == false)
return (true);
malloc_mutex_lock(&dss_mtx);
dss_prec_default = dss_prec;
malloc_mutex_unlock(&dss_mtx);
return (false);
}
void *
chunk_alloc_dss(size_t size, size_t alignment, bool *zero)
{
@@ -88,7 +123,7 @@ chunk_alloc_dss(size_t size, size_t alignment, bool *zero)
dss_max = dss_next;
malloc_mutex_unlock(&dss_mtx);
if (cpad_size != 0)
chunk_dealloc(cpad, cpad_size, true);
chunk_unmap(cpad, cpad_size);
if (*zero) {
VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
memset(ret, 0, size);
+10 -2
View File
@@ -113,22 +113,30 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size)
#endif
}
void
bool
pages_purge(void *addr, size_t length)
{
bool unzeroed;
#ifdef _WIN32
VirtualAlloc(addr, length, MEM_RESET, PAGE_READWRITE);
unzeroed = true;
#else
# ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
# define JEMALLOC_MADV_PURGE MADV_DONTNEED
# define JEMALLOC_MADV_ZEROS true
# elif defined(JEMALLOC_PURGE_MADVISE_FREE)
# define JEMALLOC_MADV_PURGE MADV_FREE
# define JEMALLOC_MADV_ZEROS false
# else
# error "No method defined for purging unused dirty pages."
# endif
madvise(addr, length, JEMALLOC_MADV_PURGE);
int err = madvise(addr, length, JEMALLOC_MADV_PURGE);
unzeroed = (JEMALLOC_MADV_ZEROS == false || err != 0);
# undef JEMALLOC_MADV_PURGE
# undef JEMALLOC_MADV_ZEROS
#endif
return (unzeroed);
}
static void *
+309 -56
View File
@@ -48,8 +48,8 @@ static int n##_ctl(const size_t *mib, size_t miblen, void *oldp, \
size_t *oldlenp, void *newp, size_t newlen);
#define INDEX_PROTO(n) \
const ctl_named_node_t *n##_index(const size_t *mib, size_t miblen, \
size_t i);
static const ctl_named_node_t *n##_index(const size_t *mib, \
size_t miblen, size_t i);
static bool ctl_arena_init(ctl_arena_stats_t *astats);
static void ctl_arena_clear(ctl_arena_stats_t *astats);
@@ -58,6 +58,7 @@ static void ctl_arena_stats_amerge(ctl_arena_stats_t *cstats,
static void ctl_arena_stats_smerge(ctl_arena_stats_t *sstats,
ctl_arena_stats_t *astats);
static void ctl_arena_refresh(arena_t *arena, unsigned i);
static bool ctl_grow(void);
static void ctl_refresh(void);
static bool ctl_init(void);
static int ctl_lookup(const char *name, ctl_node_t const **nodesp,
@@ -88,6 +89,7 @@ CTL_PROTO(config_utrace)
CTL_PROTO(config_valgrind)
CTL_PROTO(config_xmalloc)
CTL_PROTO(opt_abort)
CTL_PROTO(opt_dss)
CTL_PROTO(opt_lg_chunk)
CTL_PROTO(opt_narenas)
CTL_PROTO(opt_lg_dirty_mult)
@@ -110,6 +112,10 @@ CTL_PROTO(opt_prof_gdump)
CTL_PROTO(opt_prof_final)
CTL_PROTO(opt_prof_leak)
CTL_PROTO(opt_prof_accum)
CTL_PROTO(arena_i_purge)
static void arena_purge(unsigned arena_ind);
CTL_PROTO(arena_i_dss)
INDEX_PROTO(arena_i)
CTL_PROTO(arenas_bin_i_size)
CTL_PROTO(arenas_bin_i_nregs)
CTL_PROTO(arenas_bin_i_run_size)
@@ -125,6 +131,7 @@ CTL_PROTO(arenas_nbins)
CTL_PROTO(arenas_nhbins)
CTL_PROTO(arenas_nlruns)
CTL_PROTO(arenas_purge)
CTL_PROTO(arenas_extend)
CTL_PROTO(prof_active)
CTL_PROTO(prof_dump)
CTL_PROTO(prof_interval)
@@ -158,6 +165,7 @@ CTL_PROTO(stats_arenas_i_lruns_j_nrequests)
CTL_PROTO(stats_arenas_i_lruns_j_curruns)
INDEX_PROTO(stats_arenas_i_lruns_j)
CTL_PROTO(stats_arenas_i_nthreads)
CTL_PROTO(stats_arenas_i_dss)
CTL_PROTO(stats_arenas_i_pactive)
CTL_PROTO(stats_arenas_i_pdirty)
CTL_PROTO(stats_arenas_i_mapped)
@@ -223,6 +231,7 @@ static const ctl_named_node_t config_node[] = {
static const ctl_named_node_t opt_node[] = {
{NAME("abort"), CTL(opt_abort)},
{NAME("dss"), CTL(opt_dss)},
{NAME("lg_chunk"), CTL(opt_lg_chunk)},
{NAME("narenas"), CTL(opt_narenas)},
{NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)},
@@ -247,6 +256,18 @@ static const ctl_named_node_t opt_node[] = {
{NAME("prof_accum"), CTL(opt_prof_accum)}
};
static const ctl_named_node_t arena_i_node[] = {
{NAME("purge"), CTL(arena_i_purge)},
{NAME("dss"), CTL(arena_i_dss)}
};
static const ctl_named_node_t super_arena_i_node[] = {
{NAME(""), CHILD(named, arena_i)}
};
static const ctl_indexed_node_t arena_node[] = {
{INDEX(arena_i)}
};
static const ctl_named_node_t arenas_bin_i_node[] = {
{NAME("size"), CTL(arenas_bin_i_size)},
{NAME("nregs"), CTL(arenas_bin_i_nregs)},
@@ -282,7 +303,8 @@ static const ctl_named_node_t arenas_node[] = {
{NAME("bin"), CHILD(indexed, arenas_bin)},
{NAME("nlruns"), CTL(arenas_nlruns)},
{NAME("lrun"), CHILD(indexed, arenas_lrun)},
{NAME("purge"), CTL(arenas_purge)}
{NAME("purge"), CTL(arenas_purge)},
{NAME("extend"), CTL(arenas_extend)}
};
static const ctl_named_node_t prof_node[] = {
@@ -352,6 +374,7 @@ static const ctl_indexed_node_t stats_arenas_i_lruns_node[] = {
static const ctl_named_node_t stats_arenas_i_node[] = {
{NAME("nthreads"), CTL(stats_arenas_i_nthreads)},
{NAME("dss"), CTL(stats_arenas_i_dss)},
{NAME("pactive"), CTL(stats_arenas_i_pactive)},
{NAME("pdirty"), CTL(stats_arenas_i_pdirty)},
{NAME("mapped"), CTL(stats_arenas_i_mapped)},
@@ -387,6 +410,7 @@ static const ctl_named_node_t root_node[] = {
{NAME("thread"), CHILD(named, thread)},
{NAME("config"), CHILD(named, config)},
{NAME("opt"), CHILD(named, opt)},
{NAME("arena"), CHILD(indexed, arena)},
{NAME("arenas"), CHILD(named, arenas)},
{NAME("prof"), CHILD(named, prof)},
{NAME("stats"), CHILD(named, stats)}
@@ -420,6 +444,7 @@ static void
ctl_arena_clear(ctl_arena_stats_t *astats)
{
astats->dss = dss_prec_names[dss_prec_limit];
astats->pactive = 0;
astats->pdirty = 0;
if (config_stats) {
@@ -439,8 +464,8 @@ ctl_arena_stats_amerge(ctl_arena_stats_t *cstats, arena_t *arena)
{
unsigned i;
arena_stats_merge(arena, &cstats->pactive, &cstats->pdirty,
&cstats->astats, cstats->bstats, cstats->lstats);
arena_stats_merge(arena, &cstats->dss, &cstats->pactive,
&cstats->pdirty, &cstats->astats, cstats->bstats, cstats->lstats);
for (i = 0; i < NBINS; i++) {
cstats->allocated_small += cstats->bstats[i].allocated;
@@ -500,7 +525,7 @@ static void
ctl_arena_refresh(arena_t *arena, unsigned i)
{
ctl_arena_stats_t *astats = &ctl_stats.arenas[i];
ctl_arena_stats_t *sstats = &ctl_stats.arenas[narenas];
ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas];
ctl_arena_clear(astats);
@@ -518,11 +543,72 @@ ctl_arena_refresh(arena_t *arena, unsigned i)
}
}
static bool
ctl_grow(void)
{
size_t astats_size;
ctl_arena_stats_t *astats;
arena_t **tarenas;
/* Extend arena stats and arenas arrays. */
astats_size = (ctl_stats.narenas + 2) * sizeof(ctl_arena_stats_t);
if (ctl_stats.narenas == narenas_auto) {
/* ctl_stats.arenas and arenas came from base_alloc(). */
astats = (ctl_arena_stats_t *)imalloc(astats_size);
if (astats == NULL)
return (true);
memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) *
sizeof(ctl_arena_stats_t));
tarenas = (arena_t **)imalloc((ctl_stats.narenas + 1) *
sizeof(arena_t *));
if (tarenas == NULL) {
idalloc(astats);
return (true);
}
memcpy(tarenas, arenas, ctl_stats.narenas * sizeof(arena_t *));
} else {
astats = (ctl_arena_stats_t *)iralloc(ctl_stats.arenas,
astats_size, 0, 0, false, false);
if (astats == NULL)
return (true);
tarenas = (arena_t **)iralloc(arenas, (ctl_stats.narenas + 1) *
sizeof(arena_t *), 0, 0, false, false);
if (tarenas == NULL)
return (true);
}
/* Initialize the new astats and arenas elements. */
memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t));
if (ctl_arena_init(&astats[ctl_stats.narenas + 1]))
return (true);
tarenas[ctl_stats.narenas] = NULL;
/* Swap merged stats to their new location. */
{
ctl_arena_stats_t tstats;
memcpy(&tstats, &astats[ctl_stats.narenas],
sizeof(ctl_arena_stats_t));
memcpy(&astats[ctl_stats.narenas],
&astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t));
memcpy(&astats[ctl_stats.narenas + 1], &tstats,
sizeof(ctl_arena_stats_t));
}
ctl_stats.arenas = astats;
ctl_stats.narenas++;
malloc_mutex_lock(&arenas_lock);
arenas = tarenas;
narenas_total++;
arenas_extend(narenas_total - 1);
malloc_mutex_unlock(&arenas_lock);
return (false);
}
static void
ctl_refresh(void)
{
unsigned i;
VARIABLE_ARRAY(arena_t *, tarenas, narenas);
VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
if (config_stats) {
malloc_mutex_lock(&chunks_mtx);
@@ -542,19 +628,19 @@ ctl_refresh(void)
* Clear sum stats, since they will be merged into by
* ctl_arena_refresh().
*/
ctl_stats.arenas[narenas].nthreads = 0;
ctl_arena_clear(&ctl_stats.arenas[narenas]);
ctl_stats.arenas[ctl_stats.narenas].nthreads = 0;
ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]);
malloc_mutex_lock(&arenas_lock);
memcpy(tarenas, arenas, sizeof(arena_t *) * narenas);
for (i = 0; i < narenas; i++) {
memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
for (i = 0; i < ctl_stats.narenas; i++) {
if (arenas[i] != NULL)
ctl_stats.arenas[i].nthreads = arenas[i]->nthreads;
else
ctl_stats.arenas[i].nthreads = 0;
}
malloc_mutex_unlock(&arenas_lock);
for (i = 0; i < narenas; i++) {
for (i = 0; i < ctl_stats.narenas; i++) {
bool initialized = (tarenas[i] != NULL);
ctl_stats.arenas[i].initialized = initialized;
@@ -563,11 +649,13 @@ ctl_refresh(void)
}
if (config_stats) {
ctl_stats.allocated = ctl_stats.arenas[narenas].allocated_small
+ ctl_stats.arenas[narenas].astats.allocated_large
ctl_stats.allocated =
ctl_stats.arenas[ctl_stats.narenas].allocated_small
+ ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large
+ ctl_stats.huge.allocated;
ctl_stats.active =
(ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE)
+ ctl_stats.huge.allocated;
ctl_stats.active = (ctl_stats.arenas[narenas].pactive <<
LG_PAGE) + ctl_stats.huge.allocated;
ctl_stats.mapped = (ctl_stats.chunks.current << opt_lg_chunk);
}
@@ -585,13 +673,15 @@ ctl_init(void)
* Allocate space for one extra arena stats element, which
* contains summed stats across all arenas.
*/
assert(narenas_auto == narenas_total_get());
ctl_stats.narenas = narenas_auto;
ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc(
(narenas + 1) * sizeof(ctl_arena_stats_t));
(ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t));
if (ctl_stats.arenas == NULL) {
ret = true;
goto label_return;
}
memset(ctl_stats.arenas, 0, (narenas + 1) *
memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) *
sizeof(ctl_arena_stats_t));
/*
@@ -601,14 +691,14 @@ ctl_init(void)
*/
if (config_stats) {
unsigned i;
for (i = 0; i <= narenas; i++) {
for (i = 0; i <= ctl_stats.narenas; i++) {
if (ctl_arena_init(&ctl_stats.arenas[i])) {
ret = true;
goto label_return;
}
}
}
ctl_stats.arenas[narenas].initialized = true;
ctl_stats.arenas[ctl_stats.narenas].initialized = true;
ctl_epoch = 0;
ctl_refresh();
@@ -827,6 +917,27 @@ ctl_boot(void)
return (false);
}
void
ctl_prefork(void)
{
malloc_mutex_lock(&ctl_mtx);
}
void
ctl_postfork_parent(void)
{
malloc_mutex_postfork_parent(&ctl_mtx);
}
void
ctl_postfork_child(void)
{
malloc_mutex_postfork_child(&ctl_mtx);
}
/******************************************************************************/
/* *_ctl() functions. */
@@ -1032,8 +1143,8 @@ thread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp,
}
READ(oldval, bool);
label_return:
ret = 0;
label_return:
return (ret);
}
@@ -1063,13 +1174,14 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
int ret;
unsigned newind, oldind;
malloc_mutex_lock(&ctl_mtx);
newind = oldind = choose_arena(NULL)->ind;
WRITE(newind, unsigned);
READ(oldind, unsigned);
if (newind != oldind) {
arena_t *arena;
if (newind >= narenas) {
if (newind >= ctl_stats.narenas) {
/* New arena index is out of range. */
ret = EFAULT;
goto label_return;
@@ -1102,6 +1214,7 @@ thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
ret = 0;
label_return:
malloc_mutex_unlock(&ctl_mtx);
return (ret);
}
@@ -1135,6 +1248,7 @@ CTL_RO_BOOL_CONFIG_GEN(config_xmalloc)
/******************************************************************************/
CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
CTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t)
CTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t)
CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t)
@@ -1158,12 +1272,123 @@ CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
/******************************************************************************/
/* ctl_mutex must be held during execution of this function. */
static void
arena_purge(unsigned arena_ind)
{
VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas);
malloc_mutex_lock(&arenas_lock);
memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas);
malloc_mutex_unlock(&arenas_lock);
if (arena_ind == ctl_stats.narenas) {
unsigned i;
for (i = 0; i < ctl_stats.narenas; i++) {
if (tarenas[i] != NULL)
arena_purge_all(tarenas[i]);
}
} else {
assert(arena_ind < ctl_stats.narenas);
if (tarenas[arena_ind] != NULL)
arena_purge_all(tarenas[arena_ind]);
}
}
static int
arena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
int ret;
READONLY();
WRITEONLY();
malloc_mutex_lock(&ctl_mtx);
arena_purge(mib[1]);
malloc_mutex_unlock(&ctl_mtx);
ret = 0;
label_return:
return (ret);
}
static int
arena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
int ret, i;
bool match, err;
const char *dss;
unsigned arena_ind = mib[1];
dss_prec_t dss_prec_old = dss_prec_limit;
dss_prec_t dss_prec = dss_prec_limit;
malloc_mutex_lock(&ctl_mtx);
WRITE(dss, const char *);
match = false;
for (i = 0; i < dss_prec_limit; i++) {
if (strcmp(dss_prec_names[i], dss) == 0) {
dss_prec = i;
match = true;
break;
}
}
if (match == false) {
ret = EINVAL;
goto label_return;
}
if (arena_ind < ctl_stats.narenas) {
arena_t *arena = arenas[arena_ind];
if (arena != NULL) {
dss_prec_old = arena_dss_prec_get(arena);
arena_dss_prec_set(arena, dss_prec);
err = false;
} else
err = true;
} else {
dss_prec_old = chunk_dss_prec_get();
err = chunk_dss_prec_set(dss_prec);
}
dss = dss_prec_names[dss_prec_old];
READ(dss, const char *);
if (err) {
ret = EFAULT;
goto label_return;
}
ret = 0;
label_return:
malloc_mutex_unlock(&ctl_mtx);
return (ret);
}
static const ctl_named_node_t *
arena_i_index(const size_t *mib, size_t miblen, size_t i)
{
const ctl_named_node_t * ret;
malloc_mutex_lock(&ctl_mtx);
if (i > ctl_stats.narenas) {
ret = NULL;
goto label_return;
}
ret = super_arena_i_node;
label_return:
malloc_mutex_unlock(&ctl_mtx);
return (ret);
}
/******************************************************************************/
CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t)
const ctl_named_node_t *
static const ctl_named_node_t *
arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
{
@@ -1173,7 +1398,7 @@ arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i)
}
CTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << LG_PAGE), size_t)
const ctl_named_node_t *
static const ctl_named_node_t *
arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
{
@@ -1182,7 +1407,27 @@ arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i)
return (super_arenas_lrun_i_node);
}
CTL_RO_NL_GEN(arenas_narenas, narenas, unsigned)
static int
arenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen)
{
int ret;
unsigned narenas;
malloc_mutex_lock(&ctl_mtx);
READONLY();
if (*oldlenp != sizeof(unsigned)) {
ret = EINVAL;
goto label_return;
}
narenas = ctl_stats.narenas;
READ(narenas, unsigned);
ret = 0;
label_return:
malloc_mutex_unlock(&ctl_mtx);
return (ret);
}
static int
arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
@@ -1193,13 +1438,13 @@ arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp,
malloc_mutex_lock(&ctl_mtx);
READONLY();
if (*oldlenp != narenas * sizeof(bool)) {
if (*oldlenp != ctl_stats.narenas * sizeof(bool)) {
ret = EINVAL;
nread = (*oldlenp < narenas * sizeof(bool))
? (*oldlenp / sizeof(bool)) : narenas;
nread = (*oldlenp < ctl_stats.narenas * sizeof(bool))
? (*oldlenp / sizeof(bool)) : ctl_stats.narenas;
} else {
ret = 0;
nread = narenas;
nread = ctl_stats.narenas;
}
for (i = 0; i < nread; i++)
@@ -1222,36 +1467,43 @@ arenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
int ret;
unsigned arena;
unsigned arena_ind;
malloc_mutex_lock(&ctl_mtx);
WRITEONLY();
arena = UINT_MAX;
WRITE(arena, unsigned);
if (newp != NULL && arena >= narenas) {
arena_ind = UINT_MAX;
WRITE(arena_ind, unsigned);
if (newp != NULL && arena_ind >= ctl_stats.narenas)
ret = EFAULT;
goto label_return;
} else {
VARIABLE_ARRAY(arena_t *, tarenas, narenas);
malloc_mutex_lock(&arenas_lock);
memcpy(tarenas, arenas, sizeof(arena_t *) * narenas);
malloc_mutex_unlock(&arenas_lock);
if (arena == UINT_MAX) {
unsigned i;
for (i = 0; i < narenas; i++) {
if (tarenas[i] != NULL)
arena_purge_all(tarenas[i]);
}
} else {
assert(arena < narenas);
if (tarenas[arena] != NULL)
arena_purge_all(tarenas[arena]);
}
else {
if (arena_ind == UINT_MAX)
arena_ind = ctl_stats.narenas;
arena_purge(arena_ind);
ret = 0;
}
label_return:
malloc_mutex_unlock(&ctl_mtx);
return (ret);
}
static int
arenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen)
{
int ret;
malloc_mutex_lock(&ctl_mtx);
READONLY();
if (ctl_grow()) {
ret = EAGAIN;
goto label_return;
}
READ(ctl_stats.narenas - 1, unsigned);
ret = 0;
label_return:
malloc_mutex_unlock(&ctl_mtx);
return (ret);
}
@@ -1356,7 +1608,7 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns,
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns,
ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t)
const ctl_named_node_t *
static const ctl_named_node_t *
stats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j)
{
@@ -1374,7 +1626,7 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests,
CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns,
ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t)
const ctl_named_node_t *
static const ctl_named_node_t *
stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
{
@@ -1384,6 +1636,7 @@ stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j)
}
CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned)
CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *)
CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t)
CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t)
CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
@@ -1395,13 +1648,13 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise,
CTL_RO_CGEN(config_stats, stats_arenas_i_purged,
ctl_stats.arenas[mib[2]].astats.purged, uint64_t)
const ctl_named_node_t *
static const ctl_named_node_t *
stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i)
{
const ctl_named_node_t * ret;
malloc_mutex_lock(&ctl_mtx);
if (ctl_stats.arenas[i].initialized == false) {
if (i > ctl_stats.narenas || ctl_stats.arenas[i].initialized == false) {
ret = NULL;
goto label_return;
}
+4 -3
View File
@@ -48,7 +48,8 @@ huge_palloc(size_t size, size_t alignment, bool zero)
* it is possible to make correct junk/zero fill decisions below.
*/
is_zeroed = zero;
ret = chunk_alloc(csize, alignment, false, &is_zeroed);
ret = chunk_alloc(csize, alignment, false, &is_zeroed,
chunk_dss_prec_get());
if (ret == NULL) {
base_node_dealloc(node);
return (NULL);
@@ -101,7 +102,7 @@ huge_ralloc_no_move(void *ptr, size_t oldsize, size_t size, size_t extra)
void *
huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
size_t alignment, bool zero)
size_t alignment, bool zero, bool try_tcache_dalloc)
{
void *ret;
size_t copysize;
@@ -180,7 +181,7 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
#endif
{
memcpy(ret, ptr, copysize);
iqalloc(ptr);
iqallocx(ptr, try_tcache_dalloc);
}
return (ret);
}
+155 -57
View File
@@ -33,7 +33,8 @@ unsigned ncpus;
malloc_mutex_t arenas_lock;
arena_t **arenas;
unsigned narenas;
unsigned narenas_total;
unsigned narenas_auto;
/* Set to true once the allocator has been initialized. */
static bool malloc_initialized = false;
@@ -144,14 +145,14 @@ choose_arena_hard(void)
{
arena_t *ret;
if (narenas > 1) {
if (narenas_auto > 1) {
unsigned i, choose, first_null;
choose = 0;
first_null = narenas;
first_null = narenas_auto;
malloc_mutex_lock(&arenas_lock);
assert(arenas[0] != NULL);
for (i = 1; i < narenas; i++) {
for (i = 1; i < narenas_auto; i++) {
if (arenas[i] != NULL) {
/*
* Choose the first arena that has the lowest
@@ -160,7 +161,7 @@ choose_arena_hard(void)
if (arenas[i]->nthreads <
arenas[choose]->nthreads)
choose = i;
} else if (first_null == narenas) {
} else if (first_null == narenas_auto) {
/*
* Record the index of the first uninitialized
* arena, in case all extant arenas are in use.
@@ -174,7 +175,8 @@ choose_arena_hard(void)
}
}
if (arenas[choose]->nthreads == 0 || first_null == narenas) {
if (arenas[choose]->nthreads == 0
|| first_null == narenas_auto) {
/*
* Use an unloaded arena, or the least loaded arena if
* all arenas are already initialized.
@@ -203,7 +205,7 @@ stats_print_atexit(void)
{
if (config_tcache && config_stats) {
unsigned i;
unsigned narenas, i;
/*
* Merge stats from extant threads. This is racy, since
@@ -212,7 +214,7 @@ stats_print_atexit(void)
* out of date by the time they are reported, if other threads
* continue to allocate.
*/
for (i = 0; i < narenas; i++) {
for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
arena_t *arena = arenas[i];
if (arena != NULL) {
tcache_t *tcache;
@@ -254,12 +256,13 @@ malloc_ncpus(void)
result = si.dwNumberOfProcessors;
#else
result = sysconf(_SC_NPROCESSORS_ONLN);
#endif
if (result == -1) {
/* Error. */
ret = 1;
}
#endif
ret = (unsigned)result;
} else {
ret = (unsigned)result;
}
return (ret);
}
@@ -377,6 +380,22 @@ malloc_conf_init(void)
const char *opts, *k, *v;
size_t klen, vlen;
/*
* Automatically configure valgrind before processing options. The
* valgrind option remains in jemalloc 3.x for compatibility reasons.
*/
if (config_valgrind) {
opt_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false;
if (config_fill && opt_valgrind) {
opt_junk = false;
assert(opt_zero == false);
opt_quarantine = JEMALLOC_VALGRIND_QUARANTINE_DEFAULT;
opt_redzone = true;
}
if (config_tcache && opt_valgrind)
opt_tcache = false;
}
for (i = 0; i < 3; i++) {
/* Get runtime configuration. */
switch (i) {
@@ -537,6 +556,30 @@ malloc_conf_init(void)
*/
CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE +
(config_fill ? 2 : 1), (sizeof(size_t) << 3) - 1)
if (strncmp("dss", k, klen) == 0) {
int i;
bool match = false;
for (i = 0; i < dss_prec_limit; i++) {
if (strncmp(dss_prec_names[i], v, vlen)
== 0) {
if (chunk_dss_prec_set(i)) {
malloc_conf_error(
"Error setting dss",
k, klen, v, vlen);
} else {
opt_dss =
dss_prec_names[i];
match = true;
break;
}
}
}
if (match == false) {
malloc_conf_error("Invalid conf value",
k, klen, v, vlen);
}
continue;
}
CONF_HANDLE_SIZE_T(opt_narenas, "narenas", 1,
SIZE_T_MAX)
CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult",
@@ -553,20 +596,7 @@ malloc_conf_init(void)
CONF_HANDLE_BOOL(opt_utrace, "utrace")
}
if (config_valgrind) {
bool hit;
CONF_HANDLE_BOOL_HIT(opt_valgrind,
"valgrind", hit)
if (config_fill && opt_valgrind && hit) {
opt_junk = false;
opt_zero = false;
if (opt_quarantine == 0) {
opt_quarantine =
JEMALLOC_VALGRIND_QUARANTINE_DEFAULT;
}
opt_redzone = true;
}
if (hit)
continue;
CONF_HANDLE_BOOL(opt_valgrind, "valgrind")
}
if (config_xmalloc) {
CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
@@ -695,9 +725,9 @@ malloc_init_hard(void)
* Create enough scaffolding to allow recursive allocation in
* malloc_ncpus().
*/
narenas = 1;
narenas_total = narenas_auto = 1;
arenas = init_arenas;
memset(arenas, 0, sizeof(arena_t *) * narenas);
memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
/*
* Initialize one arena here. The rest are lazily created in
@@ -755,20 +785,21 @@ malloc_init_hard(void)
else
opt_narenas = 1;
}
narenas = opt_narenas;
narenas_auto = opt_narenas;
/*
* Make sure that the arenas array can be allocated. In practice, this
* limit is enough to allow the allocator to function, but the ctl
* machinery will fail to allocate memory at far lower limits.
*/
if (narenas > chunksize / sizeof(arena_t *)) {
narenas = chunksize / sizeof(arena_t *);
if (narenas_auto > chunksize / sizeof(arena_t *)) {
narenas_auto = chunksize / sizeof(arena_t *);
malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
narenas);
narenas_auto);
}
narenas_total = narenas_auto;
/* Allocate and initialize arenas. */
arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas);
arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas_total);
if (arenas == NULL) {
malloc_mutex_unlock(&init_lock);
return (true);
@@ -777,7 +808,7 @@ malloc_init_hard(void)
* Zero the array. In practice, this should always be pre-zeroed,
* since it was just mmap()ed, but let's be sure.
*/
memset(arenas, 0, sizeof(arena_t *) * narenas);
memset(arenas, 0, sizeof(arena_t *) * narenas_total);
/* Copy the pointer to the one arena that was already initialized. */
arenas[0] = init_arenas[0];
@@ -1262,11 +1293,10 @@ je_valloc(size_t size)
* passed an extra argument for the caller return address, which will be
* ignored.
*/
JEMALLOC_EXPORT void (* const __free_hook)(void *ptr) = je_free;
JEMALLOC_EXPORT void *(* const __malloc_hook)(size_t size) = je_malloc;
JEMALLOC_EXPORT void *(* const __realloc_hook)(void *ptr, size_t size) =
je_realloc;
JEMALLOC_EXPORT void *(* const __memalign_hook)(size_t alignment, size_t size) =
JEMALLOC_EXPORT void (* __free_hook)(void *ptr) = je_free;
JEMALLOC_EXPORT void *(* __malloc_hook)(size_t size) = je_malloc;
JEMALLOC_EXPORT void *(* __realloc_hook)(void *ptr, size_t size) = je_realloc;
JEMALLOC_EXPORT void *(* __memalign_hook)(size_t alignment, size_t size) =
je_memalign;
#endif
@@ -1279,7 +1309,7 @@ JEMALLOC_EXPORT void *(* const __memalign_hook)(size_t alignment, size_t size) =
*/
size_t
je_malloc_usable_size(const void *ptr)
je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr)
{
size_t ret;
@@ -1343,18 +1373,19 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
#ifdef JEMALLOC_EXPERIMENTAL
JEMALLOC_INLINE void *
iallocm(size_t usize, size_t alignment, bool zero)
iallocm(size_t usize, size_t alignment, bool zero, bool try_tcache,
arena_t *arena)
{
assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize,
alignment)));
if (alignment != 0)
return (ipalloc(usize, alignment, zero));
return (ipallocx(usize, alignment, zero, try_tcache, arena));
else if (zero)
return (icalloc(usize));
return (icallocx(usize, try_tcache, arena));
else
return (imalloc(usize));
return (imallocx(usize, try_tcache, arena));
}
int
@@ -1365,6 +1396,9 @@ je_allocm(void **ptr, size_t *rsize, size_t size, int flags)
size_t alignment = (ZU(1) << (flags & ALLOCM_LG_ALIGN_MASK)
& (SIZE_T_MAX-1));
bool zero = flags & ALLOCM_ZERO;
unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
arena_t *arena;
bool try_tcache;
assert(ptr != NULL);
assert(size != 0);
@@ -1372,6 +1406,14 @@ je_allocm(void **ptr, size_t *rsize, size_t size, int flags)
if (malloc_init())
goto label_oom;
if (arena_ind != UINT_MAX) {
arena = arenas[arena_ind];
try_tcache = false;
} else {
arena = NULL;
try_tcache = true;
}
usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment);
if (usize == 0)
goto label_oom;
@@ -1388,18 +1430,19 @@ je_allocm(void **ptr, size_t *rsize, size_t size, int flags)
s2u(SMALL_MAXCLASS+1) : sa2u(SMALL_MAXCLASS+1,
alignment);
assert(usize_promoted != 0);
p = iallocm(usize_promoted, alignment, zero);
p = iallocm(usize_promoted, alignment, zero,
try_tcache, arena);
if (p == NULL)
goto label_oom;
arena_prof_promoted(p, usize);
} else {
p = iallocm(usize, alignment, zero);
p = iallocm(usize, alignment, zero, try_tcache, arena);
if (p == NULL)
goto label_oom;
}
prof_malloc(p, usize, cnt);
} else {
p = iallocm(usize, alignment, zero);
p = iallocm(usize, alignment, zero, try_tcache, arena);
if (p == NULL)
goto label_oom;
}
@@ -1436,6 +1479,9 @@ je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags)
& (SIZE_T_MAX-1));
bool zero = flags & ALLOCM_ZERO;
bool no_move = flags & ALLOCM_NO_MOVE;
unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
bool try_tcache_alloc, try_tcache_dalloc;
arena_t *arena;
assert(ptr != NULL);
assert(*ptr != NULL);
@@ -1443,6 +1489,19 @@ je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags)
assert(SIZE_T_MAX - size >= extra);
assert(malloc_initialized || IS_INITIALIZER);
if (arena_ind != UINT_MAX) {
arena_chunk_t *chunk;
try_tcache_alloc = true;
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(*ptr);
try_tcache_dalloc = (chunk == *ptr || chunk->arena !=
arenas[arena_ind]);
arena = arenas[arena_ind];
} else {
try_tcache_alloc = true;
try_tcache_dalloc = true;
arena = NULL;
}
p = *ptr;
if (config_prof && opt_prof) {
prof_thr_cnt_t *cnt;
@@ -1469,9 +1528,10 @@ je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags)
if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U
&& ((alignment == 0) ? s2u(size) : sa2u(size, alignment))
<= SMALL_MAXCLASS) {
q = iralloc(p, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >=
q = irallocx(p, SMALL_MAXCLASS+1, (SMALL_MAXCLASS+1 >=
size+extra) ? 0 : size+extra - (SMALL_MAXCLASS+1),
alignment, zero, no_move);
alignment, zero, no_move, try_tcache_alloc,
try_tcache_dalloc, arena);
if (q == NULL)
goto label_err;
if (max_usize < PAGE) {
@@ -1480,7 +1540,8 @@ je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags)
} else
usize = isalloc(q, config_prof);
} else {
q = iralloc(p, size, extra, alignment, zero, no_move);
q = irallocx(p, size, extra, alignment, zero, no_move,
try_tcache_alloc, try_tcache_dalloc, arena);
if (q == NULL)
goto label_err;
usize = isalloc(q, config_prof);
@@ -1497,7 +1558,8 @@ je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags)
old_size = isalloc(p, false);
old_rzsize = u2rz(old_size);
}
q = iralloc(p, size, extra, alignment, zero, no_move);
q = irallocx(p, size, extra, alignment, zero, no_move,
try_tcache_alloc, try_tcache_dalloc, arena);
if (q == NULL)
goto label_err;
if (config_stats)
@@ -1558,10 +1620,19 @@ je_dallocm(void *ptr, int flags)
{
size_t usize;
size_t rzsize JEMALLOC_CC_SILENCE_INIT(0);
unsigned arena_ind = ((unsigned)(flags >> 8)) - 1;
bool try_tcache;
assert(ptr != NULL);
assert(malloc_initialized || IS_INITIALIZER);
if (arena_ind != UINT_MAX) {
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
try_tcache = (chunk == ptr || chunk->arena !=
arenas[arena_ind]);
} else
try_tcache = true;
UTRACE(ptr, 0, 0);
if (config_stats || config_valgrind)
usize = isalloc(ptr, config_prof);
@@ -1574,7 +1645,7 @@ je_dallocm(void *ptr, int flags)
thread_allocated_tsd_get()->deallocated += usize;
if (config_valgrind && opt_valgrind)
rzsize = p2rz(ptr);
iqalloc(ptr);
iqallocx(ptr, try_tcache);
JEMALLOC_VALGRIND_FREE(ptr, rzsize);
return (ALLOCM_SUCCESS);
@@ -1611,6 +1682,27 @@ je_nallocm(size_t *rsize, size_t size, int flags)
* malloc during fork().
*/
/*
* If an application creates a thread before doing any allocation in the main
* thread, then calls fork(2) in the main thread followed by memory allocation
* in the child process, a race can occur that results in deadlock within the
* child: the main thread may have forked while the created thread had
* partially initialized the allocator. Ordinarily jemalloc prevents
* fork/malloc races via the following functions it registers during
* initialization using pthread_atfork(), but of course that does no good if
* the allocator isn't fully initialized at fork time. The following library
* constructor is a partial solution to this problem. It may still possible to
* trigger the deadlock described above, but doing so would involve forking via
* a library constructor that runs before jemalloc's runs.
*/
JEMALLOC_ATTR(constructor)
static void
jemalloc_constructor(void)
{
malloc_init();
}
#ifndef JEMALLOC_MUTEX_INIT_CB
void
jemalloc_prefork(void)
@@ -1628,14 +1720,16 @@ _malloc_prefork(void)
assert(malloc_initialized);
/* Acquire all mutexes in a safe order. */
ctl_prefork();
malloc_mutex_prefork(&arenas_lock);
for (i = 0; i < narenas; i++) {
for (i = 0; i < narenas_total; i++) {
if (arenas[i] != NULL)
arena_prefork(arenas[i]);
}
prof_prefork();
chunk_prefork();
base_prefork();
huge_prefork();
chunk_dss_prefork();
}
#ifndef JEMALLOC_MUTEX_INIT_CB
@@ -1655,14 +1749,16 @@ _malloc_postfork(void)
assert(malloc_initialized);
/* Release all mutexes, now that fork() has completed. */
chunk_dss_postfork_parent();
huge_postfork_parent();
base_postfork_parent();
for (i = 0; i < narenas; i++) {
chunk_postfork_parent();
prof_postfork_parent();
for (i = 0; i < narenas_total; i++) {
if (arenas[i] != NULL)
arena_postfork_parent(arenas[i]);
}
malloc_mutex_postfork_parent(&arenas_lock);
ctl_postfork_parent();
}
void
@@ -1673,14 +1769,16 @@ jemalloc_postfork_child(void)
assert(malloc_initialized);
/* Release all mutexes, now that fork() has completed. */
chunk_dss_postfork_child();
huge_postfork_child();
base_postfork_child();
for (i = 0; i < narenas; i++) {
chunk_postfork_child();
prof_postfork_child();
for (i = 0; i < narenas_total; i++) {
if (arenas[i] != NULL)
arena_postfork_child(arenas[i]);
}
malloc_mutex_postfork_child(&arenas_lock);
ctl_postfork_child();
}
/******************************************************************************/
+1 -1
View File
@@ -64,7 +64,7 @@ pthread_create(pthread_t *__restrict thread,
/******************************************************************************/
#ifdef JEMALLOC_MUTEX_INIT_CB
int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex,
JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex,
void *(calloc_cb)(size_t, size_t));
#endif
+42
View File
@@ -1270,4 +1270,46 @@ prof_boot2(void)
return (false);
}
void
prof_prefork(void)
{
if (opt_prof) {
unsigned i;
malloc_mutex_lock(&bt2ctx_mtx);
malloc_mutex_lock(&prof_dump_seq_mtx);
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_lock(&ctx_locks[i]);
}
}
void
prof_postfork_parent(void)
{
if (opt_prof) {
unsigned i;
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_postfork_parent(&ctx_locks[i]);
malloc_mutex_postfork_parent(&prof_dump_seq_mtx);
malloc_mutex_postfork_parent(&bt2ctx_mtx);
}
}
void
prof_postfork_child(void)
{
if (opt_prof) {
unsigned i;
for (i = 0; i < PROF_NCTX_LOCKS; i++)
malloc_mutex_postfork_child(&ctx_locks[i]);
malloc_mutex_postfork_child(&prof_dump_seq_mtx);
malloc_mutex_postfork_child(&bt2ctx_mtx);
}
}
/******************************************************************************/
+21
View File
@@ -44,3 +44,24 @@ rtree_new(unsigned bits)
return (ret);
}
void
rtree_prefork(rtree_t *rtree)
{
malloc_mutex_prefork(&rtree->mutex);
}
void
rtree_postfork_parent(rtree_t *rtree)
{
malloc_mutex_postfork_parent(&rtree->mutex);
}
void
rtree_postfork_child(rtree_t *rtree)
{
malloc_mutex_postfork_child(&rtree->mutex);
}
+8 -2
View File
@@ -206,6 +206,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
unsigned i, bool bins, bool large)
{
unsigned nthreads;
const char *dss;
size_t page, pactive, pdirty, mapped;
uint64_t npurge, nmadvise, purged;
size_t small_allocated;
@@ -218,6 +219,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
CTL_I_GET("stats.arenas.0.nthreads", &nthreads, unsigned);
malloc_cprintf(write_cb, cbopaque,
"assigned threads: %u\n", nthreads);
CTL_I_GET("stats.arenas.0.dss", &dss, const char *);
malloc_cprintf(write_cb, cbopaque, "dss allocation precedence: %s\n",
dss);
CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
@@ -370,6 +374,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
"Run-time option settings:\n");
OPT_WRITE_BOOL(abort)
OPT_WRITE_SIZE_T(lg_chunk)
OPT_WRITE_CHAR_P(dss)
OPT_WRITE_SIZE_T(narenas)
OPT_WRITE_SSIZE_T(lg_dirty_mult)
OPT_WRITE_BOOL(stats_print)
@@ -400,7 +405,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
malloc_cprintf(write_cb, cbopaque, "CPUs: %u\n", ncpus);
CTL_GET("arenas.narenas", &uv, unsigned);
malloc_cprintf(write_cb, cbopaque, "Max arenas: %u\n", uv);
malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n", uv);
malloc_cprintf(write_cb, cbopaque, "Pointer size: %zu\n",
sizeof(void *));
@@ -472,7 +477,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
CTL_GET("stats.chunks.current", &chunks_current, size_t);
malloc_cprintf(write_cb, cbopaque, "chunks: nchunks "
"highchunks curchunks\n");
malloc_cprintf(write_cb, cbopaque, " %13"PRIu64"%13zu%13zu\n",
malloc_cprintf(write_cb, cbopaque,
" %13"PRIu64" %12zu %12zu\n",
chunks_total, chunks_high, chunks_current);
/* Print huge stats. */
+2 -2
View File
@@ -288,7 +288,7 @@ tcache_create(arena_t *arena)
else if (size <= tcache_maxclass)
tcache = (tcache_t *)arena_malloc_large(arena, size, true);
else
tcache = (tcache_t *)icalloc(size);
tcache = (tcache_t *)icallocx(size, false, arena);
if (tcache == NULL)
return (NULL);
@@ -364,7 +364,7 @@ tcache_destroy(tcache_t *tcache)
arena_dalloc_large(arena, chunk, tcache);
} else
idalloc(tcache);
idallocx(tcache, false);
}
void
-5
View File
@@ -377,7 +377,6 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
case '\0': goto label_out;
case '%': {
bool alt_form = false;
bool zero_pad = false;
bool left_justify = false;
bool plus_space = false;
bool plus_plus = false;
@@ -398,10 +397,6 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap)
assert(alt_form == false);
alt_form = true;
break;
case '0':
assert(zero_pad == false);
zero_pad = true;
break;
case '-':
assert(left_justify == false);
left_justify = true;
+11 -1
View File
@@ -171,6 +171,16 @@ void
register_zone(void)
{
/*
* If something else replaced the system default zone allocator, don't
* register jemalloc's.
*/
malloc_zone_t *default_zone = malloc_default_zone();
if (!default_zone->zone_name ||
strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) {
return;
}
zone.size = (void *)zone_size;
zone.malloc = (void *)zone_malloc;
zone.calloc = (void *)zone_calloc;
@@ -241,7 +251,7 @@ register_zone(void)
* then becomes the default.
*/
do {
malloc_zone_t *default_zone = malloc_default_zone();
default_zone = malloc_default_zone();
malloc_zone_unregister(default_zone);
malloc_zone_register(default_zone);
} while (malloc_default_zone() != &zone);
+66
View File
@@ -0,0 +1,66 @@
#define JEMALLOC_MANGLE
#include "jemalloc_test.h"
#define NTHREADS 10
void *
je_thread_start(void *arg)
{
unsigned thread_ind = (unsigned)(uintptr_t)arg;
unsigned arena_ind;
int r;
void *p;
size_t rsz, sz;
sz = sizeof(arena_ind);
if (mallctl("arenas.extend", &arena_ind, &sz, NULL, 0)
!= 0) {
malloc_printf("Error in arenas.extend\n");
abort();
}
if (thread_ind % 4 != 3) {
size_t mib[3];
size_t miblen = sizeof(mib) / sizeof(size_t);
const char *dss_precs[] = {"disabled", "primary", "secondary"};
const char *dss = dss_precs[thread_ind % 4];
if (mallctlnametomib("arena.0.dss", mib, &miblen) != 0) {
malloc_printf("Error in mallctlnametomib()\n");
abort();
}
mib[1] = arena_ind;
if (mallctlbymib(mib, miblen, NULL, NULL, (void *)&dss,
sizeof(const char *))) {
malloc_printf("Error in mallctlbymib()\n");
abort();
}
}
r = allocm(&p, &rsz, 1, ALLOCM_ARENA(arena_ind));
if (r != ALLOCM_SUCCESS) {
malloc_printf("Unexpected allocm() error\n");
abort();
}
return (NULL);
}
int
main(void)
{
je_thread_t threads[NTHREADS];
unsigned i;
malloc_printf("Test begin\n");
for (i = 0; i < NTHREADS; i++) {
je_thread_create(&threads[i], je_thread_start,
(void *)(uintptr_t)i);
}
for (i = 0; i < NTHREADS; i++)
je_thread_join(threads[i], NULL);
malloc_printf("Test end\n");
return (0);
}
+2
View File
@@ -0,0 +1,2 @@
Test begin
Test end
+5 -3
View File
@@ -1,7 +1,7 @@
#define JEMALLOC_MANGLE
#include "jemalloc_test.h"
#define NTHREADS 10
#define NTHREADS 10
void *
je_thread_start(void *arg)
@@ -66,8 +66,10 @@ main(void)
goto label_return;
}
for (i = 0; i < NTHREADS; i++)
je_thread_create(&threads[i], je_thread_start, (void *)&arena_ind);
for (i = 0; i < NTHREADS; i++) {
je_thread_create(&threads[i], je_thread_start,
(void *)&arena_ind);
}
for (i = 0; i < NTHREADS; i++)
je_thread_join(threads[i], (void *)&ret);
+37 -20
View File
@@ -8,34 +8,37 @@
* Does a number of crazy assumptions that happen to be true in 99.9999% of
* the 2010 UNIX computers around.
*
* ------------------------------------------------------------------------
*
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis 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:
* 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 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
* * 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.
*
* 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
* HOLDER 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.
*
* ------------------------------------------------------------------------
*
* References:
* - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
@@ -290,6 +293,8 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
size_t len = 0;
size_t cols = getColumns();
int history_index = 0;
size_t old_pos;
size_t diff;
buf[0] = '\0';
buflen--; /* Make sure there is always space for the nulterm */
@@ -465,6 +470,18 @@ up_down_arrow:
case 12: /* ctrl+l, clear screen */
linenoiseClearScreen();
refreshLine(fd,prompt,buf,len,pos,cols);
break;
case 23: /* ctrl+w, delete previous word */
old_pos = pos;
while (pos > 0 && buf[pos-1] == ' ')
pos--;
while (pos > 0 && buf[pos-1] != ' ')
pos--;
diff = old_pos - pos;
memmove(&buf[pos], &buf[old_pos], len-old_pos+1);
len -= diff;
refreshLine(fd,prompt,buf,len,pos,cols);
break;
}
}
return len;
+1 -1
View File
@@ -9,7 +9,7 @@ For details and rationale, see http://www.lua.org/license.html .
===============================================================================
Copyright (C) 1994-2008 Lua.org, PUC-Rio.
Copyright (C) 1994-2012 Lua.org, PUC-Rio.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+1 -1
View File
@@ -48,7 +48,7 @@ TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.1
R= 5.1.4
R= 5.1.5
all: $(PLAT)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 B

+79 -81
View File
@@ -3,11 +3,10 @@
<HEAD>
<TITLE>Lua 5.1 Reference Manual - contents</TITLE>
<LINK REL="stylesheet" TYPE="text/css" HREF="lua.css">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=iso-8859-1">
<META HTTP-EQUIV="content-type" CONTENT="text/html; charset=utf-8">
<STYLE TYPE="text/css">
ul {
list-style-type: none ;
list-style-position: outside ;
}
</STYLE>
</HEAD>
@@ -20,7 +19,13 @@ ul {
Lua 5.1 Reference Manual
</H1>
This is an online version of
<P>
The reference manual is the official definition of the Lua language.
For a complete introduction to Lua programming, see the book
<A HREF="http://www.lua.org/docs.html#pil">Programming in Lua</A>.
<P>
This manual is also available as a book:
<BLOCKQUOTE>
<A HREF="http://www.amazon.com/exec/obidos/ASIN/8590379833/lua-indexmanual-20">
<IMG SRC="cover.png" ALT="" TITLE="buy from Amazon" BORDER=1 ALIGN="left" HSPACE=12>
@@ -29,128 +34,119 @@ This is an online version of
<BR>by R. Ierusalimschy, L. H. de Figueiredo, W. Celes
<BR>Lua.org, August 2006
<BR>ISBN 85-903798-3-3
<BR><A HREF="http://www.amazon.com/exec/obidos/ASIN/8590379833/lua-indexmanual-20">
<IMG SRC="amazon.gif" ALT="[Buy from Amazon]" BORDER=0></A>
<BR CLEAR="all">
</BLOCKQUOTE>
<P>
Buy a copy of this book and
<P>
<A HREF="http://www.amazon.com/exec/obidos/ASIN/8590379833/lua-indexmanual-20">Buy a copy</A>
of this book and
<A HREF="http://www.lua.org/donations.html">help to support</A>
the Lua project.
<P>
The reference manual is the official definition of the Lua language.
For a complete introduction to Lua programming, see the book
<A HREF="http://www.lua.org/docs.html#books">Programming in Lua</A>.
<P>
<A HREF="manual.html">start</A>
&middot;
<A HREF="#contents">contents</A>
&middot;
<A HREF="#index">index</A>
&middot;
<A HREF="http://www.lua.org/manual/5.1/pt/">português</A>
&middot;
<A HREF="http://www.lua.org/manual/5.1/es/">español</A>
<A HREF="http://www.lua.org/manual/">other versions</A>
<HR>
<SMALL>
Copyright &copy; 2006-2008 Lua.org, PUC-Rio.
Copyright &copy; 2006&ndash;2012 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html#5">Lua license</a>.
<A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL>
<P>
<H2><A NAME="contents">Contents</A></H2>
<UL style="padding: 0">
<LI><A HREF="manual.html">1 - Introduction</A>
<LI><A HREF="manual.html">1 &ndash; Introduction</A>
<P>
<LI><A HREF="manual.html#2">2 - The Language</A>
<LI><A HREF="manual.html#2">2 &ndash; The Language</A>
<UL>
<LI><A HREF="manual.html#2.1">2.1 - Lexical Conventions</A>
<LI><A HREF="manual.html#2.2">2.2 - Values and Types</A>
<LI><A HREF="manual.html#2.1">2.1 &ndash; Lexical Conventions</A>
<LI><A HREF="manual.html#2.2">2.2 &ndash; Values and Types</A>
<UL>
<LI><A HREF="manual.html#2.2.1">2.2.1 - Coercion</A>
<LI><A HREF="manual.html#2.2.1">2.2.1 &ndash; Coercion</A>
</UL>
<LI><A HREF="manual.html#2.3">2.3 - Variables</A>
<LI><A HREF="manual.html#2.4">2.4 - Statements</A>
<LI><A HREF="manual.html#2.3">2.3 &ndash; Variables</A>
<LI><A HREF="manual.html#2.4">2.4 &ndash; Statements</A>
<UL>
<LI><A HREF="manual.html#2.4.1">2.4.1 - Chunks</A>
<LI><A HREF="manual.html#2.4.2">2.4.2 - Blocks</A>
<LI><A HREF="manual.html#2.4.3">2.4.3 - Assignment</A>
<LI><A HREF="manual.html#2.4.4">2.4.4 - Control Structures</A>
<LI><A HREF="manual.html#2.4.5">2.4.5 - For Statement</A>
<LI><A HREF="manual.html#2.4.6">2.4.6 - Function Calls as Statements</A>
<LI><A HREF="manual.html#2.4.7">2.4.7 - Local Declarations</A>
<LI><A HREF="manual.html#2.4.1">2.4.1 &ndash; Chunks</A>
<LI><A HREF="manual.html#2.4.2">2.4.2 &ndash; Blocks</A>
<LI><A HREF="manual.html#2.4.3">2.4.3 &ndash; Assignment</A>
<LI><A HREF="manual.html#2.4.4">2.4.4 &ndash; Control Structures</A>
<LI><A HREF="manual.html#2.4.5">2.4.5 &ndash; For Statement</A>
<LI><A HREF="manual.html#2.4.6">2.4.6 &ndash; Function Calls as Statements</A>
<LI><A HREF="manual.html#2.4.7">2.4.7 &ndash; Local Declarations</A>
</UL>
<LI><A HREF="manual.html#2.5">2.5 - Expressions</A>
<LI><A HREF="manual.html#2.5">2.5 &ndash; Expressions</A>
<UL>
<LI><A HREF="manual.html#2.5.1">2.5.1 - Arithmetic Operators</A>
<LI><A HREF="manual.html#2.5.2">2.5.2 - Relational Operators</A>
<LI><A HREF="manual.html#2.5.3">2.5.3 - Logical Operators</A>
<LI><A HREF="manual.html#2.5.4">2.5.4 - Concatenation</A>
<LI><A HREF="manual.html#2.5.5">2.5.5 - The Length Operator</A>
<LI><A HREF="manual.html#2.5.6">2.5.6 - Precedence</A>
<LI><A HREF="manual.html#2.5.7">2.5.7 - Table Constructors</A>
<LI><A HREF="manual.html#2.5.8">2.5.8 - Function Calls</A>
<LI><A HREF="manual.html#2.5.9">2.5.9 - Function Definitions</A>
<LI><A HREF="manual.html#2.5.1">2.5.1 &ndash; Arithmetic Operators</A>
<LI><A HREF="manual.html#2.5.2">2.5.2 &ndash; Relational Operators</A>
<LI><A HREF="manual.html#2.5.3">2.5.3 &ndash; Logical Operators</A>
<LI><A HREF="manual.html#2.5.4">2.5.4 &ndash; Concatenation</A>
<LI><A HREF="manual.html#2.5.5">2.5.5 &ndash; The Length Operator</A>
<LI><A HREF="manual.html#2.5.6">2.5.6 &ndash; Precedence</A>
<LI><A HREF="manual.html#2.5.7">2.5.7 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#2.5.8">2.5.8 &ndash; Function Calls</A>
<LI><A HREF="manual.html#2.5.9">2.5.9 &ndash; Function Definitions</A>
</UL>
<LI><A HREF="manual.html#2.6">2.6 - Visibility Rules</A>
<LI><A HREF="manual.html#2.7">2.7 - Error Handling</A>
<LI><A HREF="manual.html#2.8">2.8 - Metatables</A>
<LI><A HREF="manual.html#2.9">2.9 - Environments</A>
<LI><A HREF="manual.html#2.10">2.10 - Garbage Collection</A>
<LI><A HREF="manual.html#2.6">2.6 &ndash; Visibility Rules</A>
<LI><A HREF="manual.html#2.7">2.7 &ndash; Error Handling</A>
<LI><A HREF="manual.html#2.8">2.8 &ndash; Metatables</A>
<LI><A HREF="manual.html#2.9">2.9 &ndash; Environments</A>
<LI><A HREF="manual.html#2.10">2.10 &ndash; Garbage Collection</A>
<UL>
<LI><A HREF="manual.html#2.10.1">2.10.1 - Garbage-Collection Metamethods</A>
<LI><A HREF="manual.html#2.10.2">2.10.2 - Weak Tables</A>
<LI><A HREF="manual.html#2.10.1">2.10.1 &ndash; Garbage-Collection Metamethods</A>
<LI><A HREF="manual.html#2.10.2">2.10.2 &ndash; Weak Tables</A>
</UL>
<LI><A HREF="manual.html#2.11">2.11 - Coroutines</A>
<LI><A HREF="manual.html#2.11">2.11 &ndash; Coroutines</A>
</UL>
<P>
<LI><A HREF="manual.html#3">3 - The Application Program Interface</A>
<LI><A HREF="manual.html#3">3 &ndash; The Application Program Interface</A>
<UL>
<LI><A HREF="manual.html#3.1">3.1 - The Stack</A>
<LI><A HREF="manual.html#3.2">3.2 - Stack Size</A>
<LI><A HREF="manual.html#3.3">3.3 - Pseudo-Indices</A>
<LI><A HREF="manual.html#3.4">3.4 - C Closures</A>
<LI><A HREF="manual.html#3.5">3.5 - Registry</A>
<LI><A HREF="manual.html#3.6">3.6 - Error Handling in C</A>
<LI><A HREF="manual.html#3.7">3.7 - Functions and Types</A>
<LI><A HREF="manual.html#3.8">3.8 - The Debug Interface</A>
<LI><A HREF="manual.html#3.1">3.1 &ndash; The Stack</A>
<LI><A HREF="manual.html#3.2">3.2 &ndash; Stack Size</A>
<LI><A HREF="manual.html#3.3">3.3 &ndash; Pseudo-Indices</A>
<LI><A HREF="manual.html#3.4">3.4 &ndash; C Closures</A>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Registry</A>
<LI><A HREF="manual.html#3.6">3.6 &ndash; Error Handling in C</A>
<LI><A HREF="manual.html#3.7">3.7 &ndash; Functions and Types</A>
<LI><A HREF="manual.html#3.8">3.8 &ndash; The Debug Interface</A>
</UL>
<P>
<LI><A HREF="manual.html#4">4 - The Auxiliary Library</A>
<LI><A HREF="manual.html#4">4 &ndash; The Auxiliary Library</A>
<UL>
<LI><A HREF="manual.html#4.1">4.1 - Functions and Types</A>
<LI><A HREF="manual.html#4.1">4.1 &ndash; Functions and Types</A>
</UL>
<P>
<LI><A HREF="manual.html#5">5 - Standard Libraries</A>
<LI><A HREF="manual.html#5">5 &ndash; Standard Libraries</A>
<UL>
<LI><A HREF="manual.html#5.1">5.1 - Basic Functions</A>
<LI><A HREF="manual.html#5.2">5.2 - Coroutine Manipulation</A>
<LI><A HREF="manual.html#5.3">5.3 - Modules</A>
<LI><A HREF="manual.html#5.4">5.4 - String Manipulation</A>
<LI><A HREF="manual.html#5.1">5.1 &ndash; Basic Functions</A>
<LI><A HREF="manual.html#5.2">5.2 &ndash; Coroutine Manipulation</A>
<LI><A HREF="manual.html#5.3">5.3 &ndash; Modules</A>
<LI><A HREF="manual.html#5.4">5.4 &ndash; String Manipulation</A>
<UL>
<LI><A HREF="manual.html#5.4.1">5.4.1 - Patterns</A>
<LI><A HREF="manual.html#5.4.1">5.4.1 &ndash; Patterns</A>
</UL>
<LI><A HREF="manual.html#5.5">5.5 - Table Manipulation</A>
<LI><A HREF="manual.html#5.6">5.6 - Mathematical Functions</A>
<LI><A HREF="manual.html#5.7">5.7 - Input and Output Facilities</A>
<LI><A HREF="manual.html#5.8">5.8 - Operating System Facilities</A>
<LI><A HREF="manual.html#5.9">5.9 - The Debug Library</A>
<LI><A HREF="manual.html#5.5">5.5 &ndash; Table Manipulation</A>
<LI><A HREF="manual.html#5.6">5.6 &ndash; Mathematical Functions</A>
<LI><A HREF="manual.html#5.7">5.7 &ndash; Input and Output Facilities</A>
<LI><A HREF="manual.html#5.8">5.8 &ndash; Operating System Facilities</A>
<LI><A HREF="manual.html#5.9">5.9 &ndash; The Debug Library</A>
</UL>
<P>
<LI><A HREF="manual.html#6">6 - Lua Stand-alone</A>
<LI><A HREF="manual.html#6">6 &ndash; Lua Stand-alone</A>
<P>
<LI><A HREF="manual.html#7">7 - Incompatibilities with the Previous Version</A>
<LI><A HREF="manual.html#7">7 &ndash; Incompatibilities with the Previous Version</A>
<UL>
<LI><A HREF="manual.html#7.1">7.1 - Changes in the Language</A>
<LI><A HREF="manual.html#7.2">7.2 - Changes in the Libraries</A>
<LI><A HREF="manual.html#7.3">7.3 - Changes in the API</A>
<LI><A HREF="manual.html#7.1">7.1 &ndash; Changes in the Language</A>
<LI><A HREF="manual.html#7.2">7.2 &ndash; Changes in the Libraries</A>
<LI><A HREF="manual.html#7.3">7.3 &ndash; Changes in the API</A>
</UL>
<P>
<LI><A HREF="manual.html#8">8 - The Complete Syntax of Lua</A>
<LI><A HREF="manual.html#8">8 &ndash; The Complete Syntax of Lua</A>
</UL>
<H2><A NAME="index">Index</A></H2>
@@ -160,6 +156,8 @@ Freely available under the terms of the
<H3><A NAME="functions">Lua functions</A></H3>
<A HREF="manual.html#pdf-_G">_G</A><BR>
<A HREF="manual.html#pdf-_VERSION">_VERSION</A><BR>
<P>
<A HREF="manual.html#pdf-assert">assert</A><BR>
<A HREF="manual.html#pdf-collectgarbage">collectgarbage</A><BR>
<A HREF="manual.html#pdf-dofile">dofile</A><BR>
@@ -487,12 +485,12 @@ Freely available under the terms of the
<P>
<HR>
<SMALL>
<SMALL CLASS="footer">
Last update:
Sat Jan 19 13:24:29 BRST 2008
Mon Feb 13 18:53:32 BRST 2012
</SMALL>
<!--
Last change: revised for Lua 5.1.3
Last change: revised for Lua 5.1.5
-->
</BODY>
+45 -3
View File
@@ -1,17 +1,37 @@
body {
color: #000000 ;
background-color: #FFFFFF ;
font-family: sans-serif ;
font-family: Helvetica, Arial, sans-serif ;
text-align: justify ;
margin-right: 20px ;
margin-left: 20px ;
margin-right: 30px ;
margin-left: 30px ;
}
h1, h2, h3, h4 {
font-family: Verdana, Geneva, sans-serif ;
font-weight: normal ;
font-style: italic ;
}
h2 {
padding-top: 0.4em ;
padding-bottom: 0.4em ;
padding-left: 30px ;
padding-right: 30px ;
margin-left: -30px ;
background-color: #E0E0FF ;
}
h3 {
padding-left: 0.5em ;
border-left: solid #E0E0FF 1em ;
}
table h3 {
padding-left: 0px ;
border-left: none ;
}
a:link {
color: #000080 ;
background-color: inherit ;
@@ -39,3 +59,25 @@ hr {
background-color: #a0a0a0 ;
}
:target {
background-color: #F8F8F8 ;
padding: 8px ;
border: solid #a0a0a0 2px ;
}
.footer {
color: gray ;
font-size: small ;
}
input[type=text] {
border: solid #a0a0a0 2px ;
border-radius: 2em ;
-moz-border-radius: 2em ;
background-image: url('images/search.png') ;
background-repeat: no-repeat;
background-position: 4px center ;
padding-left: 20px ;
height: 2em ;
}
+13 -2
View File
@@ -1,13 +1,24 @@
h3 code {
font-family: inherit ;
font-size: inherit ;
}
pre {
font-size: 105% ;
pre, code {
font-size: 12pt ;
}
span.apii {
float: right ;
font-family: inherit ;
font-style: normal ;
font-size: small ;
color: gray ;
}
p+h1, ul+h1 {
padding-top: 0.4em ;
padding-bottom: 0.4em ;
padding-left: 30px ;
margin-left: -30px ;
background-color: #E0E0FF ;
}
+17 -14
View File
@@ -19,9 +19,9 @@ Lua 5.1 Reference Manual
by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<p>
<small>
Copyright &copy; 2006-2008 Lua.org, PUC-Rio.
Copyright &copy; 2006&ndash;2012 Lua.org, PUC-Rio.
Freely available under the terms of the
<a href="http://www.lua.org/license.html#5">Lua license</a>.
<a href="http://www.lua.org/license.html">Lua license</a>.
</small>
<hr>
<p>
@@ -29,11 +29,13 @@ Freely available under the terms of the
<a href="contents.html#contents">contents</A>
&middot;
<a href="contents.html#index">index</A>
&middot;
<A HREF="http://www.lua.org/manual/">other versions</A>
<!-- ====================================================================== -->
<p>
<!-- $Id: manual.of,v 1.48 2008/08/18 15:24:20 roberto Exp $ -->
<!-- $Id: manual.of,v 1.49.1.2 2012/01/13 20:23:26 roberto Exp $ -->
@@ -5645,7 +5647,7 @@ Currently, Lua has the following standard libraries:
<ul>
<li>basic library,</li> which includes the coroutine sub-library;
<li>basic library, which includes the coroutine sub-library;</li>
<li>package library;</li>
@@ -5709,7 +5711,7 @@ when absent, it defaults to "assertion failed!"
<p>
<hr><h3><a name="pdf-collectgarbage"><code>collectgarbage (opt [, arg])</code></a></h3>
<hr><h3><a name="pdf-collectgarbage"><code>collectgarbage ([opt [, arg]])</code></a></h3>
<p>
@@ -5718,6 +5720,11 @@ It performs different functions according to its first argument, <code>opt</code
<ul>
<li><b>"collect":</b>
performs a full garbage-collection cycle.
This is the default option.
</li>
<li><b>"stop":</b>
stops the garbage collector.
</li>
@@ -5726,10 +5733,6 @@ stops the garbage collector.
restarts the garbage collector.
</li>
<li><b>"collect":</b>
performs a full garbage-collection cycle.
</li>
<li><b>"count":</b>
returns the total memory in use by Lua (in Kbytes).
</li>
@@ -5760,7 +5763,7 @@ Returns the previous value for <em>step</em>.
<p>
<hr><h3><a name="pdf-dofile"><code>dofile (filename)</code></a></h3>
<hr><h3><a name="pdf-dofile"><code>dofile ([filename])</code></a></h3>
Opens the named file and executes its contents as a Lua chunk.
When called without arguments,
<code>dofile</code> executes the contents of the standard input (<code>stdin</code>).
@@ -8421,7 +8424,7 @@ Otherwise, it returns the name of the upvalue.
<p>
<hr><h3><a name="pdf-debug.traceback"><code>debug.traceback ([thread,] [message] [, level])</code></a></h3>
<hr><h3><a name="pdf-debug.traceback"><code>debug.traceback ([thread,] [message [, level]])</code></a></h3>
<p>
@@ -8789,12 +8792,12 @@ Here is the complete syntax of Lua in extended BNF.
<HR>
<SMALL>
<SMALL CLASS="footer">
Last update:
Mon Aug 18 13:25:46 BRT 2008
Mon Feb 13 18:54:19 BRST 2012
</SMALL>
<!--
Last change: revised for Lua 5.1.4
Last change: revised for Lua 5.1.5
-->
</body></html>
+2 -2
View File
@@ -12,7 +12,7 @@
Documentation
</H1>
This is the documentation included in the source distribution of Lua 5.1.4.
This is the documentation included in the source distribution of Lua 5.1.5.
<UL>
<LI><A HREF="contents.html">Reference manual</A>
@@ -33,7 +33,7 @@ especially the
<HR>
<SMALL>
Last update:
Tue Aug 12 14:46:07 BRT 2008
Fri Feb 3 09:44:42 BRST 2012
</SMALL>
</BODY>
+1 -1
View File
@@ -5,7 +5,7 @@
# grep '^V=' ../Makefile
V= 5.1
# grep '^R=' ../Makefile
R= 5.1.4
R= 5.1.5
# grep '^INSTALL_.*=' ../Makefile | sed 's/INSTALL_TOP/prefix/'
prefix= /usr/local
+2 -2
View File
@@ -7,7 +7,7 @@
# Your platform. See PLATS for possible values.
PLAT= none
CC= gcc
CC?= gcc
CFLAGS= -O2 -Wall $(MYCFLAGS)
AR= ar rcu
RANLIB= ranlib
@@ -48,7 +48,7 @@ o: $(ALL_O)
a: $(ALL_A)
$(LUA_A): $(CORE_O) $(LIB_O)
$(AR) $@ $?
$(AR) $@ $(CORE_O) $(LIB_O) # DLL needs all object files
$(RANLIB) $@
$(LUA_T): $(LUA_O) $(LUA_A)
+1 -1
View File
@@ -631,7 +631,7 @@ static void base_open (lua_State *L) {
luaL_register(L, "_G", base_funcs);
lua_pushliteral(L, LUA_VERSION);
lua_setglobal(L, "_VERSION"); /* set global _VERSION */
/* `ipairs' and `pairs' need auxliliary functions as upvalues */
/* `ipairs' and `pairs' need auxiliary functions as upvalues */
auxopen(L, "ipairs", luaB_ipairs, ipairsaux);
auxopen(L, "pairs", luaB_pairs, luaB_next);
/* `newproxy' needs a weaktable as upvalue */
+1 -9
View File
@@ -1,5 +1,5 @@
/*
** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $
** $Id: lcode.c,v 2.25.1.5 2011/01/31 14:53:16 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -544,10 +544,6 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
pc = NO_JUMP; /* always true; do nothing */
break;
}
case VFALSE: {
pc = luaK_jump(fs); /* always jump */
break;
}
case VJMP: {
invertjump(fs, e);
pc = e->u.s.info;
@@ -572,10 +568,6 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) {
pc = NO_JUMP; /* always false; do nothing */
break;
}
case VTRUE: {
pc = luaK_jump(fs); /* always jump */
break;
}
case VJMP: {
pc = e->u.s.info;
break;
+2 -1
View File
@@ -1,5 +1,5 @@
/*
** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $
** $Id: ldblib.c,v 1.104.1.4 2009/08/04 18:50:18 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -45,6 +45,7 @@ static int db_setmetatable (lua_State *L) {
static int db_getfenv (lua_State *L) {
luaL_checkany(L, 1);
lua_getfenv(L, 1);
return 1;
}
+2 -1
View File
@@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $
** $Id: ldo.c,v 2.38.1.4 2012/01/18 02:27:10 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -217,6 +217,7 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int nvar = actual - nfixargs; /* number of extra arguments */
lua_assert(p->is_vararg & VARARG_HASARG);
luaC_checkGC(L);
luaD_checkstack(L, p->maxstacksize);
htab = luaH_new(L, nvar, 1); /* create `arg' table */
for (i=0; i<nvar; i++) /* put extra arguments into `arg' table */
setobj2n(L, luaH_setnum(L, htab, i+1), L->top - nvar + i);
+1 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.38.1.1 2007/12/27 13:02:25 roberto Exp $
** $Id: lgc.c,v 2.38.1.2 2011/03/18 18:05:38 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -627,7 +627,6 @@ void luaC_step (lua_State *L) {
}
}
else {
lua_assert(g->totalbytes >= g->estimate);
setthreshold(g);
}
}
+5 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.73.1.3 2008/01/18 17:47:43 roberto Exp $
** $Id: liolib.c,v 2.73.1.4 2010/05/14 15:33:51 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -276,7 +276,10 @@ static int read_number (lua_State *L, FILE *f) {
lua_pushnumber(L, d);
return 1;
}
else return 0; /* read fails */
else {
lua_pushnil(L); /* "result" to be removed */
return 0; /* read fails */
}
}
+4 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: llex.c,v 2.20.1.1 2007/12/27 13:02:25 roberto Exp $
** $Id: llex.c,v 2.20.1.2 2009/11/23 14:58:22 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -118,8 +118,10 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
TString *ts = luaS_newlstr(L, str, l);
TValue *o = luaH_setstr(L, ls->fs->h, ts); /* entry for `str' */
if (ttisnil(o))
if (ttisnil(o)) {
setbvalue(o, 1); /* make sure `str' will not be collected */
luaC_checkGC(L);
}
return ts;
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $
** $Id: loadlib.c,v 1.52.1.4 2009/09/09 13:17:16 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -639,7 +639,7 @@ LUALIB_API int luaopen_package (lua_State *L) {
lua_pushvalue(L, -1);
lua_replace(L, LUA_ENVIRONINDEX);
/* create `loaders' table */
lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1);
lua_createtable(L, sizeof(loaders)/sizeof(loaders[0]) - 1, 0);
/* fill it with pre-defined loaders */
for (i=0; loaders[i] != NULL; i++) {
lua_pushcfunction(L, loaders[i]);
+2 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: lparser.c,v 2.42.1.3 2007/12/28 15:32:23 roberto Exp $
** $Id: lparser.c,v 2.42.1.4 2011/10/21 19:31:42 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -374,9 +374,9 @@ static void close_func (LexState *ls) {
lua_assert(luaG_checkcode(f));
lua_assert(fs->bl == NULL);
ls->fs = fs->prev;
L->top -= 2; /* remove table and prototype from the stack */
/* last token read was anchored in defunct function; must reanchor it */
if (fs) anchor_token(ls);
L->top -= 2; /* remove table and prototype from the stack */
}
+4 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: lstrlib.c,v 1.132.1.4 2008/07/11 17:27:21 roberto Exp $
** $Id: lstrlib.c,v 1.132.1.5 2010/05/14 15:34:19 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -754,6 +754,7 @@ static void addintlen (char *form) {
static int str_format (lua_State *L) {
int top = lua_gettop(L);
int arg = 1;
size_t sfl;
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
@@ -768,7 +769,8 @@ static int str_format (lua_State *L) {
else { /* format item */
char form[MAX_FORMAT]; /* to store the format (`%...') */
char buff[MAX_ITEM]; /* to store the formatted item */
arg++;
if (++arg > top)
luaL_argerror(L, arg, "no value");
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
+4 -4
View File
@@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $
** $Id: lua.h,v 1.218.1.7 2012/01/13 20:36:20 roberto Exp $
** Lua - An Extensible Extension Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -17,9 +17,9 @@
#define LUA_VERSION "Lua 5.1"
#define LUA_RELEASE "Lua 5.1.4"
#define LUA_RELEASE "Lua 5.1.5"
#define LUA_VERSION_NUM 501
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT "Copyright (C) 1994-2012 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
@@ -362,7 +362,7 @@ struct lua_Debug {
/******************************************************************************
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
* Copyright (C) 1994-2012 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
+1 -1
View File
@@ -374,7 +374,7 @@ static int table_is_an_array(lua_State *L) {
while(lua_next(L,-2)) {
/* Stack: ... key value */
lua_pop(L,1); /* Stack: ... key */
if (!lua_isnumber(L,-1)) goto not_array;
if (lua_type(L,-1) != LUA_TNUMBER) goto not_array;
n = lua_tonumber(L,-1);
idx = n;
if (idx != n || idx < 1) goto not_array;
+119 -52
View File
@@ -1,18 +1,7 @@
#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 $
** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $
** See Copyright Notice at the end of this file
** =======================================================
*/
@@ -25,6 +14,7 @@
** b/B - signed/unsigned byte
** h/H - signed/unsigned short
** l/L - signed/unsigned long
** T - size_t
** 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
@@ -36,6 +26,38 @@
*/
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
#if (LUA_VERSION_NUM >= 502)
#define luaL_register(L,n,f) luaL_newlib(L,f)
#endif
/* basic integer type */
#if !defined(STRUCT_INT)
#define STRUCT_INT long
#endif
typedef STRUCT_INT Inttype;
/* corresponding unsigned version */
typedef unsigned STRUCT_INT Uinttype;
/* maximum size (in bytes) for integral types */
#define MAXINTSIZE 32
/* is 'x' a power of 2? */
#define isp2(x) ((x) > 0 && ((x) & ((x) - 1)) == 0)
@@ -67,11 +89,11 @@ typedef struct Header {
} Header;
static size_t getnum (const char **fmt, size_t df) {
static int getnum (const char **fmt, int df) {
if (!isdigit(**fmt)) /* no number? */
return df; /* return default value */
else {
size_t a = 0;
int a = 0;
do {
a = a*10 + *((*fmt)++) - '0';
} while (isdigit(**fmt));
@@ -89,33 +111,40 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) {
case 'B': case 'b': return sizeof(char);
case 'H': case 'h': return sizeof(short);
case 'L': case 'l': return sizeof(long);
case 'T': return sizeof(size_t);
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);
if (sz > MAXINTSIZE)
luaL_error(L, "integral size %d is larger than limit of %d",
sz, MAXINTSIZE);
return sz;
}
default: {
const char *msg = lua_pushfstring(L, "invalid format option [%c]", opt);
return luaL_argerror(L, 1, msg);
}
default: return 0; /* other cases do not need alignment */
}
}
/*
** return number of bytes needed to align an element of size 'size'
** at current position 'len'
*/
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);
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) {
/*
** options to control endianess and alignment
*/
static void controloptions (lua_State *L, int opt, const char **fmt,
Header *h) {
switch (opt) {
case ' ': return; /* ignore white spaces */
case '>': h->endian = BIG; return;
@@ -127,7 +156,10 @@ static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) {
h->align = a;
return;
}
default: assert(0);
default: {
const char *msg = lua_pushfstring(L, "invalid format option '%c'", opt);
luaL_argerror(L, 1, msg);
}
}
}
@@ -135,21 +167,27 @@ static void commoncases (lua_State *L, int opt, const char **fmt, Header *h) {
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;
Uinttype value;
char buff[MAXINTSIZE];
if (n < 0)
value = (Uinttype)(Inttype)n;
else
value = (unsigned long)n;
value = (Uinttype)n;
if (endian == LITTLE) {
int i;
for (i = 0; i < size; i++)
luaL_addchar(b, (value >> 8*i) & 0xff);
for (i = 0; i < size; i++) {
buff[i] = (value & 0xff);
value >>= 8;
}
}
else {
int i;
for (i = size - 1; i >= 0; i--)
luaL_addchar(b, (value >> 8*i) & 0xff);
for (i = size - 1; i >= 0; i--) {
buff[i] = (value & 0xff);
value >>= 8;
}
}
luaL_addlstring(b, buff, size);
}
@@ -179,15 +217,15 @@ static int b_pack (lua_State *L) {
size_t size = optsize(L, opt, &fmt);
int toalign = gettoalign(totalsize, &h, opt, size);
totalsize += toalign;
while (toalign-- > 0) luaL_putchar(&b, '\0');
while (toalign-- > 0) luaL_addchar(&b, '\0');
switch (opt) {
case 'b': case 'B': case 'h': case 'H':
case 'l': case 'L': case 'i': case 'I': { /* integer types */
case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
putinteger(L, &b, arg++, h.endian, size);
break;
}
case 'x': {
luaL_putchar(&b, '\0');
luaL_addchar(&b, '\0');
break;
}
case 'f': {
@@ -209,12 +247,12 @@ static int b_pack (lua_State *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 */
luaL_addchar(&b, '\0'); /* add zero at the end */
size++;
}
break;
}
default: commoncases(L, opt, &fmt, &h);
default: controloptions(L, opt, &fmt, &h);
}
totalsize += size;
}
@@ -225,24 +263,27 @@ static int b_pack (lua_State *L) {
static lua_Number getinteger (const char *buff, int endian,
int issigned, int size) {
unsigned long l = 0;
Uinttype l = 0;
int i;
if (endian == BIG) {
int i;
for (i = 0; i < size; i++)
l |= (unsigned long)(unsigned char)buff[size - i - 1] << (i*8);
for (i = 0; i < size; i++) {
l <<= 8;
l |= (Uinttype)(unsigned char)buff[i];
}
}
else {
int i;
for (i = 0; i < size; i++)
l |= (unsigned long)(unsigned char)buff[i] << (i*8);
for (i = size - 1; i >= 0; i--) {
l <<= 8;
l |= (Uinttype)(unsigned char)buff[i];
}
}
if (!issigned)
return (lua_Number)l;
else { /* signed format */
unsigned long mask = ~(0UL) << (size*8 - 1);
Uinttype mask = (Uinttype)(~((Uinttype)0)) << (size*8 - 1);
if (l & mask) /* negative value? */
l |= mask; /* signal extension */
return (lua_Number)(long)l;
return (lua_Number)(Inttype)l;
}
}
@@ -260,9 +301,10 @@ static int b_unpack (lua_State *L) {
size_t size = optsize(L, opt, &fmt);
pos += gettoalign(pos, &h, opt, size);
luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
luaL_checkstack(L, 1, "too many results");
switch (opt) {
case 'b': case 'B': case 'h': case 'H':
case 'l': case 'L': case 'i': case 'I': { /* integer types */
case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
int issigned = islower(opt);
lua_Number res = getinteger(data+pos, h.endian, issigned, size);
lua_pushnumber(L, res);
@@ -304,7 +346,7 @@ static int b_unpack (lua_State *L) {
lua_pushlstring(L, data+pos, size - 1);
break;
}
default: commoncases(L, opt, &fmt, &h);
default: controloptions(L, opt, &fmt, &h);
}
pos += size;
}
@@ -312,26 +354,50 @@ static int b_unpack (lua_State *L) {
return lua_gettop(L) - 2;
}
static int b_size (lua_State *L) {
Header h;
const char *fmt = luaL_checkstring(L, 1);
size_t pos = 0;
defaultoptions(&h);
while (*fmt) {
int opt = *fmt++;
size_t size = optsize(L, opt, &fmt);
pos += gettoalign(pos, &h, opt, size);
if (opt == 's')
luaL_argerror(L, 1, "option 's' has no fixed size");
else if (opt == 'c' && size == 0)
luaL_argerror(L, 1, "option 'c0' has no fixed size");
if (!isalnum(opt))
controloptions(L, opt, &fmt, &h);
pos += size;
}
lua_pushinteger(L, pos);
return 1;
}
/* }====================================================== */
static const struct luaL_reg thislib[] = {
static const struct luaL_Reg thislib[] = {
{"pack", b_pack},
{"unpack", b_unpack},
{"size", b_size},
{NULL, NULL}
};
LUALIB_API int luaopen_struct (lua_State *L);
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.
* Copyright (C) 2010-2012 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
@@ -352,3 +418,4 @@ LUALIB_API int luaopen_struct (lua_State *L) {
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/
+6 -2
View File
@@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $
** $Id: lvm.c,v 2.63.1.5 2011/08/17 20:43:11 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -133,6 +133,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
int loop;
TValue temp;
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* `t' is a table? */
@@ -141,6 +142,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
if (!ttisnil(oldval) || /* result is no nil? */
(tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */
setobj2t(L, oldval, val);
h->flags = 0;
luaC_barriert(L, h, val);
return;
}
@@ -152,7 +154,9 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
callTM(L, tm, t, key, val);
return;
}
t = tm; /* else repeat with `tm' */
/* else repeat with `tm' */
setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */
t = &temp;
}
luaG_runerror(L, "loop in settable");
}
+181 -26
View File
@@ -24,9 +24,14 @@ pidfile /var/run/redis.pid
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
# By default Redis listens for connections from all the network interfaces
# available on the server. It is possible to listen to just one or multiple
# interfaces using the "bind" configuration directive, followed by one or
# more IP addresses.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1
# Specify the path for the unix socket that will be used to listen for
@@ -39,18 +44,34 @@ port 6379
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# Set server verbosity to 'debug'
# it can be one of:
# TCP keepalive.
#
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
# of communication. This is useful for two reasons:
#
# 1) Detect dead peers.
# 2) Take the connection alive from the point of view of network
# equipment in the middle.
#
# On Linux, the specified value (in seconds) is the period used to send ACKs.
# Note that to close the connection the double of the time is needed.
# On other kernels the period depends on the kernel configuration.
#
# A reasonable value for this option is 60 seconds.
tcp-keepalive 0
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
# Specify the log file name. Also 'stdout' can be used to force
# Specify the log file name. Also the emptry string can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile stdout
logfile ""
# To enable logging to the system logger, just set 'syslog-enabled' to yes,
# and optionally update the other syslog parameters to suit your needs.
@@ -59,7 +80,7 @@ logfile stdout
# Specify the syslog identity.
# syslog-ident redis
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# syslog-facility local0
# Set the number of databases. The default database is DB 0, you can select
@@ -114,7 +135,7 @@ stop-writes-on-bgsave-error yes
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes
# Since verison 5 of RDB a CRC64 checksum is placed at the end of the file.
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
# for maximum performances.
@@ -131,7 +152,7 @@ dbfilename dump.rdb
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# Also the Append Only File will be created inside this directory.
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./
@@ -152,14 +173,14 @@ dir ./
#
# masterauth <master-password>
# When a slave lost the connection with the master, or when the replication
# When a slave loses its connection with the master, or when the replication
# is still in progress, the slave can act in two different ways:
#
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
# still reply to client requests, possibly with out of date data, or the
# data set may just be empty if this is the first synchronization.
#
# 2) if slave-serve-stale data is set to 'no' the slave will reply with
# 2) if slave-serve-stale-data is set to 'no' the slave will reply with
# an error "SYNC with master in progress" to all the kind of commands
# but to INFO and SLAVEOF.
#
@@ -187,8 +208,11 @@ slave-read-only yes
#
# repl-ping-slave-period 10
# The following option sets a timeout for both Bulk transfer I/O timeout and
# master data or ping response timeout. The default value is 60 seconds.
# The following option sets the replication timeout for:
#
# 1) Bulk transfer I/O during SYNC, from the point of view of slave.
# 2) Master timeout from the point of view of slaves (data, pings).
# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings).
#
# It is important to make sure that this value is greater than the value
# specified for repl-ping-slave-period otherwise a timeout will be detected
@@ -196,6 +220,43 @@ slave-read-only yes
#
# repl-timeout 60
# Disable TCP_NODELAY on the slave socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to slaves. But this can add a delay for
# the data to appear on the slave side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the slave side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and slaves are many hops away, turning this to "yes" may
# be a good idea.
repl-disable-tcp-nodelay no
# Set the replication backlog size. The backlog is a buffer that accumulates
# slave data when slaves are disconnected for some time, so that when a slave
# wants to reconnect again, often a full resync is not needed, but a partial
# resync is enough, just passing the portion of data the slave missed while
# disconnected.
#
# The biggest the replication backlog, the longer the time the slave can be
# disconnected and later be able to perform a partial resynchronization.
#
# The backlog is only allocated once there is at least a slave connected.
#
# repl-backlog-size 1mb
# After a master has no longer connected slaves for some time, the backlog
# will be freed. The following option configures the amount of seconds that
# need to elapse, starting from the time the last slave disconnected, for
# the backlog buffer to be freed.
#
# A value of 0 means to never release the backlog.
#
# repl-backlog-ttl 3600
# The slave priority is an integer number published by Redis in the INFO output.
# It is used by Redis Sentinel in order to select a slave to promote into a
# master if the master is no longer working correctly.
@@ -211,6 +272,28 @@ slave-read-only yes
# By default the priority is 100.
slave-priority 100
# It is possible for a master to stop accepting writes if there are less than
# N slaves connected, having a lag less or equal than M seconds.
#
# The N slaves need to be in "online" state.
#
# The lag in seconds, that must be <= the specified value, is calculated from
# the last ping received from the slave, that is usually sent every second.
#
# This option does not GUARANTEES that N replicas will accept the write, but
# will limit the window of exposure for lost writes in case not enough slaves
# are available, to the specified number of seconds.
#
# For example to require at least 3 slaves with a lag <= 10 seconds use:
#
# min-slaves-to-write 3
# min-slaves-max-lag 10
#
# Setting one or the other to 0 disables the feature.
#
# By default min-slaves-to-write is set to 0 (feature disabled) and
# min-slaves-max-lag is set to 10.
################################## SECURITY ###################################
# Require clients to issue AUTH <PASSWORD> before processing any other
@@ -230,23 +313,26 @@ slave-priority 100
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# of hard to guess so that it will be still available for internal-use
# tools but not available for general clients.
# hard to guess so that it will still be available for internal-use tools
# but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command renaming it into
# It is also possible to completely kill a command by renaming it into
# an empty string:
#
# rename-command CONFIG ""
#
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to slaves may cause problems.
################################### LIMITS ####################################
# Set the max number of connected clients at the same time. By default
# this limit is set to 10000 clients, however if the Redis server is not
# able ot configure the process file limit to allow for the specified limit
# able to configure the process file limit to allow for the specified limit
# the max number of allowed clients is set to the current file limit
# minus 32 (as Redis reserves a few file descriptors for internal uses).
#
@@ -281,7 +367,7 @@ slave-priority 100
# maxmemory <bytes>
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached? You can select among five behavior:
# is reached. You can select among five behaviors:
#
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key accordingly to the LRU algorithm
@@ -290,7 +376,7 @@ slave-priority 100
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#
# Note: with all the kind of policies, Redis will return an error on write
# Note: with any of the above policies, Redis will return an error on write
# operations, when there are not suitable keys for eviction.
#
# At the date of writing this commands are: set setnx setex append
@@ -346,7 +432,7 @@ appendonly no
# always: fsync after every write to the append only log . Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec" that's usually the right compromise between
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
@@ -374,9 +460,9 @@ appendfsync everysec
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving the durability of Redis is
# the same as "appendfsync none", that in practical terms means that it is
# possible to lost up to 30 seconds of log in the worst scenario (with the
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync none". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
@@ -385,10 +471,10 @@ no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size will growth by the specified percentage.
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (or if no rewrite happened since the restart, the size of
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
@@ -445,6 +531,52 @@ slowlog-log-slower-than 10000
# You can reclaim memory used by the slow log with SLOWLOG RESET.
slowlog-max-len 128
############################# Event notification ##############################
# Redis can notify Pub/Sub clients about events happening in the key space.
# This feature is documented at http://redis.io/topics/keyspace-events
#
# For instance if keyspace events notification is enabled, and a client
# performs a DEL operation on key "foo" stored in the Database 0, two
# messages will be published via Pub/Sub:
#
# PUBLISH __keyspace@0__:foo del
# PUBLISH __keyevent@0__:del foo
#
# It is possible to select the events that Redis will notify among a set
# of classes. Every class is identified by a single character:
#
# K Keyspace events, published with __keyspace@<db>__ prefix.
# E Keyevent events, published with __keyevent@<db>__ prefix.
# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
# $ String commands
# l List commands
# s Set commands
# h Hash commands
# z Sorted set commands
# x Expired events (events generated every time a key expires)
# e Evicted events (events generated when a key is evicted for maxmemory)
# A Alias for g$lshzxe, so that the "AKE" string means all the events.
#
# The "notify-keyspace-events" takes as argument a string that is composed
# by zero or multiple characters. The empty string means that notifications
# are disabled at all.
#
# Example: to enable list and generic events, from the point of view of the
# event name, use:
#
# notify-keyspace-events Elg
#
# Example 2: to get the stream of the expired keys subscribing to channel
# name __keyevent@0__:expired use:
#
# notify-keyspace-events Ex
#
# By default all notifications are disabled because most users don't need
# this feature and the feature has some overhead. Note that if you don't
# specify at least one of K or E, no events will be delivered.
notify-keyspace-events ""
############################### ADVANCED CONFIG ###############################
# Hashes are encoded using a memory efficient data structure when they have a
@@ -524,11 +656,34 @@ activerehashing yes
# Instead there is a default limit for pubsub and slave clients, since
# subscribers and slaves receive data in a push fashion.
#
# Both the hard or the soft limit can be disabled just setting it to zero.
# Both the hard or the soft limit can be disabled by setting them to zero.
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
# Redis calls an internal function to perform many background tasks, like
# closing connections of clients in timeot, purging expired keys that are
# never requested, and so forth.
#
# Not all tasks are performed with the same frequency, but Redis checks for
# tasks to perform accordingly to the specified "hz" value.
#
# By default "hz" is set to 10. Raising the value will use more CPU when
# Redis is idle, but at the same time will make Redis more responsive when
# there are many keys expiring at the same time, and timeouts may be
# handled with more precision.
#
# The range is between 1 and 500, however a value over 100 is usually not
# a good idea. Most users should use the default of 10 and raise this up to
# 100 only in environments where very low latency is required.
hz 10
# When a child rewrites the AOF file, if the following option is enabled
# the file will be fsync-ed every 32 MB of data generated. This is useful
# in order to commit the file to the disk more incrementally and avoid
# big latency spikes.
aof-rewrite-incremental-fsync yes
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
+10 -5
View File
@@ -1,9 +1,14 @@
#!/bin/sh
TCL=tclsh8.5
which $TCL
if [ "$?" != "0" ]
TCL_VERSIONS="8.5 8.6"
TCLSH=""
for VERSION in $TCL_VERSIONS; do
TCL=`which tclsh$VERSION 2>/dev/null` && TCLSH=$TCL
done
if [ -z $TCLSH ]
then
echo "You need '$TCL' in order to run the Redis test"
echo "You need tcl 8.5 or newer in order to run the Redis test"
exit 1
fi
$TCL tests/test_helper.tcl $*
$TCLSH tests/test_helper.tcl $*
+28 -32
View File
@@ -9,6 +9,10 @@ port 26379
# Tells Sentinel to monitor this slave, and to consider it in O_DOWN
# (Objectively Down) state only if at least <quorum> sentinels agree.
#
# Note that whatever is the ODOWN quorum, a Sentinel will require to
# be elected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
#
# Note: master name should not include special characters or spaces.
# The valid charset is A-z 0-9 and the three characters ".-_".
sentinel monitor mymaster 127.0.0.1 6379 2
@@ -42,11 +46,6 @@ sentinel monitor mymaster 127.0.0.1 6379 2
# Default is 30 seconds.
sentinel down-after-milliseconds mymaster 30000
# sentinel can-failover <master-name> <yes|no>
#
# Specify if this Sentinel can start the failover for this master.
sentinel can-failover mymaster yes
# sentinel parallel-syncs <master-name> <numslaves>
#
# How many slaves we can reconfigure to point to the new slave simultaneously
@@ -57,21 +56,30 @@ sentinel parallel-syncs mymaster 1
# sentinel failover-timeout <master-name> <milliseconds>
#
# Specifies the failover timeout in milliseconds. When this time has elapsed
# without any progress in the failover process, it is considered concluded by
# the sentinel even if not all the attached slaves were correctly configured
# to replicate with the new master (however a "best effort" SLAVEOF command
# is sent to all the slaves before).
# Specifies the failover timeout in milliseconds. It is used in many ways:
#
# Also when 25% of this time has elapsed without any advancement, and there
# is a leader switch (the sentinel did not started the failover but is now
# elected as leader), the sentinel will continue the failover doing a
# "takeover".
# - The time needed to re-start a failover after a previous failover was
# already tried against the same master by a given Sentinel, is two
# times the failover timeout.
#
# Default is 15 minutes.
sentinel failover-timeout mymaster 900000
# - The time needed for a slave replicating to a wrong master according
# to a Sentinel currnet configuration, to be forced to replicate
# with the right master, is exactly the failover timeout (counting since
# the moment a Sentinel detected the misconfiguration).
#
# - The time needed to cancel a failover that is already in progress but
# did not produced any configuration change (SLAVEOF NO ONE yet not
# acknowledged by the promoted slave).
#
# - The maximum time a failover in progress waits for all the slaves to be
# reconfigured as slaves of the new master. However even after this time
# the slaves will be reconfigured by the Sentinels anyway, but not with
# the exact parallel-syncs progression as specified.
#
# Default is 3 minutes.
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECTION
# SCRIPTS EXECUTION
#
# sentinel notification-script and sentinel reconfig-script are used in order
# to configure scripts that are called to notify the system administrator
@@ -114,32 +122,20 @@ sentinel failover-timeout mymaster 900000
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# When the failover starts, ends, or is aborted, a script can be called in
# When the master changed because of a failover a script can be called in
# order to perform application-specific tasks to notify the clients that the
# configuration has changed and the master is at a different address.
#
# The script is called in the following cases:
#
# Failover started (a slave is already promoted)
# Failover finished (all the additional slaves already reconfigured)
# Failover aborted (in that case the script was previously called when the
# failover started, and now gets called again with swapped
# addresses).
#
# The following arguments are passed to the script:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> is "start", "end" or "abort"
# <state> is currently always "failover"
# <role> is either "leader" or "observer"
#
# The arguments from-ip, from-port, to-ip, to-port are used to communicate
# the old address of the master and the new address of the elected slave
# (now a master) in the case state is "start" or "end".
#
# For abort instead the "from" is the address of the promoted slave and
# "to" is the address of the original master address, since the failover
# was aborted.
# (now a master).
#
# This script should be resistant to multiple invocations.
#
+49 -40
View File
@@ -18,72 +18,76 @@ OPTIMIZATION?=-O2
DEPENDENCY_TARGETS=hiredis linenoise lua
# Default settings
STD= -std=c99 -pedantic
WARN= -Wall
OPT= $(OPTIMIZATION)
STD=-std=c99 -pedantic
WARN=-Wall
OPT=$(OPTIMIZATION)
PREFIX?=/usr/local
INSTALL_BIN=$(PREFIX)/bin
INSTALL=install
# Default allocator
ifeq ($(uname_S),Linux)
MALLOC=jemalloc
MALLOC=jemalloc
else
MALLOC=libc
MALLOC=libc
endif
# Backwards compatibility for selecting an allocator
ifeq ($(USE_TCMALLOC),yes)
MALLOC=tcmalloc
MALLOC=tcmalloc
endif
ifeq ($(USE_TCMALLOC_MINIMAL),yes)
MALLOC=tcmalloc_minimal
MALLOC=tcmalloc_minimal
endif
ifeq ($(USE_JEMALLOC),yes)
MALLOC=jemalloc
MALLOC=jemalloc
endif
# Override default settings if possible
-include .make-settings
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
FINAL_LIBS=-lm
DEBUG=-g -ggdb
ifeq ($(uname_S),SunOS)
FINAL_CFLAGS= $(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS) -D__EXTENSIONS__ -D_XPG6
FINAL_LDFLAGS= $(LDFLAGS) $(REDIS_LDFLAGS) -g -ggdb
FINAL_LIBS= -ldl -lnsl -lsocket -lm -lpthread
DEBUG= -g -ggdb
INSTALL=cp -pf
FINAL_CFLAGS+= -D__EXTENSIONS__ -D_XPG6
FINAL_LIBS+= -ldl -lnsl -lsocket -lpthread
else ifeq ($(uname_S),Darwin)
else
FINAL_CFLAGS= $(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
FINAL_LDFLAGS= $(LDFLAGS) $(REDIS_LDFLAGS) -g -rdynamic -ggdb
FINAL_LIBS= -lm -pthread
DEBUG= -g -rdynamic -ggdb
FINAL_LDFLAGS+= -rdynamic
FINAL_LIBS+= -pthread
endif
# Include paths to dependencies
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src
ifeq ($(MALLOC),tcmalloc)
FINAL_CFLAGS+= -DUSE_TCMALLOC
FINAL_LIBS+= -ltcmalloc
FINAL_CFLAGS+= -DUSE_TCMALLOC
FINAL_LIBS+= -ltcmalloc
endif
ifeq ($(MALLOC),tcmalloc_minimal)
FINAL_CFLAGS+= -DUSE_TCMALLOC
FINAL_LIBS+= -ltcmalloc_minimal
FINAL_CFLAGS+= -DUSE_TCMALLOC
FINAL_LIBS+= -ltcmalloc_minimal
endif
ifeq ($(MALLOC),jemalloc)
DEPENDENCY_TARGETS+= jemalloc
FINAL_CFLAGS+= -DUSE_JEMALLOC -I../deps/jemalloc/include
FINAL_LIBS+= ../deps/jemalloc/lib/libjemalloc.a -ldl
DEPENDENCY_TARGETS+= jemalloc
FINAL_CFLAGS+= -DUSE_JEMALLOC -I../deps/jemalloc/include
FINAL_LIBS+= ../deps/jemalloc/lib/libjemalloc.a -ldl
endif
REDIS_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS)
REDIS_LD=$(QUIET_LINK)$(CC) $(FINAL_LDFLAGS)
REDIS_INSTALL=$(QUIET_INSTALL)$(INSTALL)
PREFIX?=/usr/local
INSTALL_BIN= $(PREFIX)/bin
INSTALL= cp -pf
CCCOLOR="\033[34m"
LINKCOLOR="\033[34;1m"
SRCCOLOR="\033[33m"
@@ -97,17 +101,17 @@ QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(EN
QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2;
endif
REDIS_SERVER_NAME= redis-server
REDIS_SENTINEL_NAME= redis-sentinel
REDIS_SERVER_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 migrate.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o
REDIS_CLI_NAME= redis-cli
REDIS_CLI_OBJ= anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o
REDIS_BENCHMARK_NAME= redis-benchmark
REDIS_BENCHMARK_OBJ= ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o redis-benchmark.o
REDIS_CHECK_DUMP_NAME= redis-check-dump
REDIS_CHECK_DUMP_OBJ= redis-check-dump.o lzf_c.o lzf_d.o crc64.o
REDIS_CHECK_AOF_NAME= redis-check-aof
REDIS_CHECK_AOF_OBJ= redis-check-aof.o
REDIS_SERVER_NAME=redis-server
REDIS_SENTINEL_NAME=redis-sentinel
REDIS_SERVER_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 migrate.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o
REDIS_CLI_NAME=redis-cli
REDIS_CLI_OBJ=anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o
REDIS_BENCHMARK_NAME=redis-benchmark
REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o redis-benchmark.o
REDIS_CHECK_DUMP_NAME=redis-check-dump
REDIS_CHECK_DUMP_OBJ=redis-check-dump.o lzf_c.o lzf_d.o crc64.o
REDIS_CHECK_AOF_NAME=redis-check-aof
REDIS_CHECK_AOF_OBJ=redis-check-aof.o
all: $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_DUMP_NAME) $(REDIS_CHECK_AOF_NAME)
@echo ""
@@ -196,6 +200,8 @@ distclean: clean
test: $(REDIS_SERVER_NAME) $(REDIS_CHECK_AOF_NAME)
@(cd ..; ./runtest)
check: test
lcov:
$(MAKE) gcov
@(set -e; cd ..; ./runtest --clients 1)
@@ -217,13 +223,16 @@ gcov:
$(MAKE) REDIS_CFLAGS="-fprofile-arcs -ftest-coverage -DCOVERAGE_TEST" REDIS_LDFLAGS="-fprofile-arcs -ftest-coverage"
noopt:
$(MAKE) OPT="-O0"
$(MAKE) OPTIMIZATION="-O0"
valgrind:
$(MAKE) OPTIMIZATION="-O0" MALLOC="libc"
src/help.h:
@../utils/generate-command-help.rb > help.h
install: all
mkdir -p $(INSTALL_BIN)
@mkdir -p $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_SERVER_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_BENCHMARK_NAME) $(INSTALL_BIN)
$(REDIS_INSTALL) $(REDIS_CLI_NAME) $(INSTALL_BIN)
+22 -9
View File
@@ -1,6 +1,7 @@
adlist.o: adlist.c adlist.h zmalloc.h
ae.o: ae.c ae.h zmalloc.h config.h ae_kqueue.c
ae_epoll.o: ae_epoll.c
ae_evport.o: ae_evport.c
ae_kqueue.o: ae_kqueue.c
ae_select.o: ae_select.c
anet.o: anet.c fmacros.h anet.h
@@ -10,6 +11,9 @@ aof.o: aof.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
bio.o: bio.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h bio.h
bitops.o: bitops.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
config.o: config.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
@@ -19,13 +23,13 @@ db.o: db.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
debug.o: debug.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h crc64.h bio.h
dict.o: dict.c fmacros.h dict.h zmalloc.h
endianconv.o: endianconv.c
intset.o: intset.c intset.h zmalloc.h endianconv.h
intset.o: intset.c intset.h zmalloc.h endianconv.h config.h
lzf_c.o: lzf_c.c lzfP.h
lzf_d.o: lzf_d.c lzfP.h
memtest.o: memtest.c
memtest.o: memtest.c config.h
migrate.o: migrate.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h endianconv.h
@@ -36,6 +40,9 @@ networking.o: networking.c redis.h fmacros.h config.h \
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
notify.o: notify.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
object.o: object.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
@@ -51,25 +58,31 @@ rdb.o: rdb.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
redis-benchmark.o: redis-benchmark.c fmacros.h ae.h \
../deps/hiredis/hiredis.h sds.h adlist.h zmalloc.h
redis-check-aof.o: redis-check-aof.c fmacros.h config.h
redis-check-dump.o: redis-check-dump.c lzf.h
redis-check-dump.o: redis-check-dump.c lzf.h crc64.h
redis-cli.o: redis-cli.c fmacros.h version.h ../deps/hiredis/hiredis.h \
sds.h zmalloc.h ../deps/linenoise/linenoise.h help.h
sds.h zmalloc.h ../deps/linenoise/linenoise.h help.h anet.h ae.h
redis.o: redis.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h slowlog.h bio.h \
asciilogo.h
release.o: release.c release.h
release.o: release.c release.h version.h crc64.h
replication.o: replication.c redis.h fmacros.h config.h \
../deps/lua/src/lua.h ../deps/lua/src/luaconf.h ae.h sds.h dict.h \
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h \
rio.h
rio.o: rio.c fmacros.h rio.h sds.h util.h
rio.o: rio.c fmacros.h rio.h sds.h util.h crc64.h
scripting.o: scripting.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h sha1.h rand.h \
../deps/lua/src/lauxlib.h ../deps/lua/src/lua.h \
../deps/lua/src/lualib.h
sds.o: sds.c sds.h zmalloc.h
sentinel.o: sentinel.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h \
../deps/hiredis/hiredis.h ../deps/hiredis/async.h \
../deps/hiredis/hiredis.h
setproctitle.o: setproctitle.c
sha1.o: sha1.c sha1.h config.h
slowlog.o: slowlog.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
@@ -96,6 +109,6 @@ t_zset.o: t_zset.c redis.h fmacros.h config.h ../deps/lua/src/lua.h \
../deps/lua/src/luaconf.h ae.h sds.h dict.h adlist.h zmalloc.h anet.h \
ziplist.h intset.h version.h util.h rdb.h rio.h
util.o: util.c fmacros.h util.h
ziplist.o: ziplist.c zmalloc.h util.h ziplist.h endianconv.h
zipmap.o: zipmap.c zmalloc.h endianconv.h
ziplist.o: ziplist.c zmalloc.h util.h ziplist.h endianconv.h config.h
zipmap.o: zipmap.c zmalloc.h endianconv.h config.h
zmalloc.o: zmalloc.c config.h zmalloc.h
+3 -3
View File
@@ -97,7 +97,7 @@ list *listAddNodeHead(list *list, void *value)
return list;
}
/* Add a new node to the list, to tail, contaning the specified 'value'
/* Add a new node to the list, to tail, containing the specified 'value'
* pointer as value.
*
* On error, NULL is returned and no operation is performed (i.e. the
@@ -308,7 +308,7 @@ listNode *listSearchKey(list *list, void *key)
/* Return the element at the specified zero-based index
* where 0 is the head, 1 is the element next to head
* and so on. Negative integers are used in order to count
* from the tail, -1 is the last element, -2 the penultimante
* from the tail, -1 is the last element, -2 the penultimate
* and so on. If the index is out of range NULL is returned. */
listNode *listIndex(list *list, long index) {
listNode *n;
@@ -330,7 +330,7 @@ void listRotate(list *list) {
if (listLength(list) <= 1) return;
/* Detatch current tail */
/* Detach current tail */
list->tail = tail->prev;
list->tail->next = NULL;
/* Move it as head */
+1 -1
View File
@@ -1,6 +1,6 @@
/* adlist.h - A generic doubly linked list implementation
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
+38 -4
View File
@@ -38,6 +38,7 @@
#include <poll.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include "ae.h"
#include "zmalloc.h"
@@ -90,6 +91,36 @@ err:
return NULL;
}
/* Return the current set size. */
int aeGetSetSize(aeEventLoop *eventLoop) {
return eventLoop->setsize;
}
/* Resize the maximum set size of the event loop.
* If the requested set size is smaller than the current set size, but
* there is already a file descriptor in use that is >= the requested
* set size minus one, AE_ERR is returned and the operation is not
* performed at all.
*
* Otherwise AE_OK is returned and the operation is successful. */
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
int i;
if (setsize == eventLoop->setsize) return AE_OK;
if (eventLoop->maxfd >= setsize) return AE_ERR;
if (aeApiResize(eventLoop,setsize) == -1) return AE_ERR;
eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize);
eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize);
eventLoop->setsize = setsize;
/* Make sure that if we created new slots, they are initialized with
* an AE_NONE mask. */
for (i = eventLoop->maxfd+1; i < setsize; i++)
eventLoop->events[i].mask = AE_NONE;
return AE_OK;
}
void aeDeleteEventLoop(aeEventLoop *eventLoop) {
aeApiFree(eventLoop);
zfree(eventLoop->events);
@@ -104,7 +135,10 @@ void aeStop(aeEventLoop *eventLoop) {
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
aeFileProc *proc, void *clientData)
{
if (fd >= eventLoop->setsize) return AE_ERR;
if (fd >= eventLoop->setsize) {
errno = ERANGE;
return AE_ERR;
}
aeFileEvent *fe = &eventLoop->events[fd];
if (aeApiAddEvent(eventLoop, fd, mask) == -1)
@@ -305,7 +339,7 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
/* Process every pending time event, then every pending file event
* (that may be registered by time event callbacks just processed).
* Without special flags the function sleeps until some file event
* fires, or when the next time event occurrs (if any).
* fires, or when the next time event occurs (if any).
*
* If flags is 0, the function does nothing and returns.
* if flags has AE_ALL_EVENTS set, all the kind of events are processed.
@@ -352,7 +386,7 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
if (tvp->tv_usec < 0) tvp->tv_usec = 0;
} else {
/* If we have to check for events but need to return
* ASAP because of AE_DONT_WAIT we need to se the timeout
* ASAP because of AE_DONT_WAIT we need to set the timeout
* to zero */
if (flags & AE_DONT_WAIT) {
tv.tv_sec = tv.tv_usec = 0;
@@ -391,7 +425,7 @@ int aeProcessEvents(aeEventLoop *eventLoop, int flags)
return processed; /* return the number of processed file/time events */
}
/* Wait for millseconds until the given file descriptor becomes
/* Wait for milliseconds until the given file descriptor becomes
* writable/readable/exception */
int aeWait(int fd, int mask, long long milliseconds) {
struct pollfd pfd;
+3 -1
View File
@@ -2,7 +2,7 @@
* for the Jim's event-loop (Jim is a Tcl interpreter) but later translated
* it in form of a library for easy reuse.
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -114,5 +114,7 @@ int aeWait(int fd, int mask, long long milliseconds);
void aeMain(aeEventLoop *eventLoop);
char *aeGetApiName(void);
void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep);
int aeGetSetSize(aeEventLoop *eventLoop);
int aeResizeSetSize(aeEventLoop *eventLoop, int setsize);
#endif
+36 -2
View File
@@ -1,6 +1,33 @@
/* Linux epoll(2) based ae.c module
* Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
* Released under the BSD license. See the COPYING file for more info. */
*
* Copyright (c) 2009-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 <sys/epoll.h>
@@ -28,6 +55,13 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
return 0;
}
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
aeApiState *state = eventLoop->apidata;
state->events = zrealloc(state->events, sizeof(struct epoll_event)*setsize);
return 0;
}
static void aeApiFree(aeEventLoop *eventLoop) {
aeApiState *state = eventLoop->apidata;
+38 -7
View File
@@ -1,6 +1,32 @@
/* ae.c module for illumos event ports.
*
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Released under the BSD license. See the COPYING file for more info. */
*
* 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 <assert.h>
#include <errno.h>
@@ -24,15 +50,15 @@ static int evport_debug = 0;
* aeApiPoll, the corresponding file descriptors become dissociated from the
* port. This is necessary because poll events are level-triggered, so if the
* fd didn't become dissociated, it would immediately fire another event since
* the underlying state hasn't changed yet. We must reassociate the file
* the underlying state hasn't changed yet. We must re-associate the file
* descriptor, but only after we know that our caller has actually read from it.
* The ae API does not tell us exactly when that happens, but we do know that
* it must happen by the time aeApiPoll is called again. Our solution is to
* keep track of the last fds returned by aeApiPoll and reassociate them next
* keep track of the last fds returned by aeApiPoll and re-associate them next
* time aeApiPoll is invoked.
*
* To summarize, in this module, each fd association is EITHER (a) represented
* only via the in-kernel assocation OR (b) represented by pending_fds and
* only via the in-kernel association OR (b) represented by pending_fds and
* pending_masks. (b) is only true for the last fds we returned from aeApiPoll,
* and only until we enter aeApiPoll again (at which point we restore the
* in-kernel association).
@@ -68,6 +94,11 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
return 0;
}
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
/* Nothing to resize here. */
return 0;
}
static void aeApiFree(aeEventLoop *eventLoop) {
aeApiState *state = eventLoop->apidata;
@@ -138,7 +169,7 @@ static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
* This fd was recently returned from aeApiPoll. It should be safe to
* assume that the consumer has processed that poll event, but we play
* it safer by simply updating pending_mask. The fd will be
* reassociated as usual when aeApiPoll is called again.
* re-associated as usual when aeApiPoll is called again.
*/
if (evport_debug)
fprintf(stderr, "aeApiAddEvent: adding to pending fd %d\n", fd);
@@ -202,7 +233,7 @@ static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
* ENOMEM is a potentially transient condition, but the kernel won't
* generally return it unless things are really bad. EAGAIN indicates
* we've reached an resource limit, for which it doesn't make sense to
* retry (counterintuitively). All other errors indicate a bug. In any
* retry (counter-intuitively). All other errors indicate a bug. In any
* of these cases, the best we can do is to abort.
*/
abort(); /* will not return */
@@ -217,7 +248,7 @@ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
port_event_t event[MAX_EVENT_BATCHSZ];
/*
* If we've returned fd events before, we must reassociate them with the
* If we've returned fd events before, we must re-associate them with the
* port now, before calling port_get(). See the block comment at the top of
* this file for an explanation of why.
*/
+35 -2
View File
@@ -1,6 +1,33 @@
/* Kqueue(2)-based ae.c module
*
* Copyright (C) 2009 Harish Mallipeddi - harish.mallipeddi@gmail.com
* Released under the BSD license. See the COPYING file for more info. */
* 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 <sys/types.h>
#include <sys/event.h>
@@ -27,10 +54,16 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
return -1;
}
eventLoop->apidata = state;
return 0;
}
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
aeApiState *state = eventLoop->apidata;
state->events = zrealloc(state->events, sizeof(struct kevent)*setsize);
return 0;
}
static void aeApiFree(aeEventLoop *eventLoop) {
aeApiState *state = eventLoop->apidata;
+36 -3
View File
@@ -1,6 +1,33 @@
/* Select()-based ae.c module
* Copyright (C) 2009-2010 Salvatore Sanfilippo - antirez@gmail.com
* Released under the BSD license. See the COPYING file for more info. */
/* Select()-based ae.c module.
*
* Copyright (c) 2009-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 <string.h>
@@ -21,6 +48,12 @@ static int aeApiCreate(aeEventLoop *eventLoop) {
return 0;
}
static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
/* Just ensure we have enough room in the fd_set type. */
if (setsize >= FD_SETSIZE) return -1;
return 0;
}
static void aeApiFree(aeEventLoop *eventLoop) {
zfree(eventLoop->apidata);
}
+210 -73
View File
@@ -1,6 +1,6 @@
/* anet.c -- Basic TCP socket stuff made a bit less boring
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,7 @@ int anetNonBlock(char *err, int fd)
{
int flags;
/* Set the socket nonblocking.
/* Set the socket non-blocking.
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
if ((flags = fcntl(fd, F_GETFL)) == -1) {
@@ -75,10 +75,56 @@ int anetNonBlock(char *err, int fd)
return ANET_OK;
}
int anetTcpNoDelay(char *err, int fd)
/* Set TCP keep alive option to detect dead peers. The interval option
* is only used for Linux as we are using Linux-specific APIs to set
* the probe send time, interval, and count. */
int anetKeepAlive(char *err, int fd, int interval)
{
int yes = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1)
int val = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1)
{
anetSetError(err, "setsockopt SO_KEEPALIVE: %s", strerror(errno));
return ANET_ERR;
}
#ifdef __linux__
/* Default settings are more or less garbage, with the keepalive time
* set to 7200 by default on Linux. Modify settings to make the feature
* actually useful. */
/* Send first probe after interval. */
val = interval;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) {
anetSetError(err, "setsockopt TCP_KEEPIDLE: %s\n", strerror(errno));
return ANET_ERR;
}
/* Send next probes after the specified interval. Note that we set the
* delay as interval / 3, as we send three probes before detecting
* an error (see the next setsockopt call). */
val = interval/3;
if (val == 0) val = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) {
anetSetError(err, "setsockopt TCP_KEEPINTVL: %s\n", strerror(errno));
return ANET_ERR;
}
/* Consider the socket in error state after three we send three ACK
* probes without getting a reply. */
val = 3;
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
anetSetError(err, "setsockopt TCP_KEEPCNT: %s\n", strerror(errno));
return ANET_ERR;
}
#endif
return ANET_OK;
}
static int anetSetTcpNoDelay(char *err, int fd, int val)
{
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1)
{
anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
return ANET_ERR;
@@ -86,6 +132,17 @@ int anetTcpNoDelay(char *err, int fd)
return ANET_OK;
}
int anetEnableTcpNoDelay(char *err, int fd)
{
return anetSetTcpNoDelay(err, fd, 1);
}
int anetDisableTcpNoDelay(char *err, int fd)
{
return anetSetTcpNoDelay(err, fd, 0);
}
int anetSetSendBuffer(char *err, int fd, int buffsize)
{
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffsize, sizeof(buffsize)) == -1)
@@ -106,36 +163,53 @@ int anetTcpKeepAlive(char *err, int fd)
return ANET_OK;
}
int anetResolve(char *err, char *host, char *ipbuf)
int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len)
{
struct sockaddr_in sa;
struct addrinfo hints, *info;
int rv;
sa.sin_family = AF_INET;
if (inet_aton(host, &sa.sin_addr) == 0) {
struct hostent *he;
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; /* specify socktype to avoid dups */
he = gethostbyname(host);
if (he == NULL) {
anetSetError(err, "can't resolve: %s", host);
return ANET_ERR;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
if ((rv = getaddrinfo(host, NULL, &hints, &info)) != 0) {
anetSetError(err, "%s", gai_strerror(rv));
return ANET_ERR;
}
if (info->ai_family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *)info->ai_addr;
inet_ntop(AF_INET, &(sa->sin_addr), ipbuf, ipbuf_len);
} else {
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)info->ai_addr;
inet_ntop(AF_INET6, &(sa->sin6_addr), ipbuf, ipbuf_len);
}
freeaddrinfo(info);
return ANET_OK;
}
static int anetSetReuseAddr(char *err, int fd) {
int yes = 1;
/* Make sure connection-intensive things like the redis benckmark
* will be able to close/open sockets a zillion of times */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
return ANET_ERR;
}
strcpy(ipbuf,inet_ntoa(sa.sin_addr));
return ANET_OK;
}
static int anetCreateSocket(char *err, int domain) {
int s, on = 1;
int s;
if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
anetSetError(err, "creating socket: %s", strerror(errno));
return ANET_ERR;
}
/* Make sure connection-intensive things like the redis benckmark
/* Make sure connection-intensive things like the redis benchmark
* will be able to close/open sockets a zillion of times */
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
anetSetError(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
if (anetSetReuseAddr(err,s) == ANET_ERR) {
close(s);
return ANET_ERR;
}
return s;
@@ -145,38 +219,45 @@ static int anetCreateSocket(char *err, int domain) {
#define ANET_CONNECT_NONBLOCK 1
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
{
int s;
struct sockaddr_in sa;
int s, rv;
char _port[6]; /* strlen("65535"); */
struct addrinfo hints, *servinfo, *p;
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
snprintf(_port,6,"%d",port);
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) {
anetSetError(err, "%s", gai_strerror(rv));
return ANET_ERR;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
continue;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if (inet_aton(addr, &sa.sin_addr) == 0) {
struct hostent *he;
he = gethostbyname(addr);
if (he == NULL) {
anetSetError(err, "can't resolve: %s", addr);
/* if we set err then goto cleanup, otherwise next */
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
if (flags & ANET_CONNECT_NONBLOCK && anetNonBlock(err,s) != ANET_OK)
goto error;
if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
if (errno == EINPROGRESS && flags & ANET_CONNECT_NONBLOCK) goto end;
close(s);
return ANET_ERR;
continue;
}
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
}
if (flags & ANET_CONNECT_NONBLOCK) {
if (anetNonBlock(err,s) != ANET_OK)
return ANET_ERR;
}
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
if (errno == EINPROGRESS &&
flags & ANET_CONNECT_NONBLOCK)
return s;
anetSetError(err, "connect: %s", strerror(errno));
close(s);
return ANET_ERR;
/* break with the socket */
goto end;
}
if (p == NULL) {
anetSetError(err, "creating socket: %s", strerror(errno));
goto error;
}
error:
s = ANET_ERR;
end:
freeaddrinfo(servinfo);
return s;
}
@@ -274,28 +355,63 @@ static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
return ANET_OK;
}
int anetTcpServer(char *err, int port, char *bindaddr)
{
int s;
struct sockaddr_in sa;
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
return ANET_ERR;
memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) {
anetSetError(err, "invalid bind address");
static int anetV6Only(char *err, int s) {
int yes = 1;
if (setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,&yes,sizeof(yes)) == -1) {
anetSetError(err, "setsockopt: %s", strerror(errno));
close(s);
return ANET_ERR;
}
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
return ANET_OK;
}
static int _anetTcpServer(char *err, int port, char *bindaddr, int af)
{
int s, rv;
char _port[6]; /* strlen("65535") */
struct addrinfo hints, *servinfo, *p;
snprintf(_port,6,"%d",port);
memset(&hints,0,sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; /* No effect if bindaddr != NULL */
if ((rv = getaddrinfo(bindaddr,_port,&hints,&servinfo)) != 0) {
anetSetError(err, "%s", gai_strerror(rv));
return ANET_ERR;
}
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
continue;
if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error;
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
if (anetListen(err,s,p->ai_addr,p->ai_addrlen) == ANET_ERR) goto error;
goto end;
}
if (p == NULL) {
anetSetError(err, "unable to bind socket");
goto error;
}
error:
s = ANET_ERR;
end:
freeaddrinfo(servinfo);
return s;
}
int anetTcpServer(char *err, int port, char *bindaddr)
{
return _anetTcpServer(err, port, bindaddr, AF_INET);
}
int anetTcp6Server(char *err, int port, char *bindaddr)
{
return _anetTcpServer(err, port, bindaddr, AF_INET6);
}
int anetUnixServer(char *err, char *path, mode_t perm)
{
int s;
@@ -331,15 +447,22 @@ static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *l
return fd;
}
int anetTcpAccept(char *err, int s, char *ip, int *port) {
int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) {
int fd;
struct sockaddr_in sa;
struct sockaddr_storage sa;
socklen_t salen = sizeof(sa);
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
return ANET_ERR;
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
if (sa.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&sa;
if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len);
if (port) *port = ntohs(s->sin_port);
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len);
if (port) *port = ntohs(s->sin6_port);
}
return fd;
}
@@ -353,8 +476,8 @@ int anetUnixAccept(char *err, int s) {
return fd;
}
int anetPeerToString(int fd, char *ip, int *port) {
struct sockaddr_in sa;
int anetPeerToString(int fd, char *ip, size_t ip_len, int *port) {
struct sockaddr_storage sa;
socklen_t salen = sizeof(sa);
if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) {
@@ -363,13 +486,20 @@ int anetPeerToString(int fd, char *ip, int *port) {
ip[1] = '\0';
return -1;
}
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
if (sa.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&sa;
if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len);
if (port) *port = ntohs(s->sin_port);
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len);
if (port) *port = ntohs(s->sin6_port);
}
return 0;
}
int anetSockName(int fd, char *ip, int *port) {
struct sockaddr_in sa;
int anetSockName(int fd, char *ip, size_t ip_len, int *port) {
struct sockaddr_storage sa;
socklen_t salen = sizeof(sa);
if (getsockname(fd,(struct sockaddr*)&sa,&salen) == -1) {
@@ -378,7 +508,14 @@ int anetSockName(int fd, char *ip, int *port) {
ip[1] = '\0';
return -1;
}
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
if (port) *port = ntohs(sa.sin_port);
if (sa.ss_family == AF_INET) {
struct sockaddr_in *s = (struct sockaddr_in *)&sa;
if (ip) inet_ntop(AF_INET,(void*)&(s->sin_addr),ip,ip_len);
if (port) *port = ntohs(s->sin_port);
} else {
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
if (ip) inet_ntop(AF_INET6,(void*)&(s->sin6_addr),ip,ip_len);
if (port) *port = ntohs(s->sin6_port);
}
return 0;
}
+9 -5
View File
@@ -1,6 +1,6 @@
/* anet.c -- Basic TCP socket stuff made a bit less boring
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,15 +44,19 @@ int anetTcpNonBlockConnect(char *err, char *addr, int port);
int anetUnixConnect(char *err, char *path);
int anetUnixNonBlockConnect(char *err, char *path);
int anetRead(int fd, char *buf, int count);
int anetResolve(char *err, char *host, char *ipbuf);
int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len);
int anetTcpServer(char *err, int port, char *bindaddr);
int anetTcp6Server(char *err, int port, char *bindaddr);
int anetUnixServer(char *err, char *path, mode_t perm);
int anetTcpAccept(char *err, int serversock, char *ip, int *port);
int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);
int anetUnixAccept(char *err, int serversock);
int anetWrite(int fd, char *buf, int count);
int anetNonBlock(char *err, int fd);
int anetTcpNoDelay(char *err, int fd);
int anetEnableTcpNoDelay(char *err, int fd);
int anetDisableTcpNoDelay(char *err, int fd);
int anetTcpKeepAlive(char *err, int fd);
int anetPeerToString(int fd, char *ip, int *port);
int anetPeerToString(int fd, char *ip, size_t ip_len, int *port);
int anetKeepAlive(char *err, int fd, int interval);
int anetSockName(int fd, char *ip, size_t ip_len, int *port);
#endif
+49 -8
View File
@@ -1,3 +1,32 @@
/*
* Copyright (c) 2009-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 "redis.h"
#include "bio.h"
#include "rio.h"
@@ -148,7 +177,7 @@ void stopAppendOnly(void) {
redisLog(REDIS_NOTICE,"Killing running AOF rewrite child: %ld",
(long) server.aof_child_pid);
if (kill(server.aof_child_pid,SIGKILL) != -1)
if (kill(server.aof_child_pid,SIGUSR1) != -1)
wait3(&statloc,0,NULL);
/* reset the buffer accumulating changes while the child saves */
aofRewriteBufferReset();
@@ -356,7 +385,7 @@ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int a
sds buf = sdsempty();
robj *tmpargv[3];
/* The DB this command was targetting is not the same as the last command
/* The DB this command was targeting is not the same as the last command
* we appendend. To issue a SELECT command is needed. */
if (dictid != server.aof_selected_db) {
char seldb[64];
@@ -413,6 +442,7 @@ struct redisClient *createFakeClient(void) {
selectDb(c,0);
c->fd = -1;
c->name = NULL;
c->querybuf = sdsempty();
c->querybuf_peak = 0;
c->argc = 0;
@@ -426,7 +456,7 @@ struct redisClient *createFakeClient(void) {
c->reply_bytes = 0;
c->obuf_soft_limit_reached_time = 0;
c->watched_keys = listCreate();
listSetFreeMethod(c->reply,decrRefCount);
listSetFreeMethod(c->reply,decrRefCountVoid);
listSetDupMethod(c->reply,dupClientReplyValue);
initClientMultiState(c);
return c;
@@ -506,7 +536,7 @@ int loadAppendOnlyFile(char *filename) {
/* Command lookup */
cmd = lookupCommand(argv[0]->ptr);
if (!cmd) {
redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", (char*)argv[0]->ptr);
exit(1);
}
/* Run the command in the context of a fake client */
@@ -825,6 +855,8 @@ int rewriteAppendOnlyFile(char *filename) {
}
rioInitWithFile(&aof,fp);
if (server.aof_rewrite_incremental_fsync)
rioSetAutoSync(&aof,REDIS_AOF_AUTOSYNC_BYTES);
for (j = 0; j < server.dbnum; j++) {
char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
redisDb *db = server.db+j;
@@ -852,6 +884,9 @@ int rewriteAppendOnlyFile(char *filename) {
expiretime = getExpire(db,&key);
/* If this key is already expired skip it */
if (expiretime != -1 && expiretime < now) continue;
/* Save the key and associated value */
if (o->type == REDIS_STRING) {
/* Emit a SET command */
@@ -874,8 +909,6 @@ int rewriteAppendOnlyFile(char *filename) {
/* Save the expire time */
if (expiretime != -1) {
char cmd[]="*3\r\n$9\r\nPEXPIREAT\r\n";
/* If this key is already expired skip it */
if (expiretime < now) continue;
if (rioWrite(&aof,cmd,sizeof(cmd)-1) == 0) goto werr;
if (rioWriteBulkObject(&aof,&key) == 0) goto werr;
if (rioWriteBulkLongLong(&aof,expiretime) == 0) goto werr;
@@ -929,10 +962,17 @@ int rewriteAppendOnlyFileBackground(void) {
char tmpfile[256];
/* Child */
if (server.ipfd > 0) close(server.ipfd);
if (server.sofd > 0) close(server.sofd);
closeListeningSockets(0);
redisSetProcTitle("redis-aof-rewrite");
snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
size_t private_dirty = zmalloc_get_private_dirty();
if (private_dirty) {
redisLog(REDIS_NOTICE,
"AOF rewrite: %zu MB of memory used by copy-on-write",
private_dirty/(1024*1024));
}
exitFromChild(0);
} else {
exitFromChild(1);
@@ -957,6 +997,7 @@ int rewriteAppendOnlyFileBackground(void) {
* accumulated by the parent into server.aof_rewrite_buf will start
* with a SELECT statement and it will be safe to merge. */
server.aof_selected_db = -1;
replicationScriptCacheFlush();
return REDIS_OK;
}
return REDIS_OK; /* unreached */
+29
View File
@@ -1,3 +1,32 @@
/*
* Copyright (c) 2009-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.
*/
char *ascii_logo =
" _._ \n"
" _.-``__ ''-._ \n"
+54 -51
View File
@@ -26,11 +26,42 @@
*
* Currently there is no way for the creator of the job to be notified about
* the completion of the operation, this will only be added when/if needed.
*
* ----------------------------------------------------------------------------
*
* Copyright (c) 2009-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 "redis.h"
#include "bio.h"
static pthread_t bio_threads[REDIS_BIO_NUM_OPS];
static pthread_mutex_t bio_mutex[REDIS_BIO_NUM_OPS];
static pthread_cond_t bio_condvar[REDIS_BIO_NUM_OPS];
static list *bio_jobs[REDIS_BIO_NUM_OPS];
@@ -43,7 +74,7 @@ static list *bio_jobs[REDIS_BIO_NUM_OPS];
static unsigned long long bio_pending[REDIS_BIO_NUM_OPS];
/* This structure represents a background Job. It is only used locally to this
* file as the API deos not expose the internals at all. */
* file as the API does not expose the internals at all. */
struct bio_job {
time_t time; /* Time at which the job was created. */
/* Job specific arguments pointers. If we need to pass more than three
@@ -88,6 +119,7 @@ void bioInit(void) {
redisLog(REDIS_WARNING,"Fatal: Can't initialize Background Jobs.");
exit(1);
}
bio_threads[j] = thread;
}
}
@@ -110,7 +142,11 @@ void *bioProcessBackgroundJobs(void *arg) {
unsigned long type = (unsigned long) arg;
sigset_t sigset;
pthread_detach(pthread_self());
/* Make the thread killable at any time, so that bioKillThreads()
* can work reliably. */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_mutex_lock(&bio_mutex[type]);
/* Block SIGALRM so we are sure that only the main thread will
* receive the watchdog signal. */
@@ -162,56 +198,23 @@ unsigned long long bioPendingJobsOfType(int type) {
return val;
}
#if 0 /* We don't use the following code for now, and bioWaitPendingJobsLE
probably needs a rewrite using conditional variables instead of the
current implementation. */
/* Kill the running bio threads in an unclean way. This function should be
* used only when it's critical to stop the threads for some reason.
* Currently Redis does this only on crash (for instance on SIGSEGV) in order
* to perform a fast memory check without other threads messing with memory. */
void bioKillThreads(void) {
int err, j;
/* Wait until the number of pending jobs of the specified type are
* less or equal to the specified number.
*
* This function may block for long time, it should only be used to perform
* the following tasks:
*
* 1) To avoid that the main thread is pushing jobs of a given time so fast
* that the background thread can't process them at the same speed.
* So before creating a new job of a given type the main thread should
* call something like: bioWaitPendingJobsLE(job_type,10000);
* 2) In order to perform special operations that make it necessary to be sure
* no one is touching shared resourced in the background.
*/
void bioWaitPendingJobsLE(int type, unsigned long long num) {
unsigned long long iteration = 0;
/* We poll the jobs queue aggressively to start, and gradually relax
* the polling speed if it is going to take too much time. */
while(1) {
iteration++;
if (iteration > 1000 && iteration <= 10000) {
usleep(100);
} else if (iteration > 10000) {
usleep(1000);
for (j = 0; j < REDIS_BIO_NUM_OPS; j++) {
if (pthread_cancel(bio_threads[j]) == 0) {
if ((err = pthread_join(bio_threads[j],NULL)) != 0) {
redisLog(REDIS_WARNING,
"Bio thread for job type #%d can be joined: %s",
j, strerror(err));
} else {
redisLog(REDIS_WARNING,
"Bio thread for job type #%d terminated",j);
}
}
if (bioPendingJobsOfType(type) <= num) break;
}
}
/* Return the older job of the specified type. */
time_t bioOlderJobOfType(int type) {
time_t time;
listNode *ln;
struct bio_job *job;
pthread_mutex_lock(&bio_mutex[type]);
ln = listFirst(bio_jobs[type]);
if (ln == NULL) {
pthread_mutex_unlock(&bio_mutex[type]);
return 0;
}
job = ln->value;
time = job->time;
pthread_mutex_unlock(&bio_mutex[type]);
return time;
}
#endif

Some files were not shown because too many files have changed in this diff Show More