Showing preview only (3,696K chars total). Download the full file or copy to clipboard to get everything.
Repository: antirez/disque
Branch: master
Commit: 0192ba7e1cda
Files: 327
Total size: 3.5 MB
Directory structure:
gitextract_1opxwdmk/
├── .gitignore
├── .travis.yml
├── COPYING
├── Makefile
├── README.md
├── deps/
│ ├── Makefile
│ ├── README.md
│ ├── hiredis/
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── CHANGELOG.md
│ │ ├── COPYING
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── adapters/
│ │ │ ├── ae.h
│ │ │ ├── libev.h
│ │ │ ├── libevent.h
│ │ │ └── libuv.h
│ │ ├── async.c
│ │ ├── async.h
│ │ ├── dict.c
│ │ ├── dict.h
│ │ ├── examples/
│ │ │ ├── example-ae.c
│ │ │ ├── example-libev.c
│ │ │ ├── example-libevent.c
│ │ │ ├── example-libuv.c
│ │ │ └── example.c
│ │ ├── fmacros.h
│ │ ├── hiredis.c
│ │ ├── hiredis.h
│ │ ├── net.c
│ │ ├── net.h
│ │ ├── sds.c
│ │ ├── sds.h
│ │ ├── sdsalloc.h
│ │ ├── test.c
│ │ └── zmalloc.h
│ ├── jemalloc/
│ │ ├── .autom4te.cfg
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── COPYING
│ │ ├── ChangeLog
│ │ ├── INSTALL
│ │ ├── Makefile.in
│ │ ├── README
│ │ ├── VERSION
│ │ ├── autogen.sh
│ │ ├── bin/
│ │ │ ├── jemalloc-config.in
│ │ │ ├── jemalloc.sh.in
│ │ │ └── jeprof.in
│ │ ├── config.guess
│ │ ├── config.stamp.in
│ │ ├── config.sub
│ │ ├── configure
│ │ ├── configure.ac
│ │ ├── coverage.sh
│ │ ├── doc/
│ │ │ ├── html.xsl.in
│ │ │ ├── jemalloc.3
│ │ │ ├── jemalloc.html
│ │ │ ├── jemalloc.xml.in
│ │ │ ├── manpages.xsl.in
│ │ │ └── stylesheet.xsl
│ │ ├── include/
│ │ │ ├── jemalloc/
│ │ │ │ ├── internal/
│ │ │ │ │ ├── arena.h
│ │ │ │ │ ├── atomic.h
│ │ │ │ │ ├── base.h
│ │ │ │ │ ├── bitmap.h
│ │ │ │ │ ├── chunk.h
│ │ │ │ │ ├── chunk_dss.h
│ │ │ │ │ ├── chunk_mmap.h
│ │ │ │ │ ├── ckh.h
│ │ │ │ │ ├── ctl.h
│ │ │ │ │ ├── extent.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── huge.h
│ │ │ │ │ ├── jemalloc_internal.h.in
│ │ │ │ │ ├── jemalloc_internal_decls.h
│ │ │ │ │ ├── jemalloc_internal_defs.h.in
│ │ │ │ │ ├── jemalloc_internal_macros.h
│ │ │ │ │ ├── mb.h
│ │ │ │ │ ├── mutex.h
│ │ │ │ │ ├── pages.h
│ │ │ │ │ ├── private_namespace.sh
│ │ │ │ │ ├── private_symbols.txt
│ │ │ │ │ ├── private_unnamespace.sh
│ │ │ │ │ ├── prng.h
│ │ │ │ │ ├── prof.h
│ │ │ │ │ ├── public_namespace.sh
│ │ │ │ │ ├── public_unnamespace.sh
│ │ │ │ │ ├── ql.h
│ │ │ │ │ ├── qr.h
│ │ │ │ │ ├── quarantine.h
│ │ │ │ │ ├── rb.h
│ │ │ │ │ ├── rtree.h
│ │ │ │ │ ├── size_classes.sh
│ │ │ │ │ ├── stats.h
│ │ │ │ │ ├── tcache.h
│ │ │ │ │ ├── tsd.h
│ │ │ │ │ ├── util.h
│ │ │ │ │ └── valgrind.h
│ │ │ │ ├── jemalloc.sh
│ │ │ │ ├── jemalloc_defs.h.in
│ │ │ │ ├── jemalloc_macros.h.in
│ │ │ │ ├── jemalloc_mangle.sh
│ │ │ │ ├── jemalloc_protos.h.in
│ │ │ │ ├── jemalloc_rename.sh
│ │ │ │ └── jemalloc_typedefs.h.in
│ │ │ └── msvc_compat/
│ │ │ ├── C99/
│ │ │ │ ├── stdbool.h
│ │ │ │ └── stdint.h
│ │ │ ├── strings.h
│ │ │ └── windows_extra.h
│ │ ├── install-sh
│ │ ├── jemalloc.pc.in
│ │ ├── src/
│ │ │ ├── arena.c
│ │ │ ├── atomic.c
│ │ │ ├── base.c
│ │ │ ├── bitmap.c
│ │ │ ├── chunk.c
│ │ │ ├── chunk_dss.c
│ │ │ ├── chunk_mmap.c
│ │ │ ├── ckh.c
│ │ │ ├── ctl.c
│ │ │ ├── extent.c
│ │ │ ├── hash.c
│ │ │ ├── huge.c
│ │ │ ├── jemalloc.c
│ │ │ ├── mb.c
│ │ │ ├── mutex.c
│ │ │ ├── pages.c
│ │ │ ├── prof.c
│ │ │ ├── quarantine.c
│ │ │ ├── rtree.c
│ │ │ ├── stats.c
│ │ │ ├── tcache.c
│ │ │ ├── tsd.c
│ │ │ ├── util.c
│ │ │ ├── valgrind.c
│ │ │ └── zone.c
│ │ └── test/
│ │ ├── include/
│ │ │ └── test/
│ │ │ ├── SFMT-alti.h
│ │ │ ├── SFMT-params.h
│ │ │ ├── SFMT-params11213.h
│ │ │ ├── SFMT-params1279.h
│ │ │ ├── SFMT-params132049.h
│ │ │ ├── SFMT-params19937.h
│ │ │ ├── SFMT-params216091.h
│ │ │ ├── SFMT-params2281.h
│ │ │ ├── SFMT-params4253.h
│ │ │ ├── SFMT-params44497.h
│ │ │ ├── SFMT-params607.h
│ │ │ ├── SFMT-params86243.h
│ │ │ ├── SFMT-sse2.h
│ │ │ ├── SFMT.h
│ │ │ ├── btalloc.h
│ │ │ ├── jemalloc_test.h.in
│ │ │ ├── jemalloc_test_defs.h.in
│ │ │ ├── math.h
│ │ │ ├── mq.h
│ │ │ ├── mtx.h
│ │ │ ├── test.h
│ │ │ ├── thd.h
│ │ │ └── timer.h
│ │ ├── integration/
│ │ │ ├── MALLOCX_ARENA.c
│ │ │ ├── aligned_alloc.c
│ │ │ ├── allocated.c
│ │ │ ├── chunk.c
│ │ │ ├── mallocx.c
│ │ │ ├── overflow.c
│ │ │ ├── posix_memalign.c
│ │ │ ├── rallocx.c
│ │ │ ├── sdallocx.c
│ │ │ ├── thread_arena.c
│ │ │ ├── thread_tcache_enabled.c
│ │ │ └── xallocx.c
│ │ ├── src/
│ │ │ ├── SFMT.c
│ │ │ ├── btalloc.c
│ │ │ ├── btalloc_0.c
│ │ │ ├── btalloc_1.c
│ │ │ ├── math.c
│ │ │ ├── mq.c
│ │ │ ├── mtx.c
│ │ │ ├── test.c
│ │ │ ├── thd.c
│ │ │ └── timer.c
│ │ ├── stress/
│ │ │ └── microbench.c
│ │ ├── test.sh.in
│ │ └── unit/
│ │ ├── SFMT.c
│ │ ├── atomic.c
│ │ ├── bitmap.c
│ │ ├── ckh.c
│ │ ├── hash.c
│ │ ├── junk.c
│ │ ├── junk_alloc.c
│ │ ├── junk_free.c
│ │ ├── lg_chunk.c
│ │ ├── mallctl.c
│ │ ├── math.c
│ │ ├── mq.c
│ │ ├── mtx.c
│ │ ├── prof_accum.c
│ │ ├── prof_active.c
│ │ ├── prof_gdump.c
│ │ ├── prof_idump.c
│ │ ├── prof_reset.c
│ │ ├── prof_thread_name.c
│ │ ├── ql.c
│ │ ├── qr.c
│ │ ├── quarantine.c
│ │ ├── rb.c
│ │ ├── rtree.c
│ │ ├── size_classes.c
│ │ ├── stats.c
│ │ ├── tsd.c
│ │ ├── util.c
│ │ └── zero.c
│ ├── linenoise/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.markdown
│ │ ├── example.c
│ │ ├── linenoise.c
│ │ └── linenoise.h
│ └── update-jemalloc.sh
├── disque.conf
├── runtest
├── src/
│ ├── .gitignore
│ ├── 00-RELEASENOTES
│ ├── Makefile
│ ├── Makefile.dep
│ ├── ack.c
│ ├── ack.h
│ ├── adlist.c
│ ├── adlist.h
│ ├── ae.c
│ ├── ae.h
│ ├── ae_epoll.c
│ ├── ae_evport.c
│ ├── ae_kqueue.c
│ ├── ae_select.c
│ ├── anet.c
│ ├── anet.h
│ ├── aof.c
│ ├── asciilogo.h
│ ├── atomicvar.h
│ ├── bio.c
│ ├── bio.h
│ ├── blocked.c
│ ├── cluster.c
│ ├── cluster.h
│ ├── config.c
│ ├── config.h
│ ├── crc64.c
│ ├── crc64.h
│ ├── debug.c
│ ├── dict.c
│ ├── dict.h
│ ├── disque-check-aof.c
│ ├── disque-cli.c
│ ├── disqueassert.h
│ ├── endianconv.c
│ ├── endianconv.h
│ ├── fmacros.h
│ ├── help.h
│ ├── job.c
│ ├── job.h
│ ├── latency.c
│ ├── latency.h
│ ├── lzf.h
│ ├── lzfP.h
│ ├── lzf_c.c
│ ├── lzf_d.c
│ ├── memtest.c
│ ├── mkreleasehdr.sh
│ ├── networking.c
│ ├── object.c
│ ├── pqsort.c
│ ├── pqsort.h
│ ├── queue.c
│ ├── queue.h
│ ├── release.c
│ ├── rio.c
│ ├── rio.h
│ ├── sds.c
│ ├── sds.h
│ ├── sdsalloc.h
│ ├── server.c
│ ├── server.h
│ ├── setproctitle.c
│ ├── sha1.c
│ ├── sha1.h
│ ├── skiplist.c
│ ├── skiplist.h
│ ├── slowlog.c
│ ├── slowlog.h
│ ├── solarisfixes.h
│ ├── sparkline.c
│ ├── sparkline.h
│ ├── syncio.c
│ ├── testhelp.h
│ ├── util.c
│ ├── util.h
│ ├── valgrind.sup
│ ├── version.h
│ ├── zmalloc.c
│ └── zmalloc.h
└── tests/
├── cluster/
│ ├── cluster.tcl
│ ├── run.tcl
│ ├── tests/
│ │ ├── 00-base.tcl
│ │ ├── 01-faildet.tcl
│ │ ├── 02-jobs-replication.tcl
│ │ ├── 03-jobs-queueing.tcl
│ │ ├── 04-ttl.tcl
│ │ ├── 05-acks.tcl
│ │ ├── 06-federation.tcl
│ │ ├── 07-persistence.tcl
│ │ ├── 08-qscan.tcl
│ │ ├── 09-jscan.tcl
│ │ ├── 10-leaving.tcl
│ │ ├── 11-waiting-nack.tcl
│ │ ├── 12-nack-and-counters.tcl
│ │ └── includes/
│ │ ├── init-tests.tcl
│ │ └── job-utils.tcl
│ └── tmp/
│ └── .gitignore
├── instances.tcl
├── support/
│ ├── cluster.tcl
│ ├── redis.tcl
│ ├── server.tcl
│ ├── test.tcl
│ ├── tmpfile.tcl
│ └── util.tcl
└── test_helper.tcl
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.*.swp
*.o
*.log
dump.rdb
disque-server
disque-check-aof
disque
doc-tools
release
misc/*
src/release.h
appendonly.aof
SHORT_TERM_TODO
release.h
src/transfer.sh
src/configs
redis.ds
src/redis.conf
src/nodes.conf
deps/lua/src/lua
deps/lua/src/luac
deps/lua/src/liblua.a
.make-*
.prerequisites
*.dSYM
================================================
FILE: .travis.yml
================================================
language: c
sudo: false
addons:
apt:
packages:
- tcl8.5
cache:
directories:
- $HOME/.ccache
install: make CC="ccache $CC"
script: make test
================================================
FILE: COPYING
================================================
Copyright (c) 2006-2014, 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:
* 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 Disque 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.
================================================
FILE: Makefile
================================================
# Top level makefile, the real shit is at src/Makefile
default: all
.DEFAULT:
cd src && $(MAKE) $@
install:
cd src && $(MAKE) $@
.PHONY: install
================================================
FILE: README.md
================================================
[](https://travis-ci.org/antirez/disque)
Disque, an in-memory, distributed job queue
===
Disque is an ongoing experiment to build a distributed, in-memory, message
broker.
Its goal is to capture the essence of the "Redis as a jobs queue" use case,
which is usually implemented using blocking list operations, and move
it into an ad-hoc, self-contained, scalable, and fault tolerant design, with
simple to understand properties and guarantees, but still resembling Redis
in terms of simplicity, performance, and implementation as a C non-blocking
networked server.
Currently (2 Jan 2016) the project is in release candidate state. People are
encouraged to start evaluating it and report bugs and experiences.
**WARNING: This is beta code and may not be suitable for production usage. The API is considered to be stable if not for details that may change in the next release candidates, however it's new code, so handle with care!**
What is a message queue?
---
*Hint: skip this section if you are familiar with message queues.*
You know how humans use text messages to communicate, right? I could write
my wife "please get the milk at the store", and she maybe will reply "Ok message
received, I'll get two bottles on my way home".
A message queue is the same as human text messages, but for computer programs.
For example a web application, when an user subscribes, may send another
process, that handles sending emails, "please send the confirmation email
to tom@example.net".
Message systems like Disque allow communication between processes using
different queues. So a process can send a message to a queue with a given
name, and only processes which fetch messages from this queue will return those
messages. Moreover, multiple processes can listen for messages in a given
queue, and multiple processes can send messages to the same queue.
The important part of a message queue is to be able to provide guarantees so
that messages are eventually delivered even in the face of failures. So even
if in theory implementing a message queue is very easy, to write a very
robust and scalable one is harder than it may appear.
Give me the details!
---
Disque is a distributed and fault tolerant message broker, so it works as a
middle layer among processes that want to exchange messages.
Producers add messages that are served to consumers.
Since message queues are often used in order to process delayed
jobs, Disque often uses the term "job" in the API and in the documentation,
however jobs are actually just messages in the form of strings, so Disque
can be used for other use cases. In this documentation "jobs" and "messages"
are used in an interchangeable way.
Job queues with a producer-consumer model are pretty common, so the devil is
in the details. A few details about Disque are:
Disque is a **synchronously replicated job queue**. By default when a new job is added, it is replicated to W nodes before the client gets an acknowledgement about the job being added. W-1 nodes can fail and the message will still be delivered.
Disque supports both **at-least-once and at-most-once** delivery semantics. At-least-once delivery semantics is where most effort was spent in the design and implementation, while at-most-once semantics is a trivial result of using a *retry time* set to 0 (which means, never re-queue the message again) and a replication factor of 1 for the message (not strictly needed, but it is useless to have multiple copies of a message around if it will be delivered at most one time). You can have, at the same time, both at-least-once and at-most-once jobs in the same queues and nodes, since this is a per message setting.
Disque at-least-once delivery is designed to **approximate single delivery** when possible, even during certain kinds of failures. This means that while Disque can only guarantee a number of deliveries equal or greater to one, it will try hard to avoid multiple deliveries whenever possible.
Disque is a distributed system where **all nodes have the same role** (aka, it is multi-master). Producers and consumers can attach to whatever node they like, and there is no need for producers and consumers of the same queue to stay connected to the same node. Nodes will automatically exchange messages based on load and client requests.
Disque is Available (it is an eventually consistent AP system in CAP terms): producers and consumers can make progress as long as a single node is reachable.
Disque supports **optional asynchronous commands** that are low latency for the client but provide less guarantees. For example a producer can add a job to a queue with a replication factor of 3, but may want to run away before knowing if the contacted node was really able to replicate it to the specified number of nodes or not. The node will replicate the message in the background in a best effort way.
Disque **automatically re-queues messages that are not acknowledged** as already processed by consumers, after a message-specific retry time. There is no need for consumers to re-queue a message if it was not processed.
Disque uses **explicit acknowledges** in order for a consumer to signal a message as delivered (or, using a different terminology, to signal a job as already processed).
Disque queues only provides **best effort ordering**. Each queue sorts messages based on the job creation time, which is obtained using the *wall clock* of the local node where the message was created (plus an incremental counter for messages created in the same millisecond), so messages created in the same node are normally delivered in the same order they were created. This is not causal ordering since correct ordering is violated in different cases: when messages are re-issued because they are not acknowledged, because of nodes local clock drifts, and when messages are moved to other nodes for load balancing and federation (in this case you end with queues having jobs originated in different nodes with different wall clocks). However all this also means that normally messages are not delivered in random order and usually messages created first are delivered first.
Note that since Disque does not provide strict FIFO semantics, technically speaking it should not be called a *message queue*, and it could better identified as a message broker. However I believe that at this point in the IT industry a *message queue* is often more lightly used to identify a generic broker that may or may not be able to guarantee order in all cases. Given that we document the semantics very clearly, I grant myself the right to call Disque a message queue anyway.
Disque provides the user with fine-grained control for each job **using three time related parameters**, and one replication parameter. For each job, the user can control:
1. The replication factor (how many nodes have a copy).
2. The delay time (the min time Disque will wait before putting the message in a queue, making the message deliverable).
3. The retry time (how much time should elapse since the last time the job was queued and without an acknowledge about the job delivery, before the job is re-queued for delivery).
4. The expire time (how much time should elapse for the job to be deleted regardless of whether it was successfully delivered, i.e. acknowledged, or not).
Finally, Disque supports optional disk persistence, which is not enabled by default, but that can be handy in single data center setups and during restarts.
Other minor features are:
* Ability to block queues.
* A few statistics about queue activity.
* Stateless iterators for queues and jobs.
* Commands to control the visibility of single jobs.
* Easy resize of the cluster (adding nodes is trivial).
* Graceful removal of nodes without losing job replicas.
ACKs and retries
---
Disque's implementation of *at-least-once* delivery semantics is designed in
order to avoid multiple delivery during certain classes of failures. It is not able to guarantee that no multiple deliveries will occur. However there are many *at-least-once* workloads where duplicated deliveries are acceptable (or explicitly handled), but not desirable either. A trivial example is sending emails to users (it is not terrible if an user gets a duplicated email, but is important to avoid it when possible), or doing idempotent operations that are expensive (all the times where it is critical for performance to avoid multiple deliveries).
In order to avoid multiple deliveries when possible, Disque uses client ACKs. When a consumer processes a message correctly, it should acknowledge this fact to Disque. ACKs are replicated to multiple nodes, and are garbage collected as soon as the system believes it is unlikely that more nodes in the cluster have the job (the ACK refers to) still active. Under memory pressure or under certain failure scenarios, ACKs are eventually discarded.
More explicitly:
1. A job is replicated to multiple nodes, but usually only *queued* in a single node. There is a difference between having a job in memory, and queueing it for delivery.
2. Nodes having a copy of a message, if a certain amount of time has elapsed without getting the ACK for the message, will re-queue it. Nodes will run a best-effort protocol to avoid re-queueing the message multiple times.
3. ACKs are replicated and garbage collected across the cluster so that eventually processed messages are evicted (this happens ASAP if there are no failures nor network partitions).
For example, if a node having a copy of a job gets partitioned away during the time the job gets acknowledged by the consumer, it is likely that when it returns (in a reasonable amount of time, that is, before the retry time is reached) it will be informed about the ACK and will avoid to re-queue the message. Similarly, jobs can be acknowledged during a partition to just a single available node, and when the partition heals the ACK will be propagated to other nodes that may still have a copy of the message.
So an ACK is just a **proof of delivery** that is replicated and retained for
some time in order to make multiple deliveries less likely to happen in practice.
As already mentioned, in order to control replication and retries, a Disque job has the following associated properties: number of replicas, delay, retry and expire.
If a job has a retry time set to 0, it will get queued exactly once (and in this case a replication factor greater than 1 is useless, and signaled as an error to the user), so it will get delivered either a single time or will never get delivered. While jobs can be persisted on disk for safety, queues aren't, so this behavior is guaranteed even when nodes restart after a crash, whatever the persistence configuration is. However when nodes are manually restarted by the sysadmin, for example for upgrades, queues are persisted correctly and reloaded at startup, since the store/load operation is atomic in this case, and there are no race conditions possible (it is not possible that a job was delivered to a client and is persisted on disk as queued at the same time).
Fast acknowledges
---
Disque supports a faster way to acknowledge processed messages, via the
`FASTACK` command. The normal acknowledge is very expensive from the point of
view of messages exchanged between nodes, this is what happens during a normal
acknowledge:
1. The client sends ACKJOB to one node.
2. The node sends a SETACK message to everybody it believes to have a copy.
3. The receivers of SETACK reply with GOTACK to confirm.
4. The node finally sends DELJOB to all the nodes.
*Note: actual garbage collection is more complex in case of failures and is explained in the state machine later. The above is what happens 99% of times.*
If a message is replicated to 3 nodes, acknowledging requires 1+2+2+2 messages,
for the sake of retaining the ack if some nodes may not be reached when the
message is acknowledged. This makes the probability of multiple deliveries of
this message less likely.
However the alternative **fast ack**, while less reliable, is much faster
and invovles exchanging less messages. This is how a fast acknowledge works:
1. The client sends `FASTACK` to one node.
2. The node evicts the job and sends a best effort DELJOB to all the nodes that may have a copy, or to all the cluster if the node was not aware of the job.
If during a fast acknowledge a node having a copy of the message is not
reachable, for example because of a network partition, the node will deliver
the message again, since it has a non-acknowledged copy of the message and
there is nobody able to inform it the message has been acknowledged when the
partition heals.
If the network you are using is pretty reliable, and you are very concerned with
performance, and multiple deliveries in the context of your applications are
a non issue, then `FASTACK` is probably the way to go.
Dead letter queue
---
Many message queues implement a feature called *dead letter queue*. It is
a special queue used in order to accumulate messages that cannot be processed
for some reason. Common causes could be:
1. The message was delivered too many times but never correctly processed.
2. The message time-to-live reached zero before it was processed.
3. Some worker explicitly asked the system to flag the message as having issues.
The idea is that the administrator of the system checks (usually via automatic
systems) if there is something in the dead letter queue in order to understand
if there is some software error or other kind of error preventing messages
from being processed as expected.
Since Disque is an in-memory system, the message time-to-live is an important
property. When it is reached, we want messages to go away, since the TTL should
be chosen so that after such a time it is no longer meaningful to process
the message. In such a system, to use memory and create a queue in response
to an error or to messages timing out looks like a non optimal idea. Moreover,
due to the distributed nature of Disque, dead letters could end up spawning
multiple nodes and having duplicated entries in them.
So Disque uses a different approach. Each node message representation has
two counters: a **nacks counter** and an **additional deliveries** counter.
The counters are not consistent among nodes having a copy of the same message,
they are just best effort counters that may not increment in some node during
network partitions.
The idea of these two counters is that one is incremented every time a worker
uses the `NACK` command to tell the queue the message was not processed correctly
and should be put back on the queue ASAP. The other is incremented for every other condition (different than the `NACK` call) that requires a message to be put back
on the queue again. This includes messages that get lost and are enqueued again
or messages that are enqueued on one side of the partition since the message
was processed on the other side and so forth.
Using the `GETJOB` command with the `WITHCOUNTERS` option, or using the
`SHOW` command to inspect a job, it is possible to retrieve these two counters
together with the other job information, so if a worker, before processing
a message, sees the counters have values over some application-defined limit, it
can notify operations people in multiple ways:
1. It may send an email.
2. Set a flag in a monitoring system.
3. Put the message in a special queue (simulating the dead letter feature).
4. Attempt to process the message and report the stack trace of the error if any.
Basically the exact handling of the feature is up to the application using
Disque. Note that the counters don't need to be consistent in the face of
failures or network partitions: the idea is that eventually if a message has
issues the counters will get incremented enough times to reach the limit
selected by the application as a warning threshold.
The reason for having two distinct counters is that applications may want
to handle the case of explicit negative acknowledges via `NACK` differently
than multiple deliveries because of timeouts or messages getting lost.
Disque and disk persistence
---
Disque can be operated in-memory only, using synchronous replication as a
durability guarantee, or can be operated using the Append Only File where
jobs creations and evictions are logged on disk (with configurable fsync
policies) and reloaded at restart.
AOF is recommended especially if you run in a single availability zone
where a mass reboot of all your nodes is possible.
Normally Disque only reloads job data in memory, without populating queues,
since unacknowledged jobs are requeued eventually. Moreover, reloading
queue data is not safe in the case of at-most-once jobs having the retry value
set to 0. However a special option is provided in order to reload the full
state from the AOF. This is used together with an option that allows shutting
down the server just after the AOF is generated from scratch, in order to
make it safe even to reload jobs with retry set to 0, since the AOF is generated
while the server no longer accepts commands from clients, so no race condition
is possible.
Even when running memory-only, Disque is able to dump its memory on disk and reload from disk on controlled restarts, for example in order to upgrade the software.
This is how to perform a controlled restart, that works whether AOF is enabled
or not:
1. CONFIG SET aof-enqueue-jobs-once yes
2. CONFIG REWRITE
3. SHUTDOWN REWRITE-AOF
At this point we have a freshly generated AOF on disk, and the server is
configured in order to load the full state only at the next restart
(`aof-enqueue-jobs-once` is automatically turned off after the restart).
We can just restart the server with the new software, or in a new server, and
it will restart with the full state. Note that `aof-enqueue-jobs-once`
implies loading the AOF even if AOF support is switched off, so there is
no need to enable AOF just for the upgrade of an in-memory only server.
Job IDs
---
Disque jobs are uniquely identified by an ID like the following:
D-dcb833cf-8YL1NT17e9+wsA/09NqxscQI-05a1
Job IDs are composed of exactly 40 characters and start with the prefix `D-`.
We can split an ID into multiple parts:
D- | dcb833cf | 8YL1NT17e9+wsA/09NqxscQI | 05a1
1. `D-` is the prefix.
2. `dcb833cf` is the first 8 bytes of the node ID where the message was generated.
3. `8YL1NT17e9+wsA/09NqxscQI` is the 144 bit ID pseudo-random part encoded in base64.
4. `05a1` is the Job TTL in minutes. Because of it, message IDs can be expired safely even without having the job representation.
IDs are returned by ADDJOB when a job is successfully created, are part of
the GETJOB output, and are used in order to acknowledge that a job was
correctly processed by a worker.
Part of the node ID is included in the message so that a worker processing
messages for a given queue can easily guess what are the nodes where jobs
are created, and move directly to these nodes to increase efficiency instead
of listening for messages in a node that will require to fetch messages from
other nodes.
Only 32 bits of the original node ID is included in the message, however
in a cluster with 100 Disque nodes, the probability of two nodes having
identical 32 bit ID prefixes is given by the birthday paradox:
P(100,2^32) = .000001164
In case of collisions, the workers may just make a non-efficient choice.
Collisions in the 144 bits random part are believed to be impossible,
since it is computed as follows.
144 bit ID = HIGH_144_BITS_OF_SHA1(seed || counter)
Where:
* **seed** is a seed generated via `/dev/urandom` at startup.
* **counter** is a 64 bit counter incremented at every ID generation.
So there are 22300745198530623141535718272648361505980416 possible IDs,
selected in a uniform way. While the probability of a collision is non-zero
mathematically, in practice each ID can be regarded as unique.
The encoded TTL in minutes has a special property: it is always even for
at most once jobs (job retry value set to 0), and is always odd otherwise.
This changes the encoded TTL precision to 2 minutes, but allows to tell
if a Job ID is about a job with deliveries guarantees or not.
Note that this fact does not mean that Disque jobs TTLs have a precision of
two minutes. The TTL field is only used to expire job IDs of jobs a given
node does not actually have a copy, search "dummy ACK" in this documentation
for more information.
Setup
===
To play with Disque please do the following:
1. Compile Disque - if you can compile Redis, you can compile Disque, it's the usual "no external deps" thing. Just type `make`. Binaries (`disque` and `disque-server`) will end up in the `src` directory.
2. Run a few Disque nodes on different ports. Create different `disque.conf` files following the example `disque.conf` in the source distribution.
3. After you have them running, you need to join the cluster. Just select a random node among the nodes you are running, and send the command `CLUSTER MEET <ip> <port>` for every other node in the cluster.
**Please note that you need to open two TCP ports on each node**, the base port of the Disque instance, for example 7711, plus the cluster bus port, which is always at a fixed offset, obtained summing 10000 to the base port, so in the above example, you need to open both 7711 and 17711. Disque uses the base port to communicate with clients and the cluster bus port to communicate with other Disque processes.
To run a node, just call `./disque-server`.
For example, if you are running three Disque servers in port 7711, 7712, 7713, in order to join the cluster you should use the `disque` command line tool and run the following commands:
./disque -p 7711 cluster meet 127.0.0.1 7712
./disque -p 7711 cluster meet 127.0.0.1 7713
Your cluster should now be ready. You can try to add a job and fetch it back
in order to test if everything is working:
./disque -p 7711
127.0.0.1:7711> ADDJOB queue body 0
D-dcb833cf-8YL1NT17e9+wsA/09NqxscQI-05a1
127.0.0.1:7711> GETJOB FROM queue
1) 1) "queue"
2) "D-dcb833cf-8YL1NT17e9+wsA/09NqxscQI-05a1"
3) "body"
Remember that you can add and get jobs from different nodes as Disque
is multi master. Also remember that you need to acknowledge jobs otherwise
they'll never go away from the server memory (unless the time-to-live is
reached).
Main API
===
The Disque API is composed of a small set of commands, since the system solves a
single very specific problem. The three main commands are:
#### `ADDJOB queue_name job <ms-timeout> [REPLICATE <count>] [DELAY <sec>] [RETRY <sec>] [TTL <sec>] [MAXLEN <count>] [ASYNC]`
Adds a job to the specified queue. Arguments are as follows:
* *queue_name* is the name of the queue, any string, basically. You don't need to create queues, if a queue does not exist, it gets created automatically. If one has no more jobs, it gets removed.
* *job* is a string representing the job. Disque is job meaning agnostic, for it a job is just a message to deliver. Job max size is 4GB.
* *ms-timeout* is the command timeout in milliseconds. If no ASYNC is specified, and the replication level specified is not reached in the specified number of milliseconds, the command returns with an error, and the node does a best-effort cleanup, that is, it will try to delete copies of the job across the cluster. However the job may still be delivered later. Note that the actual timeout resolution is 1/10 of second or worse with the default server hz.
* *REPLICATE count* is the number of nodes the job should be replicated to.
* *DELAY sec* is the number of seconds that should elapse before the job is queued by any server. By default there is no delay.
* *RETRY sec* period after which, if no ACK is received, the job is put into the queue again for delivery. If RETRY is 0, the job has at-most-once delivery semantics. The default retry time is 5 minutes, with the exception of jobs having a TTL so small that 10% of TTL is less than 5 minutes. In this case the default RETRY is set to TTL/10 (with a minimum value of 1 second).
* *TTL sec* is the max job life in seconds. After this time, the job is deleted even if it was not successfully delivered. If not specified, the default TTL is one day.
* *MAXLEN count* specifies that if there are already *count* messages queued for the specified queue name, the message is refused and an error reported to the client.
* *ASYNC* asks the server to let the command return ASAP and replicate the job to other nodes in the background. The job gets queued ASAP, while normally the job is put into the queue only when the client gets a positive reply.
The command returns the Job ID of the added job, assuming ASYNC is specified, or if the job was replicated correctly to the specified number of nodes. Otherwise an error is returned.
#### `GETJOB [NOHANG] [TIMEOUT <ms-timeout>] [COUNT <count>] [WITHCOUNTERS] FROM queue1 queue2 ... queueN`
Return jobs available in one of the specified queues, or return NULL
if the timeout is reached. A single job per call is returned unless a count greater than 1 is specified. Jobs are returned as a three-element array containing the queue name, the Job ID, and the job body itself. If jobs are available in multiple queues, queues are processed left to right.
If there are no jobs for the specified queues, the command blocks, and messages are exchanged with other nodes, in order to move messages about these queues to this node, so that the client can be served.
Options:
* **NOHANG**: Ask the command to not block even if there are no jobs in all the specified queues. This way the caller can just check if there are available jobs without blocking at all.
* **WITHCOUNTERS**: Return the best-effort count of NACKs (negative acknowledges) received by this job, and the number of additional deliveries performed for this job. See the *Dead Letters* section for more information.
#### `ACKJOB jobid1 jobid2 ... jobidN`
Acknowledges the execution of one or more jobs via job IDs. The node receiving the ACK will replicate it to multiple nodes and will try to garbage collect both the job and the ACKs from the cluster so that memory can be freed.
A node receiving an ACKJOB command about a job ID it does not know will create
a special empty job, with the state set to "acknowledged", called a "dummy ACK".
The dummy ACK is used in order to retain the acknolwedge during a netsplit if
the ACKJOB is sent to a node that does not have a copy of the job. When the
partition heals, job garbage collection will be attempted.
However, since the job ID encodes information about the job being an "at-most-
once" or an "at-least-once" job, the dummy ACK is only created for at-least-
once jobs.
#### `FASTACK jobid1 jobid2 ... jobidN`
Performs a best-effort cluster-wide deletion of the specified job IDs. When the
network is well connected and there are no node failures, this is equivalent to
`ACKJOB` but much faster (due to less messages being exchanged), however during
failures it is more likely that fast acknowledges will result in multiple
deliveries of the same messages.
#### `WORKING jobid`
Claims to be still working with the specified job, and asks Disque to postpone
the next time it will deliver the job again. The next delivery is postponed
for the job retry time, however the command works in a **best effort** way
since there is no way to guarantee during failures that another node in a
different network partition won't perform a delivery of the same job.
Another limitation of the `WORKING` command is that it cannot be sent to
nodes not knowing about this particular job. In such a case the command replies
with a `NOJOB` error. Similarly, if the job is already acknowledged an error
is returned.
Note that the `WORKING` command is refused by Disque nodes if 50% of the job
time to live has already elapsed. This limitation makes Disque safer since
usually the *retry* time is much smaller than the time-to-live of a job, so
it can't happen that a set of broken workers monopolize a job with `WORKING`
and never process it. After 50% of the TTL has elapsed, the job will be delivered
to other workers anyway.
Note that `WORKING` returns the number of seconds you (likely) postponed the
message visibility for other workers (the command basically returns the
*retry* time of the job), so the worker should make sure to send the next
`WORKING` command before this time elapses. Moreover, a worker that may want
to use this interface may fetch the retry value with the `SHOW` command
when starting to process a message, or may simply send a `WORKING` command
ASAP, like in the following example (in pseudo code):
retry = WORKING(jobid)
RESET timer
WHILE ... work with the job still not finished ...
IF timer reached 80% of the retry time
WORKING(jobid)
RESET timer
END
END
#### `NACK <job-id> ... <job-id>`
The `NACK` command tells Disque to put the job back in the queue ASAP. It
is very similar to `ENQUEUE` but it increments the job `nacks` counter
instead of the `additional-deliveries` counter. The command should be used
when the worker was not able to process a message and wants the message to
be put back into the queue in order to be processed again.
Other commands
===
#### `INFO`
Generic server information / stats.
#### `HELLO`
Returns hello format version, this node ID, all the nodes IDs, IP addresses,
ports, and priority (lower is better, means a node is more available).
Clients should use this as a handshake command when connecting with a
Disque node.
#### `QLEN <queue-name>`
Return the length of the queue.
#### `QSTAT <queue-name>`
Show information about a queue as an array of key-value pairs.
Below is an example of the output, however, implementations should not rely
on the order of the fields nor on the existence of the fields listed.
They may be (unlikely) removed or more can be (likely) added
in the future.
If a queue does not exist, NULL is returned. Note that queues are
automatically evicted after some time if empty and without clients blocked
waiting for jobs, even if there are active jobs for the queue. So the
non existence of a queue does not mean there are not jobs in the node
or in the whole cluster about this queue. The queue will be immediately
created again when needed to serve requests.
Example output:
```
QSTAT foo
1) "name"
2) "foo"
3) "len"
4) (integer) 56520
5) "age"
6) (integer) 601
7) "idle"
8) (integer) 3
9) "blocked"
10) (integer) 50
11) "import-from"
12) 1) "dcb833cf8f42fbb7924d92335ff6d67d3cea6e3d"
2) "4377bdf656040a18d8caf4d9f409746f1f9e6396"
13) "import-rate"
14) (integer) 19243
15) "jobs-in"
16) (integer) 3462847
17) "jobs-out"
18) (integer) 3389522
19) "pause"
20) "none"
```
Most fields should be obvious. The `import-from` field shows a list of node
IDs this node is importing jobs from, for this queue, in order to serve
clients requests. The `import-rate` is the instantaneous amount of jos/sec
we import in order to handle our outgoing traffic (GETJOB commands).
`blocked` is the number of clients blocked on this queue right now.
`age` and `idle` are reported in seconds. The `jobs-in` and `-out` counters are
incremented every time a job is enqueued or dequeued for any reason.
#### `QPEEK <queue-name> <count>`
Return, without consuming from the queue, *count* jobs. If *count* is positive
the specified number of jobs are returned from the oldest to the newest
(in the same best-effort FIFO order as GETJOB). If *count* is negative the
commands changes behavior and shows the *count* newest jobs, from the newest
from the oldest.
#### `ENQUEUE <job-id> ... <job-id>`
Queue jobs if not already queued.
#### `DEQUEUE <job-id> ... <job-id>`
Remove the job from the queue.
#### `DELJOB <job-id> ... <job-id>`
Completely delete a job from a node.
Note that this is similar to `FASTACK`, but limited to a single node since
no `DELJOB` cluster bus message is sent to other nodes.
#### `SHOW <job-id>`
Describe the job.
#### `QSCAN [COUNT <count>] [BUSYLOOP] [MINLEN <len>] [MAXLEN <len>] [IMPORTRATE <rate>]`
The command provides an interface to iterate all the existing queues in
the local node, providing a cursor in the form of an integer that is passed
to the next command invocation. During the first call, the cursor must be 0,
in the next calls the cursor returned in the previous call is used in the
next. The iterator guarantees to return all the elements but may return
duplicated elements.
Options:
* `COUNT <count>` A hint about how much work to do per iteration.
* `BUSYLOOP` Block and return all the elements in a busy loop.
* `MINLEN <count>` Don't return elements with less than `count` jobs queued.
* `MAXLEN <count>` Don't return elements with more than `count` jobs queued.
* `IMPORTRATE <rate>` Only return elements with a job import rate (from other nodes) `>=` `rate`.
The cursor argument can be in any place, the first non matching option
that has valid cursor form of an unsigned number will be sensed as a valid
cursor.
#### `JSCAN [<cursor>] [COUNT <count>] [BUSYLOOP] [QUEUE <queue>] [STATE <state1> STATE <state2> ... STATE <stateN>] [REPLY all|id]`
The command provides an interface to iterate all the existing jobs in
the local node, providing a cursor in the form of an integer that is passed
to the next command invocation. During the first call the cursor must be 0,
in the next calls the cursor returned in the previous call is used in the
next. The iterator guarantees to return all the elements but may return
duplicated elements.
Options:
* `COUNT <count>` A hint about how much work to do per iteration.
* `BUSYLOOP` Block and return all the elements in a busy loop.
* `QUEUE <queue>` Return only jobs in the specified queue.
* `STATE <state>` Return jobs in the specified state. Can be used multiple times for a logical OR.
* `REPLY <type>` Job reply type. Type can be `all` or `id`. Default is to report just the job ID. If `all` is specified the full job state is returned like for the SHOW command.
The cursor argument can be in any place, the first non matching option
that has valid cursor form of an unsigned number will be sensed as a valid
cursor.
#### `PAUSE <queue-name> option1 [option2 ... optionN]`
Control the paused state of a queue, possibly broadcasting the command to
other nodes in the cluster. Disque queues can be paused in both directions,
input and output, or both. Pausing a queue makes it unavailable for input
or output operations. Specifically:
A queue paused in input will have changed behavior in the following ways:
1. ADDJOB returns a `-PAUSED` error for queues paused in input.
2. The node where the queue is paused, no longer accepts to replicate jobs for this queue when requested by other nodes. Since ADDJOB by default uses synchronous replication, it means that if the queue is paused in enough nodes, adding jobs with a specified level of replication may fail. In general the node where the queue is paused will not create new jobs in the local node about this queue.
3. The job no longer accepts ENQUEUE messages from other nodes. Those messages are usually used by nodes in out of memory conditions that replicate jobs externally (not holding a copy), in order to put the job in the queue of some random node, among the nodes having a copy of a job.
4. Active jobs that reach their retry time, are not put back into the queue. Instead their retry timer is updated and the node will try again later.
Basically a queue paused in input never creates new jobs for this queue, and never puts active jobs (jobs for which the node has a copy but are not currently queued) back in the queue, for all the time the queue is paused.
A queue paused in output instead will behave in the following way:
1. GETJOB will block even if there are jobs available in the specified queue, instead of serving the jobs. But GETJOB will unblock if the queue output pause is cleared later.
2. The node will not provide jobs to other nodes in the context of node federation, for paused queues.
So a queue paused in output will stop acting as a source of messages for both
local and non local clients.
The paused state can be set for each queue using the PAUSE command followed
by options to specify how to change the paused state. Possible options are:
* **in**: pause the queue in input.
* **out**: pause the queue in output.
* **all**: pause the queue in input and output (same as specifying both the **in** and **out** options).
* **none**: clear the paused state in input and output.
* **state**: just report the current queue state.
* **bcast**: send a PAUSE command to all the reachable nodes of the cluster to set the same queue in the other nodes to the same state.
The command always returns the state of the queue after the execution of the specified options, so the return value is one of **in**, **out**, **all**, **none**.
Queues paused in input or output are never evicted to reclaim memory, even if
they are empty and inactive for a long time, since otherwise the paused state
would be forgotten.
For example, in order to block output for the queue `myqueue` in all the
currently reachable nodes, the following command should be send to a single node:
PAUSE myqueue out bcast
To specify **all** is the same as to specify both **in** and **out**, so the two following
forms are equivalent:
PAUSE myqueue in out
PAUSE myqueue all
To just get the current state use:
PAUSE myqueue state
"none"
Special handling of messages with RETRY set to 0
===
In order to provide a coherent API, messages with at-most-once delivery
semantics are still retained after being delivered a first time, and should
be acknowledged like any other message. Of course, the acknowledge is not
mandatory, since the message may be lost and there is no way for the receiver
to get the same message again, since the message is associated with a retry
value of 0.
In order to avoid non acknowledged messages with retry set to 0 from leaking
into Disque and eating all the memory, when the Disque server memory is full
and starts to evict, it does not just evict acknowledged messages, but also
can evict non acknowledged messages having, at the same time, the following
two properties:
1. Their retry is set to 0.
2. The job was already delivered.
In theory, acknowledging a job that will never be retried is a waste of time
and resources, however this design has hidden advantages:
1. The API is exactly the same for all the kinds of jobs.
2. After the job is delivered, it is still possible to examine it. Observability is a very good property of messaging systems.
However, not acknowledging the job does not result in big issues since they
are evicted eventually during memory pressure.
Adding and removing nodes at runtime
===
Adding nodes is trivial, and just consists in starting a new node and sending it
a `CLUSTER MEET` command. Assuming the node you just started is located
at address 192.168.1.10 port 7714, and a random (you can use any) node of
the existing cluster is located at 192.168.1.9 port 7711, all you need to do
is:
./disque -h 192.168.1.10 -p 7714 cluster meet 192.168.1.9 7711
Note that you can invert the source and destination arguments and the
new node will still join the cluster. It does not matter if it's the old node to
meet the new one or the other way around.
In order to remove a node, it is possible to use the crude way of just
shutting it down, and then use `CLUSTER FORGET <old-node-id>` in all the
other nodes in order to remove references to it from the configuration of
the other nodes. However this means that, for example, messages that had
a replication factor of 3, and one of the replicas was the node you are
shutting down, suddenly are left with just 2 replicas even if no *actual*
failure happened. Moreover if the node you are removing had messages in
queue, you'll need to wait the retry time before the messages will be
queued again. For all these reasons, Disque has a better way to remove nodes
which is described in the next section.
Gracefully removal of nodes
===
In order to empty a node of its content before removing it, it is possible
to use a feature that puts a node in *leaving* state. To enable this feature
just contact the node to remove, and use the following command:
CLUSTER LEAVING yes
The node will start advertising itself as *leaving*, so in a matter of seconds
all the cluster will know (if there are partitions, when the partition heals
all the nodes will eventually be informed), and this is what happens
when the node is in this state:
1. When the node receives `ADDJOB` commands, it performs external replication, like when a node is near the memory limits. This means that it will make sure
to create the number of replicas of the message in the cluster **without using itself** as a replica. So no new messages are created in the context of a node which is leaving.
2. The node starts to send `-LEAVING` messages to all clients that use `GETJOB` but would block waiting for jobs. The `-LEAVING` error means the clients should connect to another node. Clients that were already blocked waiting for messages will be unblocked and a `-LEAVING` error will be sent to them as well.
3. The node no longer sends `NEEDJOBS` messages in the context of Disque federation, so it will never ask other nodes to transfer messages to it.
4. The node and all the other nodes will advertise it with a bad priority in the `HELLO` command output, so that clients will select a different node.
5. The node will no longer create *dummy acks* in response to an `ACKJOB` command about a job it does not know.
All these behavior changes result in the node participating only as a source of messages, so eventually its message count will drop to zero (it is possible to check for this condition using `INFO jobs`). When this happens the node can be stopped and removed from the other nodes tables using `CLUSTER FORGET` as described in the section above.
Client libraries
===
Disque uses the same protocol as Redis itself. To adapt Redis clients, or to use them directly, should be pretty easy. However note that Disque's default port is 7711 and not 6379.
While a vanilla Redis client may work well with Disque, clients should optionally use the following protocol in order to connect with a Disque cluster:
1. The client should be given a number of IP addresses and ports where nodes are located. The client should select random nodes and should try to connect until an available one is found.
2. On a successful connection the `HELLO` command should be used in order to retrieve the Node ID and other potentially useful information (server version, number of nodes).
3. If a consumer sees a high message rate received from foreign nodes, it may optionally have logic in order to retrieve messages directly from the nodes where producers are producing the messages for a given topic. The consumer can easily check the source of the messages by checking the Node ID prefix in the messages IDs.
4. The `GETJOB` command, or other commands, may return a `-LEAVING` error instead of blocking. This error should be considered by the client library as a request to connect to a different node, since the node it is connected to is not able to serve the request since it is leaving the cluster. Nodes in this state have a very high *priority* number published via `HELLO`, so will be unlikely to be picked at the next connection attempt.
This way producers and consumers will eventually try to minimize node message exchanges whenever possible.
So basically you could perform basic usage using just a Redis client, however
there are already specialized client libraries implementing a more specialized
API on top of Disque:
*C++*
- [disque C++ client](https://github.com/zhengshuxin/acl/tree/master/lib_acl_cpp/samples/disque)
*Common Lisp*
- [cl-disque](https://github.com/CodyReichert/cl-disque)
*Elixir*
- [exdisque](https://github.com/mosic/exdisque)
*Erlang*
- [edisque](https://github.com/nacmartin/edisque)
*Go*
- [disque-go](https://github.com/zencoder/disque-go)
- [go-disque](https://github.com/EverythingMe/go-disque)
- [disque](https://github.com/goware/disque)
*Java*
- [jedisque](https://github.com/xetorthio/jedisque)
- [spinach](https://github.com/mp911de/spinach)
*Node.js*
- [disque.js](https://www.npmjs.com/package/disque.js)
- [thunk-disque](https://github.com/thunks/thunk-disque)
- [disqueue-node](https://www.npmjs.com/package/disqueue-node)
*Perl*
- [perl-disque](https://github.com/lovelle/perl-disque)
*PHP*
- [phpque](https://github.com/s12v/phpque) (PHP/HHVM)
- [disque-php](https://github.com/mariano/disque-php) ([Composer/Packagist](https://packagist.org/packages/mariano/disque-php))
- [disque-client-php](https://github.com/mavimo/disque-client-php) ([Composer/Packagist](https://packagist.org/packages/mavimo/disque-client))
- [phloppy](https://github.com/0x20h/phloppy) ([Composer/Packagist](https://packagist.org/packages/0x20h/phloppy))
*Python*
- [disq](https://github.com/ryansb/disq) ([PyPi](https://pypi.python.org/pypi/disq))
- [pydisque](https://github.com/ybrs/pydisque) ([PyPi](https://pypi.python.org/pypi/pydisque))
- [django-q](https://github.com/koed00/django-q) ([PyPi](https://pypi.python.org/pypi/django-q))
*Ruby*
- [disque-rb](https://github.com/soveran/disque-rb)
- [disque_jockey](https://github.com/DevinRiley/disque_jockey)
- [Disc](https://github.com/pote/disc)
*Rust*
- [disque-rs](https://github.com/seppo0010/disque-rs)
*.NET*
- [Disque.Net](https://github.com/ziyasal/Disque.Net)
Implementation details
===
Job replication strategy
---
1. Disque tries to replicate to W-1 (or W during out of memory) reachable nodes, shuffled.
2. The cluster REPLJOB message is used to replicate a job to multiple nodes, the job is sent together with the list of nodes that may have a copy.
2. If the required replication is not reached promptly, the job is send to one additional node every 50 milliseconds. When this happens, a new REPLJOB message is also re-sent to each node that may already have a copy, in order to refresh the list of nodes that have a copy.
3. If the specified synchronous replication timeout is reached, the node that originally received the ADDJOB command from the client gives up and returns an error to the client. When this happens the node performs a best-effort procedure to delete the job from nodes that may have already received a copy of the job.
Cluster topology
---
Disque is a full mesh, with each node connected to each other. Disque performs
distributed failure detection via gossip, only in order to adjust the
replication strategy (try reachable nodes first when trying to replicate
a message), and in order to inform clients about non reachable nodes when
they want the list of nodes they can connect to.
As Disque is multi-master, the event of nodes failing is not handled in any
special way.
Cluster messages
---
Nodes communicate via a set of messages, using the node-to-node message bus.
A few of the messages are used in order to check that other nodes are
reachable and to mark nodes as failing. Those messages are PING, PONG and
FAIL. Since failure detection is only used to adjust the replication strategy
(talk with reachable nodes first in order to improve latency), the details
are yet not described. Other messages are more important since they are used
in order to replicate jobs, re-issue jobs while trying to minimize multiple
deliveries, and in order to auto-federate to serve consumers when messages
are produced in different nodes compared to where consumers are.
The following is a list of messages and what they do, split by category.
Note that this is just an informal description, while in the next sections
describing the Disque state machine, there is a more detailed description
of the behavior caused by message reception, and in what cases they are
generated.
Cluster messages related to jobs replication and queueing
---
* REPLJOB: ask the receiver to replicate a job, that is, to add a copy of the job among the registered jobs in the target node. When a job is accepted, the receiver replies with GOTJOB to the sender. A job may not be accepted if the receiving node is near out of memory. In this case GOTJOB is not sent and the message discarded.
* GOTJOB: The reply to REPLJOB to confirm the job was replicated.
* ENQUEUE: Ask a node to put a given job into its queue. This message is used when a job is created by a node that does not want to take a copy, so it asks another node (among the ones that acknowledged the job replication) to queue it for the first time. If this message is lost, after the retry time some node will try to re-queue the message, unless retry is set to zero.
* WILLQUEUE: This message is sent 500 milliseconds before a job is re-queued to all the nodes that may have a copy of the message, according to the sender table. If some of the receivers already have the job queued, they'll reply with QUEUED in order to prevent the sender to queue the job again (avoid multiple delivery when possible).
* QUEUED: When a node re-queues a job, it sends QUEUED to all the nodes that may have a copy of the message, so that the other nodes will update the time at which they'll retry to queue the job. Moreover, every node that already has the same job in queue, but with a node ID which is lexicographically smaller than the sending node, will de-queue the message in order to best-effort de-dup messages that may be queued in multiple nodes at the same time.
Cluster messages related to ACK propagation and garbage collection
---
* SETACK: This message is sent to force a node to mark a job as successfully delivered (acknowledged by the worker): the job will no longer be considered active, and will never be re-queued by the receiving node. Also SETACK is send to the sender if the receiver of QUEUED or WILLQUEUE message has the same job marked as acknowledged (successfully delivered) already.
* GOTACK: This message is sent in order to acknowledge a SETACK message. The receiver can mark a given node that may have a copy of a job, as informed about the fact that the job was acknowledged by the worker. Nodes delete (garbage collect) a message cluster wide when they believe all the nodes that may have a copy are informed about the fact the job was acknowledged.
* DELJOB: Ask the receiver to remove a job. Is only sent in order to perform garbage collection of jobs by nodes that are sure the job was already delivered correctly. Usually the node sending DELJOB only does that when its sure that all the nodes that may have a copy of the message already marked the message ad delivered, however after some time the job GC may be performed anyway, in order to reclaim memory, and in that case, an otherwise avoidable multiple delivery of a job may happen. The DELJOB message is also used in order to implement *fast acknowledges*.
Cluster messages related to nodes federation
---
* NEEDJOBS(queue,count): The sender asks the receiver to obtain messages for a given queue, possibly *count* messages, but this is only an hit for congestion control and messages optimization, the receiver is free to reply with whatever number of messages. NEEDJOBS messages are delivered in two ways: broadcasted to every node in the cluster from time to time, in order to discover new source nodes for a given queue, or more often, to a set of nodes that recently replies with jobs for a given queue. This latter mechanism is called an *ad hoc* delivery, and is possible since every node remembers for some time the set of nodes that were recent providers of messages for a given queue. In both cases, NEEDJOBS messages are delivered with exponential delays, with the exception of queues that drop to zero-messages and have a positive recent import rate, in this case an ad hoc NEEDJOBS delivery is performed regardless of the last time the message was delivered in order to allow a continuous stream of messages under load.
* YOURJOBS(array of messages): The reply to NEEDJOBS. An array of serialized jobs, usually all about the same queue (but future optimization may allow to send different jobs from different queues). Jobs into YOURJOBS replies are extracted from the local queue, and queued at the receiver node's queue with the same name. So even messages with a retry set to 0 (at most once delivery) still guarantee the safety rule since a given message may be in the source node, on the wire, or already received in the destination node. If a YOURJOBS message is lost, at least once delivery jobs will be re-queued later when the retry time is reached.
Disque state machine
---
This section shows the most interesting (as in less obvious) parts of the state machine each Disque node implements. While practically it is a single state machine, it is split in sections. The state machine description uses a convention that is not standard but should look familiar, since it is event driven, made of actions performed upon: message receptions in the form of commands received from clients, messages received from other cluster nodes, timers, and procedure calls.
Note that: `job` is a job object with the following fields:
1. `job.delivered`: A list of nodes that may have this message. This list does not need to be complete, is used for best-effort algorithms.
2. `job.confirmed`: A list of nodes that confirmed reception of ACK by replying with a GOTJOB message.
3. `job.id`: The job 48 chars ID.
4. `job.state`: The job state among: `wait-repl`, `active`, `queued`, `acked`.
5. `job.replicate`: Replication factor for this job.
5. `job.qtime`: Time at which we need to re-queue the job.
List fields such as `.delivered` and `.confirmed` support methods like `.size` to get the number of elements.
States are as follows:
1. `wait-repl`: the job is waiting to be synchronously replicated.
2. `active`: the job is active, either it reached the replication factor in the originating node, or it was created because the node received an `REPLJOB` message from another node.
3. `queued`: the job is active and also is pending into a queue in this node.
4. `acked`: the job is no longer active since a client confirmed the reception using the `ACKJOB` command or another Disque node sent a `SETACK` message for the job.
Generic functions
---
PROCEDURE `LOOKUP-JOB(string job-id)`:
1. If job with the specified id is found, returns the corresponding job object.
2. Otherwise returns NULL.
PROCEDURE `UNREGISTER(object job)`:
1. Delete the job from memory, and if queued, from the queue.
PROCEDURE `ENQUEUE(job)`:
1. If `job.state == queued` return ASAP.
2. Add `job` into `job.queue`.
3. Change `job.state` to `queued`.
PROCEDURE `DEQUEUE(job)`:
1. If `job.state != queued` return ASAP.
2. Remove `job` from `job.queue`.
3. Change `job.state` to `active`.
ON RECV cluster message: `DELJOB(string job.id)`:
1. job = Call `LOOKUP-JOB(job-id)`.
2. IF `job != NULL` THEN call `UNREGISTER(job)`.
Job replication state machine
---
This part of the state machine documents how clients add jobs to the cluster
and how the cluster replicates jobs across different Disque nodes.
ON RECV client command `ADDJOB(string queue-name, string body, integer replicate, integer retry, integer ttl, ...):
1. Create a job object in `wait-repl` state, having as body, ttl, retry, queue name, the specified values.
2. Send REPLJOB(job.serialized) cluster message to `replicate-1` nodes.
3. Block the client without replying.
Step 3: We'll reply to the client in step 4 of `GOTJOB` message processing.
ON RECV cluster message `REPLJOB(object serialized-job)`:
1. job = Call `LOOKUP-JOB(serialized-job.id)`.
2. IF `job != NULL` THEN: job.delivered = UNION(job.delivered,serialized-job.delivered). Return ASAP, since we have the job.
3. Create a job from serialized-job information.
4. job.state = `active`.
5. Reply to the sender with `GOTJOB(job.id)`.
Step 1: We may already have the job, since REPLJOB may be duplicated.
Step 2: If we already have the same job, we update the list of jobs that may have a copy of this job, performing the union of the list of nodes we have with the list of nodes in the serialized job.
ON RECV cluster message `GOTJOB(object serialized-job)`:
1. job = Call `LOOKUP-JOB(serialized-job.id)`.
2. IF `job == NULL` OR `job.state != wait-repl` Return ASAP.
3. Add sender node to `job.confirmed`.
4. IF `job.confirmed.size == job.replicate` THEN change `job.state` to `active`, call ENQUEUE(job), and reply to the blocked client with `job.id`.
Step 4: As we receive enough confirmations via `GOTJOB` messages, we finally reach the replication factor required by the user and consider the message active.
TIMER, firing every next 50 milliseconds while a job still did not reached the expected replication factor.
1. Select an additional node not already listed in `job.delivered`, call it `node`.
2. Add `node` to `job.delivered`.
3. Send REPLJOB(job.serialized) cluster message to each node in `job.delivered`.
Step 3: We send the message to every node again, so that each node will have a chance to update `job.delivered` with the new nodes. It is not required for each node to know the full list of nodes that may have a copy, but doing so improves our approximation of single delivery whenever possible.
Job re-queueing state machine
---
This part of the state machine documents how Disque nodes put a given job
back into the queue after the specified retry time elapsed without the
job being acknowledged.
TIMER, firing 500 milliseconds before the retry time elapses:
1. Send `WILLQUEUE(job.id)` to every node in `jobs.delivered`.
TIMER, firing when `job.qtime` time is reached.
1. If `job.retry == 0` THEN return ASAP.
2. Call ENQUEUE(job).
3. Update `job.qtime` to NOW + job.retry.
4. Send `QUEUED(job.id)` message to each node in `job.delivered`.
Step 1: At most once jobs never get enqueued again.
Step 3: We'll retry again after the retry period.
ON RECV cluster message `WILLQUEUE(string job-id)`:
1. job = Call `LOOKUP-JOB(job-id)`.
2. IF `job == NULL` THEN return ASAP.
3. IF `job.state == queued` SEND `QUEUED(job.id)` to `job.delivered`.
4. IF `job.state == acked` SEND `SETACK(job.id)` to the sender.
Step 3: We broadcast the message since likely the other nodes are going to retry as well.
Step 4: SETACK processing is documented below in the acknowledges section of the state machine description.
ON RECV cluster message `QUEUED(string job-id)`:
1. job = Call `LOOKUP-JOB(job-id)`.
2. IF `job == NULL` THEN return ASAP.
3. IF `job.state == acked` THEN return ASAP.
4. IF `job.state == queued` THEN if sender node ID is greater than my node ID call DEQUEUE(job).
5. Update `job.qtime` setting it to NOW + job.retry.
Step 4: If multiple nodes re-queue the job about at the same time because of race conditions or network partitions that make `WILLQUEUE` not effective, then `QUEUED` forces receiving nodes to dequeue the message if the sender has a greater node ID, lowering the probability of unwanted multiple delivery.
Step 5: Now the message is already queued somewhere else, but the node will retry again after the retry time.
Acknowledged jobs garbage collection state machine
---
This part of the state machine is used in order to garbage collect
acknowledged jobs, when a job finally gets acknowledged by a client.
PROCEDURE `ACK-JOB(job)`:
1. If job state is already `acked`, do nothing and return ASAP.
2. Change job state to `acked`, dequeue the job if queued, schedule first call to TIMER.
PROCEDURE `START-GC(job)`:
1. Send `SETACK(job.delivered.size)` to each node that is listed in `job.delivered` but is not listed in `job.confirmed`.
2. IF `job.delivered.size == 0`, THEN send `SETACK(0)` to every node in the cluster.
Step 2: this is an ACK about a job we don’t know. In that case, we can just broadcast the acknowledged hoping somebody knows about the job and replies.
ON RECV client command `ACKJOB(string job-id)`:
1. job = Call `LOOKUP-JOB(job-id)`.
1. if job is `NULL`, ignore the message and return.
2. Call `ACK-JOB(job)`.
3. Call `START-GC(job)`.
ON RECV cluster message `SETACK(string job-id, integer may-have)`:
1. job = Call `LOOKUP-JOB(job-id)`.
2. Call ACK-JOB(job) IF job is not `NULL`.
3. Reply with GOTACK IF `job == NULL OR job.delivered.size <= may-have`.
4. IF `job != NULL` and `jobs.delivered.size > may-have` THEN call `START-GC(job)`.
5. IF `may-have == 0 AND job != NULL`, reply with `GOTACK(1)` and call `START-GC(job)`.
Steps 3 and 4 makes sure that among the reachable nodes that may have a message, garbage collection will be performed by the node that is aware of more nodes that may have a copy.
Step 5 instead is used in order to start a GC attempt if we received a SETACK message from a node just hacking a dummy ACK (an acknowledge about a job it was not aware of).
ON RECV cluster message `GOTACK(string job-id, bool known)`:
1. job = Call `LOOKUP-JOB(job-id)`. Return ASAP IF `job == NULL`.
2. Call `ACK-JOB(job)`.
3. IF `known == true AND job.delivered.size > 0` THEN add the sender node to `job.delivered`.
4. IF `(known == true) OR (known == false AND job.delivered.size > 0) OR (known == false AND sender is an element of job.delivered)` THEN add the sender node to `jobs.confirmed`.
5. IF `job.delivered.size > 0 AND job.delivered.size == job.confirmed.size`, THEN send `DELJOB(job.id)` to every node in the `job.delivered` list and call `UNREGISTER(job)`.
6. IF `job.delivered == 0 AND known == true`, THEN call `UNREGISTER(job)`.
7. IF `job.delivered == 0 AND job.confirmed.size == cluster.size` THEN call `UNREGISTER(job)`.
Step 3: If `job.delivered.size` is zero, it means that the node just holds a *dummy ack* for the job. It means the node has an acknowledged job it created on the fly because a client acknowledged (via ACKJOB command) a job it was not aware of.
Step 6: we don't have to hold a dummy acknowledged jobs if there are nodes that have the job already acknowledged.
Step 7: this happens when nobody knows about a job, like when a client acknowledged a wrong job ID.
TIMER, from time to time (exponential backoff with random error), for every acknowledged job in memory:
1. call `START-GC(job)`.
Limitations
===
* Disque is new code, not tested, and will require quite some time to reach production quality. It is likely very buggy and may contain wrong assumptions or tradeoffs.
* As long as the software is non stable, the API may change in random ways without prior notification.
* It is possible that Disque spends too much effort in approximating single delivery during failures. The **fast acknowledge** concept and command makes the user able to opt-out this efforts, but yet I may change the Disque implementation and internals in the future if I see the user base really not caring about multiple deliveries during partitions.
* There is yet a lot of Redis dead code inside probably that could be removed.
* Disque was designed a bit in *astronaut mode*, not triggered by an actual use case of mine, but more in response to what I was seeing people doing with Redis as a message queue and with other message queues. However I'm not an expert, if I succeeded to ship something useful for most users, this is kinda of an accomplishment. Otherwise it may just be that Disque is pretty useless.
* As Redis, Disque is single threaded. While in Redis there are stronger reasons to do so, in Disque there is no manipulation of complex data structures, so maybe in the future it should be moved into a threaded server. We need to see what happens in real use cases in order to understand if it's worth it or not.
* The number of jobs in a Disque process is limited to the amount of memory available. Again while this in Redis makes sense (IMHO), in Disque there are definitely simple ways in order to circumvent this limitation, like logging messages on disk when the server is out of memory and consuming back the messages when memory pressure is already acceptable. However in general, like in Redis, manipulating data structures in memory is a big advantage from the point of view of the implementation simplicity and the functionality we can provide to users.
* Disque is completely not optimized for speed, was never profiled so far. I'm currently not aware of the fact it's slow, fast, or average, compared to other messaging solutions. For sure it is not going to have Redis-alike numbers because it does a lot more work at each command. For example when a job is added, it is serialized and transmitted to other `N` servers. There is a lot more message passing between nodes involved, and so forth. The good news is that being totally unoptimized, there is room for improvements.
* Ability of federation to handle well low and high loads without incurring into congestion or high latency, was not tested well enough. The algorithm is reasonable but may fail short under many load patterns.
* Amount of tested code path and possible states is not enough.
FAQ
===
Is Disque part of Redis?
---
No, it is a standalone project, however a big part of the Redis networking source code, nodes message bus, libraries, and the client protocol, were reused in this new project. In theory it was possible to extract the common code and release it as a framework to write distributed systems in C. However this is not a perfect solution as well, since the projects are expected to diverge more and more in the future, and to rely on a common foundation was hard. Moreover the initial effort to turn Redis into two different layers: an abstract server, networking stack and cluster bus, and the actual Redis implementation, was a huge effort, ways bigger than writing Disque itself.
However while it is a separated project, conceptually Disque is related to Redis, since it tries to solve a Redis use case in a vertical, ad-hoc way.
Who created Disque?
---
Disque is a side project of Salvatore Sanfilippo, aka @antirez.
There are chances for this project to be actively developed?
---
Currently I consider this just a public alpha: If I see people happy to use it for the right reasons (i.e. it is better in some use cases compared to other message queues) I'll continue the development. Otherwise it was anyway cool to develop it, I had much fun, and I definitely learned new things.
What happens when a node runs out of memory?
---
1. Maxmemory setting is mandatory in Disque, and defaults to 1GB.
2. When 75% of maxmemory is reached, Disque starts to replicate the new jobs only to external nodes, without taking a local copy, so basically if there is free RAM into other nodes, adding still works.
3. When 95% of maxmemory is reached, Disque starts to evict data that does not violates the safety guarantees: For instance acknowledged jobs and inactive queues.
4. When 100% of maxmemory is reached, commands that may result into more memory used are not processed at all and the client is informed with an error.
Are there plans to add the ability to hold more jobs than the physical memory of a single node can handle?
---
Yes. In Disque it should be relatively simple to use the disk when memory is not
available, since jobs are immutable and don't need to necessarily exist in
memory at a given time.
There are multiple strategies available. The current idea is that
when an instance is out of memory, jobs are stored into a log file instead
of memory. As more free memory is available in the instance, on disk jobs
are loaded.
However in order to implement this, there is to observe strong evidence of its
general usefulness for the user base.
When I consume and produce from different nodes, sometimes there is a delay in order for the jobs to reach the consumer, why?
---
Disque routing is not static, the cluster automatically tries to provide
messages to nodes where consumers are attached. When there is an high
enough traffic (even one message per second is enough) nodes remember other
nodes that recently were sources for jobs in a given queue, so it is possible
to aggressively send messages asking for more jobs, every time there are
consumers waiting for more messages and the local queue is empty.
However when the traffic is very low, informations about recent sources of
messages are discarded, and nodes rely on a more generic mechanism in order to
discover other nodes that may have messages in the queues we need them (which
is also used in high traffic conditions as well, in order to discover new
sources of messages for a given queue).
For example imagine a setup with two nodes, A and B.
1. A client attaches to node A and asks for jobs in the queue `myqueue`. Node A has no jobs enqueued, so the client is blocked.
2. After a few seconds another client produces messages into `myqueue`, but sending them to node B.
During step `1` if there was no recent traffic of imported messages for this queue, node A has no idea about who may have messages for the queue `myqueue`. Every other node may have, or none may have. So it starts to broadcast `NEEDJOBS` messages to the whole cluster. However we can't spam the cluster with messages, so if no reply is received after the first broadcast, the next will be sent with a larger delay, and so foth. The delay is exponential, with a maximum value of 30 seconds (this parameters will be configurable in the future, likely).
When there is some traffic instead, nodes send `NEEDJOBS` messages ASAP to other nodes that were recent sources of messages. Even when no reply is received, the next `NEEDJOBS` messages will be sent more aggressively to the subset of nodes that had messages in the past, with a delay that starts at 25 milliseconds and has a maximum value of two seconds.
In order to minimize the latency, `NEEDJOBS` messages are not throttled at all when:
1. A client consumed the last message from a given queue. Source nodes are informed immediately in order to receive messages before the node asks for more.
2. Blocked clients are served the last message available in the queue.
For more information, please refer to the file `queue.c`, especially the function `needJobsForQueue` and its callers.
Are messages re-enqueued in the queue tail or head or what?
---
Messages are put into the queue according to their *creation time* attribute. This means that they are enqueued in a best effort order in the local node queue. Messages that need to be put back into the queue again because their delivery failed are usually (but not always) older than messages already in queue, so they'll likely be among the first to be delivered to workers.
What Disque means?
---
DIStributed QUEue but is also a joke with "dis" as negation (like in *dis*order) of the strict concept of queue, since Disque is not able to guarantee the strict ordering you expect from something called *queue*. And because of this tradeof it gains many other interesting things.
Community: how to get help and how to help
===
Get in touch with us in one of the following ways:
1. Post on [Stack Overflow](http://stackoverflow.com) using the `disque` tag. This is the preferred method to get general help about Disque: other users will easily find previous questions so we can incrementally build a knowledge base.
2. Join the `#disque` IRC channel at **irc.freenode.net**.
3. Create an Issue or Pull request if your question or issue is about the Disque implementation itself.
Thanks
===
I would like to say thank you to the following persons and companies.
* Pivotal, for allowing me to work on Disque, most in my spare time, but sometimes during work hours. Moreover Pivotal agreed to leave the copyright of the code to me. This is very generous. Thanks Pivotal!
* Michel Martens and Damian Janowski for providing early feedback about Disque while the project was still private.
* Everybody who is already writing client libraries, sending pull requests, creating issues in order to move this forward from alpha to something actually usable.
================================================
FILE: deps/Makefile
================================================
# Redis dependency Makefile
uname_S:= $(shell sh -c 'uname -s 2>/dev/null || echo not')
CCCOLOR="\033[34m"
LINKCOLOR="\033[34;1m"
SRCCOLOR="\033[33m"
BINCOLOR="\033[37;1m"
MAKECOLOR="\033[32;1m"
ENDCOLOR="\033[0m"
default:
@echo "Explicit target required"
.PHONY: default
# Prerequisites target
.make-prerequisites:
@touch $@
# Clean everything when CFLAGS is different
ifneq ($(shell sh -c '[ -f .make-cflags ] && cat .make-cflags || echo none'), $(CFLAGS))
.make-cflags: distclean
-(echo "$(CFLAGS)" > .make-cflags)
.make-prerequisites: .make-cflags
endif
# Clean everything when LDFLAGS is different
ifneq ($(shell sh -c '[ -f .make-ldflags ] && cat .make-ldflags || echo none'), $(LDFLAGS))
.make-ldflags: distclean
-(echo "$(LDFLAGS)" > .make-ldflags)
.make-prerequisites: .make-ldflags
endif
distclean:
-(cd hiredis && $(MAKE) clean) > /dev/null || true
-(cd linenoise && $(MAKE) clean) > /dev/null || true
-(cd jemalloc && [ -f Makefile ] && $(MAKE) distclean) > /dev/null || true
-(rm -f .make-*)
.PHONY: distclean
hiredis: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd hiredis && $(MAKE) static
.PHONY: hiredis
linenoise: .make-prerequisites
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
cd linenoise && $(MAKE)
.PHONY: linenoise
JEMALLOC_CFLAGS= -std=gnu99 -Wall -pipe -g3 -O3 -funroll-loops $(CFLAGS)
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) CFLAGS="$(JEMALLOC_CFLAGS)" LDFLAGS="$(JEMALLOC_LDFLAGS)" lib/libjemalloc.a
.PHONY: jemalloc
================================================
FILE: deps/README.md
================================================
This directory contains all Redis dependencies, except for the libc that
should be provided by the operating system.
* **Jemalloc** is our memory allocator, used as replacement for libc malloc on Linux by default. It has good performances and excellent fragmentation behavior. This component is upgraded from time to time.
* **geohash-int** is inside the dependencies directory but is actually part of the Redis project, since it is our private fork (heavily modified) of a library initially developed for Ardb, which is in turn a fork of Redis.
* **hiredis** is the official C client library for Redis. It is used by redis-cli, redis-benchmark and Redis Sentinel. It is part of the Redis official ecosystem but is developed externally from the Redis repository, so we just upgrade it as needed.
* **linenoise** is a readline replacement. It is developed by the same authors of Redis but is managed as a separated project and updated as needed.
* **lua** is Lua 5.1 with minor changes for security and additional libraries.
How to upgrade the above dependencies
===
Jemalloc
---
Jemalloc is unmodified. We only change settings via the `configure` script of Jemalloc using the `--with-lg-quantum` option, setting it to the value of 3 instead of 4. This provides us with more size classes that better suit the Redis data structures, in order to gain memory efficiency.
So in order to upgrade jemalloc:
1. Remove the jemalloc directory.
2. Substitute it with the new jemalloc source tree.
Geohash
---
This is never upgraded since it's part of the Redis project. If there are changes to merge from Ardb there is the need to manually check differences, but at this point the source code is pretty different.
Hiredis
---
Hiredis uses the SDS string library, that must be the same version used inside Redis itself. Hiredis is also very critical for Sentinel. Historically Redis often used forked versions of hiredis in a way or the other. In order to upgrade it is adviced to take a lot of care:
1. Check with diff if hiredis API changed and what impact it could have in Redis.
2. Make sure thet the SDS library inside Hiredis and inside Redis are compatible.
3. After the upgrade, run the Redis Sentinel test.
4. Check manually that redis-cli and redis-benchmark behave as expecteed, since we have no tests for CLI utilities currently.
Linenoise
---
Linenoise is rarely upgraded as needed. The upgrade process is trivial since
Redis uses a non modified version of linenoise, so to upgrade just do the
following:
1. Remove the linenoise directory.
2. Substitute it with the new linenoise source tree.
Lua
---
We use Lua 5.1 and no upgrade is planned currently, since we don't want to break
Lua scripts for new Lua features: in the context of Redis Lua scripts the
capabilities of 5.1 are usually more than enough, the release is rock solid,
and we definitely don't want to break old scripts.
So upgrading of Lua is up to the Redis project maintainers and should be a
manual procedure performed by taking a diff between the different versions.
Currently we have at least the following differences between official Lua 5.1
and our version:
1. Makefile is modified to allow a different compiler than GCC.
2. We have the implementation source code, and directly link to the following external libraries: `lua_cjson.o`, `lua_struct.o`, `lua_cmsgpack.o` and `lua_bit.o`.
3. There is a security fix in `ldo.c`, line 498: The check for `LUA_SIGNATURE[0]` is removed in order toa void direct bytecode exectuion.
================================================
FILE: deps/hiredis/.gitignore
================================================
/hiredis-test
/examples/hiredis-example*
/*.o
/*.so
/*.dylib
/*.a
================================================
FILE: deps/hiredis/.travis.yml
================================================
language: c
compiler:
- gcc
- clang
script: make && make check
================================================
FILE: deps/hiredis/CHANGELOG.md
================================================
### 0.11.0
* Increase the maximum multi-bulk reply depth to 7.
* Increase the read buffer size from 2k to 16k.
* Use poll(2) instead of select(2) to support large fds (>= 1024).
### 0.10.1
* Makefile overhaul. Important to check out if you override one or more
variables using environment variables or via arguments to the "make" tool.
* Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements
being created by the default reply object functions.
* Issue #43: Don't crash in an asynchronous context when Redis returns an error
reply after the connection has been made (this happens when the maximum
number of connections is reached).
### 0.10.0
* See commit log.
================================================
FILE: deps/hiredis/COPYING
================================================
Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
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.
================================================
FILE: deps/hiredis/Makefile
================================================
# Hiredis Makefile
# Copyright (C) 2010-2011 Salvatore Sanfilippo <antirez at gmail dot com>
# Copyright (C) 2010-2011 Pieter Noordhuis <pcnoordhuis at gmail dot com>
# This file is released under the BSD license, see the COPYING file
OBJ=net.o hiredis.o sds.o async.o
EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev
TESTS=hiredis-test
LIBNAME=libhiredis
HIREDIS_MAJOR=0
HIREDIS_MINOR=11
# redis-server configuration used for testing
REDIS_PORT=56379
REDIS_SERVER=redis-server
define REDIS_TEST_CONFIG
daemonize yes
pidfile /tmp/hiredis-test-redis.pid
port $(REDIS_PORT)
bind 127.0.0.1
unixsocket /tmp/hiredis-test-redis.sock
endef
export REDIS_TEST_CONFIG
# Fallback to gcc when $CC is not in $PATH.
CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
OPTIMIZATION?=-O3
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings
DEBUG?= -g -ggdb
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH)
REAL_LDFLAGS=$(LDFLAGS) $(ARCH)
DYLIBSUFFIX=so
STLIBSUFFIX=a
DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR).$(HIREDIS_MINOR)
DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
STLIB_MAKE_CMD=ar rcs $(STLIBNAME)
# Platform-specific overrides
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
ifeq ($(uname_S),SunOS)
REAL_LDFLAGS+= -ldl -lnsl -lsocket
DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
INSTALL= cp -r
endif
ifeq ($(uname_S),Darwin)
DYLIBSUFFIX=dylib
DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(DYLIBSUFFIX)
DYLIB_MAJOR_NAME=$(LIBNAME).$(HIREDIS_MAJOR).$(DYLIBSUFFIX)
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
endif
all: $(DYLIBNAME)
# Deps (use make dep to generate this)
net.o: net.c fmacros.h net.h hiredis.h
async.o: async.c async.h hiredis.h sds.h dict.c dict.h
hiredis.o: hiredis.c fmacros.h hiredis.h net.h sds.h
sds.o: sds.c sds.h
test.o: test.c hiredis.h
$(DYLIBNAME): $(OBJ)
$(DYLIB_MAKE_CMD) $(OBJ)
$(STLIBNAME): $(OBJ)
$(STLIB_MAKE_CMD) $(OBJ)
dynamic: $(DYLIBNAME)
static: $(STLIBNAME)
# Binaries:
hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME)
hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME)
ifndef AE_DIR
hiredis-example-ae:
@echo "Please specify AE_DIR (e.g. <redis repository>/src)"
@false
else
hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME)
endif
ifndef LIBUV_DIR
hiredis-example-libuv:
@echo "Please specify LIBUV_DIR (e.g. ../libuv/)"
@false
else
hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread $(STLIBNAME)
endif
hiredis-example: examples/example.c $(STLIBNAME)
$(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME)
examples: $(EXAMPLES)
hiredis-test: test.o $(STLIBNAME)
$(CC) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
test: hiredis-test
./hiredis-test
check: hiredis-test
@echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) -
./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \
( kill `cat /tmp/hiredis-test-redis.pid` && false )
kill `cat /tmp/hiredis-test-redis.pid`
.c.o:
$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $<
clean:
rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) examples/hiredis-example* *.o *.gcda *.gcno *.gcov
dep:
$(CC) -MM *.c
# Installation related variables and target
PREFIX?=/usr/local
INSTALL_INCLUDE_PATH= $(PREFIX)/include/hiredis
INSTALL_LIBRARY_PATH= $(PREFIX)/lib
ifeq ($(uname_S),SunOS)
INSTALL?= cp -r
endif
INSTALL?= cp -a
install: $(DYLIBNAME) $(STLIBNAME)
mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
$(INSTALL) hiredis.h async.h adapters $(INSTALL_INCLUDE_PATH)
$(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME)
cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME)
$(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH)
32bit:
@echo ""
@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"
@echo ""
$(MAKE) CFLAGS="-m32" LDFLAGS="-m32"
gprof:
$(MAKE) CFLAGS="-pg" LDFLAGS="-pg"
gcov:
$(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs"
coverage: gcov
make check
mkdir -p tmp/lcov
lcov -d . -c -o tmp/lcov/hiredis.info
genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info
noopt:
$(MAKE) OPTIMIZATION=""
.PHONY: all test check clean dep install 32bit gprof gcov noopt
================================================
FILE: deps/hiredis/README.md
================================================
[](https://travis-ci.org/redis/hiredis)
# HIREDIS
Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database.
It is minimalistic because it just adds minimal support for the protocol, but
at the same time it uses an high level printf-alike API in order to make it
much higher level than otherwise suggested by its minimal code base and the
lack of explicit bindings for every Redis command.
Apart from supporting sending commands and receiving replies, it comes with
a reply parser that is decoupled from the I/O layer. It
is a stream parser designed for easy reusability, which can for instance be used
in higher level language bindings for efficient reply parsing.
Hiredis only supports the binary-safe Redis protocol, so you can use it with any
Redis version >= 1.2.0.
The library comes with multiple APIs. There is the
*synchronous API*, the *asynchronous API* and the *reply parsing API*.
## UPGRADING
Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
code using hiredis should not be a big pain. The key thing to keep in mind when
upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to
the stateless 0.0.1 that only has a file descriptor to work with.
## Synchronous API
To consume the synchronous API, there are only a few function calls that need to be introduced:
redisContext *redisConnect(const char *ip, int port);
void *redisCommand(redisContext *c, const char *format, ...);
void freeReplyObject(void *reply);
### Connecting
The function `redisConnect` is used to create a so-called `redisContext`. The
context is where Hiredis holds state for a connection. The `redisContext`
struct has an integer `err` field that is non-zero when an the connection is in
an error state. The field `errstr` will contain a string with a description of
the error. More information on errors can be found in the **Errors** section.
After trying to connect to Redis using `redisConnect` you should
check the `err` field to see if establishing the connection was successful:
redisContext *c = redisConnect("127.0.0.1", 6379);
if (c != NULL && c->err) {
printf("Error: %s\n", c->errstr);
// handle error
}
### Sending commands
There are several ways to issue commands to Redis. The first that will be introduced is
`redisCommand`. This function takes a format similar to printf. In the simplest form,
it is used like this:
reply = redisCommand(context, "SET foo bar");
The specifier `%s` interpolates a string in the command, and uses `strlen` to
determine the length of the string:
reply = redisCommand(context, "SET foo %s", value);
When you need to pass binary safe strings in a command, the `%b` specifier can be
used. Together with a pointer to the string, it requires a `size_t` length argument
of the string:
reply = redisCommand(context, "SET foo %b", value, (size_t) valuelen);
Internally, Hiredis splits the command in different arguments and will
convert it to the protocol used to communicate with Redis.
One or more spaces separates arguments, so you can use the specifiers
anywhere in an argument:
reply = redisCommand(context, "SET key:%s %s", myid, value);
### Using replies
The return value of `redisCommand` holds a reply when the command was
successfully executed. When an error occurs, the return value is `NULL` and
the `err` field in the context will be set (see section on **Errors**).
Once an error is returned the context cannot be reused and you should set up
a new connection.
The standard replies that `redisCommand` are of the type `redisReply`. The
`type` field in the `redisReply` should be used to test what kind of reply
was received:
* **`REDIS_REPLY_STATUS`**:
* The command replied with a status reply. The status string can be accessed using `reply->str`.
The length of this string can be accessed using `reply->len`.
* **`REDIS_REPLY_ERROR`**:
* The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`.
* **`REDIS_REPLY_INTEGER`**:
* The command replied with an integer. The integer value can be accessed using the
`reply->integer` field of type `long long`.
* **`REDIS_REPLY_NIL`**:
* The command replied with a **nil** object. There is no data to access.
* **`REDIS_REPLY_STRING`**:
* A bulk (string) reply. The value of the reply can be accessed using `reply->str`.
The length of this string can be accessed using `reply->len`.
* **`REDIS_REPLY_ARRAY`**:
* A multi bulk reply. The number of elements in the multi bulk reply is stored in
`reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
and can be accessed via `reply->element[..index..]`.
Redis may reply with nested arrays but this is fully supported.
Replies should be freed using the `freeReplyObject()` function.
Note that this function will take care of freeing sub-replies objects
contained in arrays and nested arrays, so there is no need for the user to
free the sub replies (it is actually harmful and will corrupt the memory).
**Important:** the current version of hiredis (0.10.0) free's replies when the
asynchronous API is used. This means you should not call `freeReplyObject` when
you use this API. The reply is cleaned up by hiredis _after_ the callback
returns. This behavior will probably change in future releases, so make sure to
keep an eye on the changelog when upgrading (see issue #39).
### Cleaning up
To disconnect and free the context the following function can be used:
void redisFree(redisContext *c);
This function immediately closes the socket and then free's the allocations done in
creating the context.
### Sending commands (cont'd)
Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
It has the following prototype:
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
need to be binary safe, the entire array of lengths `argvlen` should be provided.
The return value has the same semantic as `redisCommand`.
### Pipelining
To explain how Hiredis supports pipelining in a blocking connection, there needs to be
understanding of the internal execution flow.
When any of the functions in the `redisCommand` family is called, Hiredis first formats the
command according to the Redis protocol. The formatted command is then put in the output buffer
of the context. This output buffer is dynamic, so it can hold any number of commands.
After the command is put in the output buffer, `redisGetReply` is called. This function has the
following two execution paths:
1. The input buffer is non-empty:
* Try to parse a single reply from the input buffer and return it
* If no reply could be parsed, continue at *2*
2. The input buffer is empty:
* Write the **entire** output buffer to the socket
* Read from the socket until a single reply could be parsed
The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply
is expected on the socket. To pipeline commands, the only things that needs to be done is
filling up the output buffer. For this cause, two commands can be used that are identical
to the `redisCommand` family, apart from not returning a reply:
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
After calling either function one or more times, `redisGetReply` can be used to receive the
subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where
the latter means an error occurred while reading a reply. Just as with the other commands,
the `err` field in the context can be used to find out what the cause of this error is.
The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
a single call to `read(2)`):
redisReply *reply;
redisAppendCommand(context,"SET foo bar");
redisAppendCommand(context,"GET foo");
redisGetReply(context,&reply); // reply for SET
freeReplyObject(reply);
redisGetReply(context,&reply); // reply for GET
freeReplyObject(reply);
This API can also be used to implement a blocking subscriber:
reply = redisCommand(context,"SUBSCRIBE foo");
freeReplyObject(reply);
while(redisGetReply(context,&reply) == REDIS_OK) {
// consume message
freeReplyObject(reply);
}
### Errors
When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
returned. The `err` field inside the context will be non-zero and set to one of the
following constants:
* **`REDIS_ERR_IO`**:
There was an I/O error while creating the connection, trying to write
to the socket or read from the socket. If you included `errno.h` in your
application, you can use the global `errno` variable to find out what is
wrong.
* **`REDIS_ERR_EOF`**:
The server closed the connection which resulted in an empty read.
* **`REDIS_ERR_PROTOCOL`**:
There was an error while parsing the protocol.
* **`REDIS_ERR_OTHER`**:
Any other error. Currently, it is only used when a specified hostname to connect
to cannot be resolved.
In every case, the `errstr` field in the context will be set to hold a string representation
of the error.
## Asynchronous API
Hiredis comes with an asynchronous API that works easily with any event library.
Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html)
and [libevent](http://monkey.org/~provos/libevent/).
### Connecting
The function `redisAsyncConnect` can be used to establish a non-blocking connection to
Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field
should be checked after creation to see if there were errors creating the connection.
Because the connection that will be created is non-blocking, the kernel is not able to
instantly return if the specified host and port is able to accept a connection.
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
printf("Error: %s\n", c->errstr);
// handle error
}
The asynchronous context can hold a disconnect callback function that is called when the
connection is disconnected (either because of an error or per user request). This function should
have the following prototype:
void(const redisAsyncContext *c, int status);
On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
field in the context can be accessed to find out the cause of the error.
The context object is always free'd after the disconnect callback fired. When a reconnect is needed,
the disconnect callback is a good point to do so.
Setting the disconnect callback can only be done once per context. For subsequent calls it will
return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
### Sending commands and their callbacks
In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
Therefore, unlike the synchronous API, there is only a single way to send commands.
Because commands are sent to Redis asynchronously, issuing a command requires a callback function
that is called when the reply is received. Reply callbacks should have the following prototype:
void(redisAsyncContext *c, void *reply, void *privdata);
The `privdata` argument can be used to curry arbitrary data to the callback from the point where
the command is initially queued for execution.
The functions that can be used to issue commands in an asynchronous context are:
int redisAsyncCommand(
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
const char *format, ...);
int redisAsyncCommandArgv(
redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
int argc, const char **argv, const size_t *argvlen);
Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command
was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection
is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is
returned on calls to the `redisAsyncCommand` family.
If the reply for a command with a `NULL` callback is read, it is immediately free'd. When the callback
for a command is non-`NULL`, the memory is free'd immediately following the callback: the reply is only
valid for the duration of the callback.
All pending callbacks are called with a `NULL` reply when the context encountered an error.
### Disconnecting
An asynchronous connection can be terminated using:
void redisAsyncDisconnect(redisAsyncContext *ac);
When this function is called, the connection is **not** immediately terminated. Instead, new
commands are no longer accepted and the connection is only terminated when all pending commands
have been written to the socket, their respective replies have been read and their respective
callbacks have been executed. After this, the disconnection callback is executed with the
`REDIS_OK` status and the context object is free'd.
### Hooking it up to event library *X*
There are a few hooks that need to be set on the context object after it is created.
See the `adapters/` directory for bindings to *libev* and *libevent*.
## Reply parsing API
Hiredis comes with a reply parsing API that makes it easy for writing higher
level language bindings.
The reply parsing API consists of the following functions:
redisReader *redisReaderCreate(void);
void redisReaderFree(redisReader *reader);
int redisReaderFeed(redisReader *reader, const char *buf, size_t len);
int redisReaderGetReply(redisReader *reader, void **reply);
The same set of functions are used internally by hiredis when creating a
normal Redis context, the above API just exposes it to the user for a direct
usage.
### Usage
The function `redisReaderCreate` creates a `redisReader` structure that holds a
buffer with unparsed data and state for the protocol parser.
Incoming data -- most likely from a socket -- can be placed in the internal
buffer of the `redisReader` using `redisReaderFeed`. This function will make a
copy of the buffer pointed to by `buf` for `len` bytes. This data is parsed
when `redisReaderGetReply` is called. This function returns an integer status
and a reply object (as described above) via `void **reply`. The returned status
can be either `REDIS_OK` or `REDIS_ERR`, where the latter means something went
wrong (either a protocol error, or an out of memory error).
The parser limits the level of nesting for multi bulk payloads to 7. If the
multi bulk nesting level is higher than this, the parser returns an error.
### Customizing replies
The function `redisReaderGetReply` creates `redisReply` and makes the function
argument `reply` point to the created `redisReply` variable. For instance, if
the response of type `REDIS_REPLY_STATUS` then the `str` field of `redisReply`
will hold the status as a vanilla C string. However, the functions that are
responsible for creating instances of the `redisReply` can be customized by
setting the `fn` field on the `redisReader` struct. This should be done
immediately after creating the `redisReader`.
For example, [hiredis-rb](https://github.com/pietern/hiredis-rb/blob/master/ext/hiredis_ext/reader.c)
uses customized reply object functions to create Ruby objects.
### Reader max buffer
Both when using the Reader API directly or when using it indirectly via a
normal Redis context, the redisReader structure uses a buffer in order to
accumulate data from the server.
Usually this buffer is destroyed when it is empty and is larger than 16
kb in order to avoid wasting memory in unused buffers
However when working with very big payloads destroying the buffer may slow
down performances considerably, so it is possible to modify the max size of
an idle buffer changing the value of the `maxbuf` field of the reader structure
to the desired value. The special value of 0 means that there is no maximum
value for an idle buffer, so the buffer will never get freed.
For instance if you have a normal Redis context you can set the maximum idle
buffer to zero (unlimited) just with:
context->reader->maxbuf = 0;
This should be done only in order to maximize performances when working with
large payloads. The context should be set back to `REDIS_READER_MAX_BUF` again
as soon as possible in order to prevent allocation of useless memory.
## AUTHORS
Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
================================================
FILE: deps/hiredis/adapters/ae.h
================================================
/*
* 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>
#include <ae.h>
#include "../hiredis.h"
#include "../async.h"
typedef struct redisAeEvents {
redisAsyncContext *context;
aeEventLoop *loop;
int fd;
int reading, writing;
} redisAeEvents;
static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
((void)el); ((void)fd); ((void)mask);
redisAeEvents *e = (redisAeEvents*)privdata;
redisAsyncHandleRead(e->context);
}
static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
((void)el); ((void)fd); ((void)mask);
redisAeEvents *e = (redisAeEvents*)privdata;
redisAsyncHandleWrite(e->context);
}
static void redisAeAddRead(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (!e->reading) {
e->reading = 1;
aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e);
}
}
static void redisAeDelRead(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (e->reading) {
e->reading = 0;
aeDeleteFileEvent(loop,e->fd,AE_READABLE);
}
}
static void redisAeAddWrite(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (!e->writing) {
e->writing = 1;
aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e);
}
}
static void redisAeDelWrite(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
aeEventLoop *loop = e->loop;
if (e->writing) {
e->writing = 0;
aeDeleteFileEvent(loop,e->fd,AE_WRITABLE);
}
}
static void redisAeCleanup(void *privdata) {
redisAeEvents *e = (redisAeEvents*)privdata;
redisAeDelRead(privdata);
redisAeDelWrite(privdata);
free(e);
}
static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisAeEvents *e;
/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisAeEvents*)malloc(sizeof(*e));
e->context = ac;
e->loop = loop;
e->fd = c->fd;
e->reading = e->writing = 0;
/* Register functions to start/stop listening for events */
ac->ev.addRead = redisAeAddRead;
ac->ev.delRead = redisAeDelRead;
ac->ev.addWrite = redisAeAddWrite;
ac->ev.delWrite = redisAeDelWrite;
ac->ev.cleanup = redisAeCleanup;
ac->ev.data = e;
return REDIS_OK;
}
#endif
================================================
FILE: deps/hiredis/adapters/libev.h
================================================
/*
* 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>
#include <sys/types.h>
#include <ev.h>
#include "../hiredis.h"
#include "../async.h"
typedef struct redisLibevEvents {
redisAsyncContext *context;
struct ev_loop *loop;
int reading, writing;
ev_io rev, wev;
} redisLibevEvents;
static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
#if EV_MULTIPLICITY
((void)loop);
#endif
((void)revents);
redisLibevEvents *e = (redisLibevEvents*)watcher->data;
redisAsyncHandleRead(e->context);
}
static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
#if EV_MULTIPLICITY
((void)loop);
#endif
((void)revents);
redisLibevEvents *e = (redisLibevEvents*)watcher->data;
redisAsyncHandleWrite(e->context);
}
static void redisLibevAddRead(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (!e->reading) {
e->reading = 1;
ev_io_start(EV_A_ &e->rev);
}
}
static void redisLibevDelRead(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (e->reading) {
e->reading = 0;
ev_io_stop(EV_A_ &e->rev);
}
}
static void redisLibevAddWrite(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (!e->writing) {
e->writing = 1;
ev_io_start(EV_A_ &e->wev);
}
}
static void redisLibevDelWrite(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
struct ev_loop *loop = e->loop;
((void)loop);
if (e->writing) {
e->writing = 0;
ev_io_stop(EV_A_ &e->wev);
}
}
static void redisLibevCleanup(void *privdata) {
redisLibevEvents *e = (redisLibevEvents*)privdata;
redisLibevDelRead(privdata);
redisLibevDelWrite(privdata);
free(e);
}
static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisLibevEvents *e;
/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisLibevEvents*)malloc(sizeof(*e));
e->context = ac;
#if EV_MULTIPLICITY
e->loop = loop;
#else
e->loop = NULL;
#endif
e->reading = e->writing = 0;
e->rev.data = e;
e->wev.data = e;
/* Register functions to start/stop listening for events */
ac->ev.addRead = redisLibevAddRead;
ac->ev.delRead = redisLibevDelRead;
ac->ev.addWrite = redisLibevAddWrite;
ac->ev.delWrite = redisLibevDelWrite;
ac->ev.cleanup = redisLibevCleanup;
ac->ev.data = e;
/* Initialize read/write events */
ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ);
ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE);
return REDIS_OK;
}
#endif
================================================
FILE: deps/hiredis/adapters/libevent.h
================================================
/*
* 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>
#include "../hiredis.h"
#include "../async.h"
typedef struct redisLibeventEvents {
redisAsyncContext *context;
struct event rev, wev;
} redisLibeventEvents;
static void redisLibeventReadEvent(int fd, short event, void *arg) {
((void)fd); ((void)event);
redisLibeventEvents *e = (redisLibeventEvents*)arg;
redisAsyncHandleRead(e->context);
}
static void redisLibeventWriteEvent(int fd, short event, void *arg) {
((void)fd); ((void)event);
redisLibeventEvents *e = (redisLibeventEvents*)arg;
redisAsyncHandleWrite(e->context);
}
static void redisLibeventAddRead(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_add(&e->rev,NULL);
}
static void redisLibeventDelRead(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_del(&e->rev);
}
static void redisLibeventAddWrite(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_add(&e->wev,NULL);
}
static void redisLibeventDelWrite(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_del(&e->wev);
}
static void redisLibeventCleanup(void *privdata) {
redisLibeventEvents *e = (redisLibeventEvents*)privdata;
event_del(&e->rev);
event_del(&e->wev);
free(e);
}
static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
redisContext *c = &(ac->c);
redisLibeventEvents *e;
/* Nothing should be attached when something is already attached */
if (ac->ev.data != NULL)
return REDIS_ERR;
/* Create container for context and r/w events */
e = (redisLibeventEvents*)malloc(sizeof(*e));
e->context = ac;
/* Register functions to start/stop listening for events */
ac->ev.addRead = redisLibeventAddRead;
ac->ev.delRead = redisLibeventDelRead;
ac->ev.addWrite = redisLibeventAddWrite;
ac->ev.delWrite = redisLibeventDelWrite;
ac->ev.cleanup = redisLibeventCleanup;
ac->ev.data = e;
/* Initialize and install read/write events */
event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e);
event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e);
event_base_set(base,&e->rev);
event_base_set(base,&e->wev);
return REDIS_OK;
}
#endif
================================================
FILE: deps/hiredis/adapters/libuv.h
================================================
#ifndef __HIREDIS_LIBUV_H__
#define __HIREDIS_LIBUV_H__
#include <uv.h>
#include "../hiredis.h"
#include "../async.h"
#include <string.h>
typedef struct redisLibuvEvents {
redisAsyncContext* context;
uv_poll_t handle;
int events;
} redisLibuvEvents;
int redisLibuvAttach(redisAsyncContext*, uv_loop_t*);
static void redisLibuvPoll(uv_poll_t* handle, int status, int events) {
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
if (status != 0) {
return;
}
if (events & UV_READABLE) {
redisAsyncHandleRead(p->context);
}
if (events & UV_WRITABLE) {
redisAsyncHandleWrite(p->context);
}
}
static void redisLibuvAddRead(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
p->events |= UV_READABLE;
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
}
static void redisLibuvDelRead(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
p->events &= ~UV_READABLE;
if (p->events) {
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
} else {
uv_poll_stop(&p->handle);
}
}
static void redisLibuvAddWrite(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
p->events |= UV_WRITABLE;
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
}
static void redisLibuvDelWrite(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
p->events &= ~UV_WRITABLE;
if (p->events) {
uv_poll_start(&p->handle, p->events, redisLibuvPoll);
} else {
uv_poll_stop(&p->handle);
}
}
static void on_close(uv_handle_t* handle) {
redisLibuvEvents* p = (redisLibuvEvents*)handle->data;
free(p);
}
static void redisLibuvCleanup(void *privdata) {
redisLibuvEvents* p = (redisLibuvEvents*)privdata;
uv_close((uv_handle_t*)&p->handle, on_close);
}
static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
redisContext *c = &(ac->c);
if (ac->ev.data != NULL) {
return REDIS_ERR;
}
ac->ev.addRead = redisLibuvAddRead;
ac->ev.delRead = redisLibuvDelRead;
ac->ev.addWrite = redisLibuvAddWrite;
ac->ev.delWrite = redisLibuvDelWrite;
ac->ev.cleanup = redisLibuvCleanup;
redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p));
if (!p) {
return REDIS_ERR;
}
memset(p, 0, sizeof(*p));
if (uv_poll_init(loop, &p->handle, c->fd) != 0) {
return REDIS_ERR;
}
ac->ev.data = p;
p->handle.data = p;
p->context = ac;
return REDIS_OK;
}
#endif
================================================
FILE: deps/hiredis/async.c
================================================
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* 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.
*/
#include "fmacros.h"
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include "async.h"
#include "net.h"
#include "dict.c"
#include "sds.h"
#define _EL_ADD_READ(ctx) do { \
if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \
} while(0)
#define _EL_DEL_READ(ctx) do { \
if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \
} while(0)
#define _EL_ADD_WRITE(ctx) do { \
if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \
} while(0)
#define _EL_DEL_WRITE(ctx) do { \
if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \
} while(0)
#define _EL_CLEANUP(ctx) do { \
if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \
} while(0);
/* Forward declaration of function in hiredis.c */
void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
/* Functions managing dictionary of callbacks for pub/sub. */
static unsigned int callbackHash(const void *key) {
return dictGenHashFunction((const unsigned char *)key,
sdslen((const sds)key));
}
static void *callbackValDup(void *privdata, const void *src) {
((void) privdata);
redisCallback *dup = malloc(sizeof(*dup));
memcpy(dup,src,sizeof(*dup));
return dup;
}
static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) {
int l1, l2;
((void) privdata);
l1 = sdslen((const sds)key1);
l2 = sdslen((const sds)key2);
if (l1 != l2) return 0;
return memcmp(key1,key2,l1) == 0;
}
static void callbackKeyDestructor(void *privdata, void *key) {
((void) privdata);
sdsfree((sds)key);
}
static void callbackValDestructor(void *privdata, void *val) {
((void) privdata);
free(val);
}
static dictType callbackDict = {
callbackHash,
NULL,
callbackValDup,
callbackKeyCompare,
callbackKeyDestructor,
callbackValDestructor
};
static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
redisAsyncContext *ac;
ac = realloc(c,sizeof(redisAsyncContext));
if (ac == NULL)
return NULL;
c = &(ac->c);
/* The regular connect functions will always set the flag REDIS_CONNECTED.
* For the async API, we want to wait until the first write event is
* received up before setting this flag, so reset it here. */
c->flags &= ~REDIS_CONNECTED;
ac->err = 0;
ac->errstr = NULL;
ac->data = NULL;
ac->ev.data = NULL;
ac->ev.addRead = NULL;
ac->ev.delRead = NULL;
ac->ev.addWrite = NULL;
ac->ev.delWrite = NULL;
ac->ev.cleanup = NULL;
ac->onConnect = NULL;
ac->onDisconnect = NULL;
ac->replies.head = NULL;
ac->replies.tail = NULL;
ac->sub.invalid.head = NULL;
ac->sub.invalid.tail = NULL;
ac->sub.channels = dictCreate(&callbackDict,NULL);
ac->sub.patterns = dictCreate(&callbackDict,NULL);
return ac;
}
/* We want the error field to be accessible directly instead of requiring
* an indirection to the redisContext struct. */
static void __redisAsyncCopyError(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
ac->err = c->err;
ac->errstr = c->errstr;
}
redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
redisContext *c;
redisAsyncContext *ac;
c = redisConnectNonBlock(ip,port);
if (c == NULL)
return NULL;
ac = redisAsyncInitialize(c);
if (ac == NULL) {
redisFree(c);
return NULL;
}
__redisAsyncCopyError(ac);
return ac;
}
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
const char *source_addr) {
redisContext *c = redisConnectBindNonBlock(ip,port,source_addr);
redisAsyncContext *ac = redisAsyncInitialize(c);
__redisAsyncCopyError(ac);
return ac;
}
redisAsyncContext *redisAsyncConnectUnix(const char *path) {
redisContext *c;
redisAsyncContext *ac;
c = redisConnectUnixNonBlock(path);
if (c == NULL)
return NULL;
ac = redisAsyncInitialize(c);
if (ac == NULL) {
redisFree(c);
return NULL;
}
__redisAsyncCopyError(ac);
return ac;
}
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
if (ac->onConnect == NULL) {
ac->onConnect = fn;
/* The common way to detect an established connection is to wait for
* the first write event to be fired. This assumes the related event
* library functions are already set. */
_EL_ADD_WRITE(ac);
return REDIS_OK;
}
return REDIS_ERR;
}
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) {
if (ac->onDisconnect == NULL) {
ac->onDisconnect = fn;
return REDIS_OK;
}
return REDIS_ERR;
}
/* Helper functions to push/shift callbacks */
static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
redisCallback *cb;
/* Copy callback from stack to heap */
cb = malloc(sizeof(*cb));
if (cb == NULL)
return REDIS_ERR_OOM;
if (source != NULL) {
memcpy(cb,source,sizeof(*cb));
cb->next = NULL;
}
/* Store callback in list */
if (list->head == NULL)
list->head = cb;
if (list->tail != NULL)
list->tail->next = cb;
list->tail = cb;
return REDIS_OK;
}
static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) {
redisCallback *cb = list->head;
if (cb != NULL) {
list->head = cb->next;
if (cb == list->tail)
list->tail = NULL;
/* Copy callback from heap to stack */
if (target != NULL)
memcpy(target,cb,sizeof(*cb));
free(cb);
return REDIS_OK;
}
return REDIS_ERR;
}
static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) {
redisContext *c = &(ac->c);
if (cb->fn != NULL) {
c->flags |= REDIS_IN_CALLBACK;
cb->fn(ac,reply,cb->privdata);
c->flags &= ~REDIS_IN_CALLBACK;
}
}
/* Helper function to free the context. */
static void __redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb;
dictIterator *it;
dictEntry *de;
/* Execute pending callbacks with NULL reply. */
while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK)
__redisRunCallback(ac,&cb,NULL);
/* Execute callbacks for invalid commands */
while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
__redisRunCallback(ac,&cb,NULL);
/* Run subscription callbacks callbacks with NULL reply */
it = dictGetIterator(ac->sub.channels);
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
dictRelease(ac->sub.channels);
it = dictGetIterator(ac->sub.patterns);
while ((de = dictNext(it)) != NULL)
__redisRunCallback(ac,dictGetEntryVal(de),NULL);
dictReleaseIterator(it);
dictRelease(ac->sub.patterns);
/* Signal event lib to clean up */
_EL_CLEANUP(ac);
/* Execute disconnect callback. When redisAsyncFree() initiated destroying
* this context, the status will always be REDIS_OK. */
if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
if (c->flags & REDIS_FREEING) {
ac->onDisconnect(ac,REDIS_OK);
} else {
ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
}
}
/* Cleanup self */
redisFree(c);
}
/* Free the async context. When this function is called from a callback,
* control needs to be returned to redisProcessCallbacks() before actual
* free'ing. To do so, a flag is set on the context which is picked up by
* redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
void redisAsyncFree(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
c->flags |= REDIS_FREEING;
if (!(c->flags & REDIS_IN_CALLBACK))
__redisAsyncFree(ac);
}
/* Helper function to make the disconnect happen and clean up. */
static void __redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
/* Make sure error is accessible if there is any */
__redisAsyncCopyError(ac);
if (ac->err == 0) {
/* For clean disconnects, there should be no pending callbacks. */
assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
} else {
/* Disconnection is caused by an error, make sure that pending
* callbacks cannot call new commands. */
c->flags |= REDIS_DISCONNECTING;
}
/* For non-clean disconnects, __redisAsyncFree() will execute pending
* callbacks with a NULL-reply. */
__redisAsyncFree(ac);
}
/* Tries to do a clean disconnect from Redis, meaning it stops new commands
* from being issued, but tries to flush the output buffer and execute
* callbacks for all remaining replies. When this function is called from a
* callback, there might be more replies and we can safely defer disconnecting
* to redisProcessCallbacks(). Otherwise, we can only disconnect immediately
* when there are no pending callbacks. */
void redisAsyncDisconnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
c->flags |= REDIS_DISCONNECTING;
if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
__redisAsyncDisconnect(ac);
}
static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) {
redisContext *c = &(ac->c);
dict *callbacks;
dictEntry *de;
int pvariant;
char *stype;
sds sname;
/* Custom reply functions are not supported for pub/sub. This will fail
* very hard when they are used... */
if (reply->type == REDIS_REPLY_ARRAY) {
assert(reply->elements >= 2);
assert(reply->element[0]->type == REDIS_REPLY_STRING);
stype = reply->element[0]->str;
pvariant = (tolower(stype[0]) == 'p') ? 1 : 0;
if (pvariant)
callbacks = ac->sub.patterns;
else
callbacks = ac->sub.channels;
/* Locate the right callback */
assert(reply->element[1]->type == REDIS_REPLY_STRING);
sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
de = dictFind(callbacks,sname);
if (de != NULL) {
memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb));
/* If this is an unsubscribe message, remove it. */
if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
dictDelete(callbacks,sname);
/* If this was the last unsubscribe message, revert to
* non-subscribe mode. */
assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
if (reply->element[2]->integer == 0)
c->flags &= ~REDIS_SUBSCRIBED;
}
}
sdsfree(sname);
} else {
/* Shift callback for invalid commands. */
__redisShiftCallback(&ac->sub.invalid,dstcb);
}
return REDIS_OK;
}
void redisProcessCallbacks(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
redisCallback cb = {NULL, NULL, NULL};
void *reply = NULL;
int status;
while((status = redisGetReply(c,&reply)) == REDIS_OK) {
if (reply == NULL) {
/* When the connection is being disconnected and there are
* no more replies, this is the cue to really disconnect. */
if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) {
__redisAsyncDisconnect(ac);
return;
}
/* If monitor mode, repush callback */
if(c->flags & REDIS_MONITORING) {
__redisPushCallback(&ac->replies,&cb);
}
/* When the connection is not being disconnected, simply stop
* trying to get replies and wait for the next loop tick. */
break;
}
/* Even if the context is subscribed, pending regular callbacks will
* get a reply before pub/sub messages arrive. */
if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
/*
* A spontaneous reply in a not-subscribed context can be the error
* reply that is sent when a new connection exceeds the maximum
* number of allowed connections on the server side.
*
* This is seen as an error instead of a regular reply because the
* server closes the connection after sending it.
*
* To prevent the error from being overwritten by an EOF error the
* connection is closed here. See issue #43.
*
* Another possibility is that the server is loading its dataset.
* In this case we also want to close the connection, and have the
* user wait until the server is ready to take our request.
*/
if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) {
c->err = REDIS_ERR_OTHER;
snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str);
__redisAsyncDisconnect(ac);
return;
}
/* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */
assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING));
if(c->flags & REDIS_SUBSCRIBED)
__redisGetSubscribeCallback(ac,reply,&cb);
}
if (cb.fn != NULL) {
__redisRunCallback(ac,&cb,reply);
c->reader->fn->freeObject(reply);
/* Proceed with free'ing when redisAsyncFree() was called. */
if (c->flags & REDIS_FREEING) {
__redisAsyncFree(ac);
return;
}
} else {
/* No callback for this reply. This can either be a NULL callback,
* or there were no callbacks to begin with. Either way, don't
* abort with an error, but simply ignore it because the client
* doesn't know what the server will spit out over the wire. */
c->reader->fn->freeObject(reply);
}
}
/* Disconnect when there was an error reading the reply */
if (status != REDIS_OK)
__redisAsyncDisconnect(ac);
}
/* Internal helper function to detect socket status the first time a read or
* write event fires. When connecting was not succesful, the connect callback
* is called with a REDIS_ERR status and the context is free'd. */
static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
if (redisCheckSocketError(c) == REDIS_ERR) {
/* Try again later when connect(2) is still in progress. */
if (errno == EINPROGRESS)
return REDIS_OK;
if (ac->onConnect) ac->onConnect(ac,REDIS_ERR);
__redisAsyncDisconnect(ac);
return REDIS_ERR;
}
/* Mark context as connected. */
c->flags |= REDIS_CONNECTED;
if (ac->onConnect) ac->onConnect(ac,REDIS_OK);
return REDIS_OK;
}
/* This function should be called when the socket is readable.
* It processes all replies that can be read and executes their callbacks.
*/
void redisAsyncHandleRead(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}
if (redisBufferRead(c) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Always re-schedule reads */
_EL_ADD_READ(ac);
redisProcessCallbacks(ac);
}
}
void redisAsyncHandleWrite(redisAsyncContext *ac) {
redisContext *c = &(ac->c);
int done = 0;
if (!(c->flags & REDIS_CONNECTED)) {
/* Abort connect was not successful. */
if (__redisAsyncHandleConnect(ac) != REDIS_OK)
return;
/* Try again later when the context is still not connected. */
if (!(c->flags & REDIS_CONNECTED))
return;
}
if (redisBufferWrite(c,&done) == REDIS_ERR) {
__redisAsyncDisconnect(ac);
} else {
/* Continue writing when not done, stop writing otherwise */
if (!done)
_EL_ADD_WRITE(ac);
else
_EL_DEL_WRITE(ac);
/* Always schedule reads after writes */
_EL_ADD_READ(ac);
}
}
/* Sets a pointer to the first argument and its length starting at p. Returns
* the number of bytes to skip to get to the following argument. */
static char *nextArgument(char *start, char **str, size_t *len) {
char *p = start;
if (p[0] != '$') {
p = strchr(p,'$');
if (p == NULL) return NULL;
}
*len = (int)strtol(p+1,NULL,10);
p = strchr(p,'\r');
assert(p);
*str = p+2;
return p+2+(*len)+2;
}
/* Helper function for the redisAsyncCommand* family of functions. Writes a
* formatted command to the output buffer and registers the provided callback
* function with the context. */
static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, char *cmd, size_t len) {
redisContext *c = &(ac->c);
redisCallback cb;
int pvariant, hasnext;
char *cstr, *astr;
size_t clen, alen;
char *p;
sds sname;
/* Don't accept new commands when the connection is about to be closed. */
if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR;
/* Setup callback */
cb.fn = fn;
cb.privdata = privdata;
/* Find out which command will be appended. */
p = nextArgument(cmd,&cstr,&clen);
assert(p != NULL);
hasnext = (p[0] == '$');
pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0;
cstr += pvariant;
clen -= pvariant;
if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) {
c->flags |= REDIS_SUBSCRIBED;
/* Add every channel/pattern to the list of subscription callbacks. */
while ((p = nextArgument(p,&astr,&alen)) != NULL) {
sname = sdsnewlen(astr,alen);
if (pvariant)
dictReplace(ac->sub.patterns,sname,&cb);
else
dictReplace(ac->sub.channels,sname,&cb);
}
} else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) {
/* It is only useful to call (P)UNSUBSCRIBE when the context is
* subscribed to one or more channels or patterns. */
if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR;
/* (P)UNSUBSCRIBE does not have its own response: every channel or
* pattern that is unsubscribed will receive a message. This means we
* should not append a callback function for this command. */
} else if(strncasecmp(cstr,"monitor\r\n",9) == 0) {
/* Set monitor flag and push callback */
c->flags |= REDIS_MONITORING;
__redisPushCallback(&ac->replies,&cb);
} else {
if (c->flags & REDIS_SUBSCRIBED)
/* This will likely result in an error reply, but it needs to be
* received and passed to the callback. */
__redisPushCallback(&ac->sub.invalid,&cb);
else
__redisPushCallback(&ac->replies,&cb);
}
__redisAppendCommand(c,cmd,len);
/* Always schedule a write when the write buffer is non-empty */
_EL_ADD_WRITE(ac);
return REDIS_OK;
}
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) {
char *cmd;
int len;
int status;
len = redisvFormatCommand(&cmd,format,ap);
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
free(cmd);
return status;
}
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) {
va_list ap;
int status;
va_start(ap,format);
status = redisvAsyncCommand(ac,fn,privdata,format,ap);
va_end(ap);
return status;
}
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
char *cmd;
int len;
int status;
len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
free(cmd);
return status;
}
================================================
FILE: deps/hiredis/async.h
================================================
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* 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_ASYNC_H
#define __HIREDIS_ASYNC_H
#include "hiredis.h"
#ifdef __cplusplus
extern "C" {
#endif
struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
struct dict; /* dictionary header is included in async.c */
/* Reply callback prototype and container */
typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
typedef struct redisCallback {
struct redisCallback *next; /* simple singly linked list */
redisCallbackFn *fn;
void *privdata;
} redisCallback;
/* List of callbacks for either regular replies or pub/sub */
typedef struct redisCallbackList {
redisCallback *head, *tail;
} redisCallbackList;
/* Connection callback prototypes */
typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
/* Context for an async connection to Redis */
typedef struct redisAsyncContext {
/* Hold the regular context, so it can be realloc'ed. */
redisContext c;
/* Setup error flags so they can be used directly. */
int err;
char *errstr;
/* Not used by hiredis */
void *data;
/* Event library data and hooks */
struct {
void *data;
/* Hooks that are called when the library expects to start
* reading/writing. These functions should be idempotent. */
void (*addRead)(void *privdata);
void (*delRead)(void *privdata);
void (*addWrite)(void *privdata);
void (*delWrite)(void *privdata);
void (*cleanup)(void *privdata);
} ev;
/* Called when either the connection is terminated due to an error or per
* user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
redisDisconnectCallback *onDisconnect;
/* Called when the first write event was received. */
redisConnectCallback *onConnect;
/* Regular command callbacks */
redisCallbackList replies;
/* Subscription callbacks */
struct {
redisCallbackList invalid;
struct dict *channels;
struct dict *patterns;
} sub;
} redisAsyncContext;
/* Functions that proxy to hiredis */
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr);
redisAsyncContext *redisAsyncConnectUnix(const char *path);
int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
void redisAsyncDisconnect(redisAsyncContext *ac);
void redisAsyncFree(redisAsyncContext *ac);
/* Handle read/write events */
void redisAsyncHandleRead(redisAsyncContext *ac);
void redisAsyncHandleWrite(redisAsyncContext *ac);
/* Command functions for an async context. Write the command to the
* output buffer and register the provided callback. */
int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: deps/hiredis/dict.c
================================================
/* Hash table implementation.
*
* This file implements in memory hash tables with insert/del/replace/find/
* get-random-element operations. Hash tables will auto resize if needed
* tables of power of two in size are used, collisions are handled by
* chaining. See the source code for more information... :)
*
* Copyright (c) 2006-2010, 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 "fmacros.h"
#include <stdlib.h>
#include <assert.h>
#include <limits.h>
#include "dict.h"
/* -------------------------- private prototypes ---------------------------- */
static int _dictExpandIfNeeded(dict *ht);
static unsigned long _dictNextPower(unsigned long size);
static int _dictKeyIndex(dict *ht, const void *key);
static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
/* -------------------------- hash functions -------------------------------- */
/* Generic hash function (a popular one from Bernstein).
* I tested a few and this was the best. */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
unsigned int hash = 5381;
while (len--)
hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
return hash;
}
/* ----------------------------- API implementation ------------------------- */
/* Reset an hashtable already initialized with ht_init().
* NOTE: This function should only called by ht_destroy(). */
static void _dictReset(dict *ht) {
ht->table = NULL;
ht->size = 0;
ht->sizemask = 0;
ht->used = 0;
}
/* Create a new hash table */
static dict *dictCreate(dictType *type, void *privDataPtr) {
dict *ht = malloc(sizeof(*ht));
_dictInit(ht,type,privDataPtr);
return ht;
}
/* Initialize the hash table */
static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
_dictReset(ht);
ht->type = type;
ht->privdata = privDataPtr;
return DICT_OK;
}
/* Expand or create the hashtable */
static int dictExpand(dict *ht, unsigned long size) {
dict n; /* the new hashtable */
unsigned long realsize = _dictNextPower(size), i;
/* the size is invalid if it is smaller than the number of
* elements already inside the hashtable */
if (ht->used > size)
return DICT_ERR;
_dictInit(&n, ht->type, ht->privdata);
n.size = realsize;
n.sizemask = realsize-1;
n.table = calloc(realsize,sizeof(dictEntry*));
/* Copy all the elements from the old to the new table:
* note that if the old hash table is empty ht->size is zero,
* so dictExpand just creates an hash table. */
n.used = ht->used;
for (i = 0; i < ht->size && ht->used > 0; i++) {
dictEntry *he, *nextHe;
if (ht->table[i] == NULL) continue;
/* For each hash entry on this slot... */
he = ht->table[i];
while(he) {
unsigned int h;
nextHe = he->next;
/* Get the new element index */
h = dictHashKey(ht, he->key) & n.sizemask;
he->next = n.table[h];
n.table[h] = he;
ht->used--;
/* Pass to the next element */
he = nextHe;
}
}
assert(ht->used == 0);
free(ht->table);
/* Remap the new hashtable in the old */
*ht = n;
return DICT_OK;
}
/* Add an element to the target hash table */
static int dictAdd(dict *ht, void *key, void *val) {
int index;
dictEntry *entry;
/* Get the index of the new element, or -1 if
* the element already exists. */
if ((index = _dictKeyIndex(ht, key)) == -1)
return DICT_ERR;
/* Allocates the memory and stores key */
entry = malloc(sizeof(*entry));
entry->next = ht->table[index];
ht->table[index] = entry;
/* Set the hash entry fields. */
dictSetHashKey(ht, entry, key);
dictSetHashVal(ht, entry, val);
ht->used++;
return DICT_OK;
}
/* Add an element, discarding the old if the key already exists.
* Return 1 if the key was added from scratch, 0 if there was already an
* element with such key and dictReplace() just performed a value update
* operation. */
static int dictReplace(dict *ht, void *key, void *val) {
dictEntry *entry, auxentry;
/* Try to add the element. If the key
* does not exists dictAdd will suceed. */
if (dictAdd(ht, key, val) == DICT_OK)
return 1;
/* It already exists, get the entry */
entry = dictFind(ht, key);
/* Free the old value and set the new one */
/* Set the new value and free the old one. Note that it is important
* to do that in this order, as the value may just be exactly the same
* as the previous one. In this context, think to reference counting,
* you want to increment (set), and then decrement (free), and not the
* reverse. */
auxentry = *entry;
dictSetHashVal(ht, entry, val);
dictFreeEntryVal(ht, &auxentry);
return 0;
}
/* Search and remove an element */
static int dictDelete(dict *ht, const void *key) {
unsigned int h;
dictEntry *de, *prevde;
if (ht->size == 0)
return DICT_ERR;
h = dictHashKey(ht, key) & ht->sizemask;
de = ht->table[h];
prevde = NULL;
while(de) {
if (dictCompareHashKeys(ht,key,de->key)) {
/* Unlink the element from the list */
if (prevde)
prevde->next = de->next;
else
ht->table[h] = de->next;
dictFreeEntryKey(ht,de);
dictFreeEntryVal(ht,de);
free(de);
ht->used--;
return DICT_OK;
}
prevde = de;
de = de->next;
}
return DICT_ERR; /* not found */
}
/* Destroy an entire hash table */
static int _dictClear(dict *ht) {
unsigned long i;
/* Free all the elements */
for (i = 0; i < ht->size && ht->used > 0; i++) {
dictEntry *he, *nextHe;
if ((he = ht->table[i]) == NULL) continue;
while(he) {
nextHe = he->next;
dictFreeEntryKey(ht, he);
dictFreeEntryVal(ht, he);
free(he);
ht->used--;
he = nextHe;
}
}
/* Free the table and the allocated cache structure */
free(ht->table);
/* Re-initialize the table */
_dictReset(ht);
return DICT_OK; /* never fails */
}
/* Clear & Release the hash table */
static void dictRelease(dict *ht) {
_dictClear(ht);
free(ht);
}
static dictEntry *dictFind(dict *ht, const void *key) {
dictEntry *he;
unsigned int h;
if (ht->size == 0) return NULL;
h = dictHashKey(ht, key) & ht->sizemask;
he = ht->table[h];
while(he) {
if (dictCompareHashKeys(ht, key, he->key))
return he;
he = he->next;
}
return NULL;
}
static dictIterator *dictGetIterator(dict *ht) {
dictIterator *iter = malloc(sizeof(*iter));
iter->ht = ht;
iter->index = -1;
iter->entry = NULL;
iter->nextEntry = NULL;
return iter;
}
static dictEntry *dictNext(dictIterator *iter) {
while (1) {
if (iter->entry == NULL) {
iter->index++;
if (iter->index >=
(signed)iter->ht->size) break;
iter->entry = iter->ht->table[iter->index];
} else {
iter->entry = iter->nextEntry;
}
if (iter->entry) {
/* We need to save the 'next' here, the iterator user
* may delete the entry we are returning. */
iter->nextEntry = iter->entry->next;
return iter->entry;
}
}
return NULL;
}
static void dictReleaseIterator(dictIterator *iter) {
free(iter);
}
/* ------------------------- private functions ------------------------------ */
/* Expand the hash table if needed */
static int _dictExpandIfNeeded(dict *ht) {
/* If the hash table is empty expand it to the intial size,
* if the table is "full" dobule its size. */
if (ht->size == 0)
return dictExpand(ht, DICT_HT_INITIAL_SIZE);
if (ht->used == ht->size)
return dictExpand(ht, ht->size*2);
return DICT_OK;
}
/* Our hash table capability is a power of two */
static unsigned long _dictNextPower(unsigned long size) {
unsigned long i = DICT_HT_INITIAL_SIZE;
if (size >= LONG_MAX) return LONG_MAX;
while(1) {
if (i >= size)
return i;
i *= 2;
}
}
/* Returns the index of a free slot that can be populated with
* an hash entry for the given 'key'.
* If the key already exists, -1 is returned. */
static int _dictKeyIndex(dict *ht, const void *key) {
unsigned int h;
dictEntry *he;
/* Expand the hashtable if needed */
if (_dictExpandIfNeeded(ht) == DICT_ERR)
return -1;
/* Compute the key hash value */
h = dictHashKey(ht, key) & ht->sizemask;
/* Search if this slot does not already contain the given key */
he = ht->table[h];
while(he) {
if (dictCompareHashKeys(ht, key, he->key))
return -1;
he = he->next;
}
return h;
}
================================================
FILE: deps/hiredis/dict.h
================================================
/* Hash table implementation.
*
* This file implements in memory hash tables with insert/del/replace/find/
* get-random-element operations. Hash tables will auto resize if needed
* tables of power of two in size are used, collisions are handled by
* chaining. See the source code for more information... :)
*
* Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __DICT_H
#define __DICT_H
#define DICT_OK 0
#define DICT_ERR 1
/* Unused arguments generate annoying warnings... */
#define DICT_NOTUSED(V) ((void) V)
typedef struct dictEntry {
void *key;
void *val;
struct dictEntry *next;
} dictEntry;
typedef struct dictType {
unsigned int (*hashFunction)(const void *key);
void *(*keyDup)(void *privdata, const void *key);
void *(*valDup)(void *privdata, const void *obj);
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} dictType;
typedef struct dict {
dictEntry **table;
dictType *type;
unsigned long size;
unsigned long sizemask;
unsigned long used;
void *privdata;
} dict;
typedef struct dictIterator {
dict *ht;
int index;
dictEntry *entry, *nextEntry;
} dictIterator;
/* This is the initial size of every hash table */
#define DICT_HT_INITIAL_SIZE 4
/* ------------------------------- Macros ------------------------------------*/
#define dictFreeEntryVal(ht, entry) \
if ((ht)->type->valDestructor) \
(ht)->type->valDestructor((ht)->privdata, (entry)->val)
#define dictSetHashVal(ht, entry, _val_) do { \
if ((ht)->type->valDup) \
entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
else \
entry->val = (_val_); \
} while(0)
#define dictFreeEntryKey(ht, entry) \
if ((ht)->type->keyDestructor) \
(ht)->type->keyDestructor((ht)->privdata, (entry)->key)
#define dictSetHashKey(ht, entry, _key_) do { \
if ((ht)->type->keyDup) \
entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
else \
entry->key = (_key_); \
} while(0)
#define dictCompareHashKeys(ht, key1, key2) \
(((ht)->type->keyCompare) ? \
(ht)->type->keyCompare((ht)->privdata, key1, key2) : \
(key1) == (key2))
#define dictHashKey(ht, key) (ht)->type->hashFunction(key)
#define dictGetEntryKey(he) ((he)->key)
#define dictGetEntryVal(he) ((he)->val)
#define dictSlots(ht) ((ht)->size)
#define dictSize(ht) ((ht)->used)
/* API */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
static dict *dictCreate(dictType *type, void *privDataPtr);
static int dictExpand(dict *ht, unsigned long size);
static int dictAdd(dict *ht, void *key, void *val);
static int dictReplace(dict *ht, void *key, void *val);
static int dictDelete(dict *ht, const void *key);
static void dictRelease(dict *ht);
static dictEntry * dictFind(dict *ht, const void *key);
static dictIterator *dictGetIterator(dict *ht);
static dictEntry *dictNext(dictIterator *iter);
static void dictReleaseIterator(dictIterator *iter);
#endif /* __DICT_H */
================================================
FILE: deps/hiredis/examples/example-ae.c
================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <async.h>
#include <adapters/ae.h>
/* Put event loop in the global scope, so it can be explicitly stopped */
static aeEventLoop *loop;
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
aeStop(loop);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
aeStop(loop);
return;
}
printf("Disconnected...\n");
aeStop(loop);
}
int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
loop = aeCreateEventLoop(64);
redisAeAttach(loop, c);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
aeMain(loop);
return 0;
}
================================================
FILE: deps/hiredis/examples/example-libev.c
================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <async.h>
#include <adapters/libev.h>
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}
int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
redisLibevAttach(EV_DEFAULT_ c);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
ev_loop(EV_DEFAULT_ 0);
return 0;
}
================================================
FILE: deps/hiredis/examples/example-libevent.c
================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <async.h>
#include <adapters/libevent.h>
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}
int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
struct event_base *base = event_base_new();
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
redisLibeventAttach(c,base);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
event_base_dispatch(base);
return 0;
}
================================================
FILE: deps/hiredis/examples/example-libuv.c
================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <hiredis.h>
#include <async.h>
#include <adapters/libuv.h>
void getCallback(redisAsyncContext *c, void *r, void *privdata) {
redisReply *reply = r;
if (reply == NULL) return;
printf("argv[%s]: %s\n", (char*)privdata, reply->str);
/* Disconnect after receiving the reply to GET */
redisAsyncDisconnect(c);
}
void connectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Connected...\n");
}
void disconnectCallback(const redisAsyncContext *c, int status) {
if (status != REDIS_OK) {
printf("Error: %s\n", c->errstr);
return;
}
printf("Disconnected...\n");
}
int main (int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
uv_loop_t* loop = uv_default_loop();
redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
if (c->err) {
/* Let *c leak for now... */
printf("Error: %s\n", c->errstr);
return 1;
}
redisLibuvAttach(c,loop);
redisAsyncSetConnectCallback(c,connectCallback);
redisAsyncSetDisconnectCallback(c,disconnectCallback);
redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
================================================
FILE: deps/hiredis/examples/example.c
================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
int main(int argc, char **argv) {
unsigned int j;
redisContext *c;
redisReply *reply;
const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
int port = (argc > 2) ? atoi(argv[2]) : 6379;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
c = redisConnectWithTimeout(hostname, port, timeout);
if (c == NULL || c->err) {
if (c) {
printf("Connection error: %s\n", c->errstr);
redisFree(c);
} else {
printf("Connection error: can't allocate redis context\n");
}
exit(1);
}
/* PING server */
reply = redisCommand(c,"PING");
printf("PING: %s\n", reply->str);
freeReplyObject(reply);
/* Set a key */
reply = redisCommand(c,"SET %s %s", "foo", "hello world");
printf("SET: %s\n", reply->str);
freeReplyObject(reply);
/* Set a key using binary safe API */
reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5);
printf("SET (binary API): %s\n", reply->str);
freeReplyObject(reply);
/* Try a GET and two INCR */
reply = redisCommand(c,"GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* again ... */
reply = redisCommand(c,"INCR counter");
printf("INCR counter: %lld\n", reply->integer);
freeReplyObject(reply);
/* Create a list of numbers, from 0 to 9 */
reply = redisCommand(c,"DEL mylist");
freeReplyObject(reply);
for (j = 0; j < 10; j++) {
char buf[64];
snprintf(buf,64,"%u",j);
reply = redisCommand(c,"LPUSH mylist element-%s", buf);
freeReplyObject(reply);
}
/* Let's check what we have inside the list */
reply = redisCommand(c,"LRANGE mylist 0 -1");
if (reply->type == REDIS_REPLY_ARRAY) {
for (j = 0; j < reply->elements; j++) {
printf("%u) %s\n", j, reply->element[j]->str);
}
}
freeReplyObject(reply);
/* Disconnects and frees the context */
redisFree(c);
return 0;
}
================================================
FILE: deps/hiredis/fmacros.h
================================================
#ifndef __HIREDIS_FMACRO_H
#define __HIREDIS_FMACRO_H
#if !defined(_BSD_SOURCE)
#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#endif
#if defined(_AIX)
#define _ALL_SOURCE
#endif
#if defined(__sun__)
#define _POSIX_C_SOURCE 200112L
#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE
#endif
#if __APPLE__ && __MACH__
#define _OSX
#endif
#endif
================================================
FILE: deps/hiredis/hiredis.c
================================================
/*
* Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>
* 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.
*/
#include "fmacros.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include "hiredis.h"
#include "net.h"
#include "sds.h"
static redisReply *createReplyObject(int type);
static void *createStringObject(const redisReadTask *task, char *str, size_t len);
static void *createArrayObject(const redisReadTask *task, int elements);
static void *createIntegerObject(const redisReadTask *task, long long value);
static void *createNilObject(const redisReadTask *task);
/* Default set of functions to build the reply. Keep in mind that such a
* function returning NULL is interpreted as OOM. */
static redisReplyObjectFunctions defaultFunctions = {
createStringObject,
createArrayObject,
createIntegerObject,
createNilObject,
freeReplyObject
};
/* Create a reply object */
static redisReply *createReplyObject(int type) {
redisReply *r = calloc(1,sizeof(*r));
if (r == NULL)
return NULL;
r->type = type;
return r;
}
/* Free a reply object */
void freeReplyObject(void *reply) {
redisReply *r = reply;
size_t j;
switch(r->type) {
case REDIS_REPLY_INTEGER:
break; /* Nothing to free */
case REDIS_REPLY_ARRAY:
if (r->element != NULL) {
for (j = 0; j < r->elements; j++)
if (r->element[j] != NULL)
freeReplyObject(r->element[j]);
free(r->element);
}
break;
case REDIS_REPLY_ERROR:
case REDIS_REPLY_STATUS:
case REDIS_REPLY_STRING:
if (r->str != NULL)
free(r->str);
break;
}
free(r);
}
static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
redisReply *r, *parent;
char *buf;
r = createReplyObject(task->type);
if (r == NULL)
return NULL;
buf = malloc(len+1);
if (buf == NULL) {
freeReplyObject(r);
return NULL;
}
assert(task->type == REDIS_REPLY_ERROR ||
task->type == REDIS_REPLY_STATUS ||
task->type == REDIS_REPLY_STRING);
/* Copy string value */
memcpy(buf,str,len);
buf[len] = '\0';
r->str = buf;
r->len = len;
if (task->parent) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY);
parent->element[task->idx] = r;
}
return r;
}
static void *createArrayObject(const redisReadTask *task, int elements) {
redisReply *r, *parent;
r = createReplyObject(REDIS_REPLY_ARRAY);
if (r == NULL)
return NULL;
if (elements > 0) {
r->element = calloc(elements,sizeof(redisReply*));
if (r->element == NULL) {
freeReplyObject(r);
return NULL;
}
}
r->elements = elements;
if (task->parent) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY);
parent->element[task->idx] = r;
}
return r;
}
static void *createIntegerObject(const redisReadTask *task, long long value) {
redisReply *r, *parent;
r = createReplyObject(REDIS_REPLY_INTEGER);
if (r == NULL)
return NULL;
r->integer = value;
if (task->parent) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY);
parent->element[task->idx] = r;
}
return r;
}
static void *createNilObject(const redisReadTask *task) {
redisReply *r, *parent;
r = createReplyObject(REDIS_REPLY_NIL);
if (r == NULL)
return NULL;
if (task->parent) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY);
parent->element[task->idx] = r;
}
return r;
}
static void __redisReaderSetError(redisReader *r, int type, const char *str) {
size_t len;
if (r->reply != NULL && r->fn && r->fn->freeObject) {
r->fn->freeObject(r->reply);
r->reply = NULL;
}
/* Clear input buffer on errors. */
if (r->buf != NULL) {
sdsfree(r->buf);
r->buf = NULL;
r->pos = r->len = 0;
}
/* Reset task stack. */
r->ridx = -1;
/* Set error. */
r->err = type;
len = strlen(str);
len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1);
memcpy(r->errstr,str,len);
r->errstr[len] = '\0';
}
static size_t chrtos(char *buf, size_t size, char byte) {
size_t len = 0;
switch(byte) {
case '\\':
case '"':
len = snprintf(buf,size,"\"\\%c\"",byte);
break;
case '\n': len = snprintf(buf,size,"\"\\n\""); break;
case '\r': len = snprintf(buf,size,"\"\\r\""); break;
case '\t': len = snprintf(buf,size,"\"\\t\""); break;
case '\a': len = snprintf(buf,size,"\"\\a\""); break;
case '\b': len = snprintf(buf,size,"\"\\b\""); break;
default:
if (isprint(byte))
len = snprintf(buf,size,"\"%c\"",byte);
else
len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte);
break;
}
return len;
}
static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
char cbuf[8], sbuf[128];
chrtos(cbuf,sizeof(cbuf),byte);
snprintf(sbuf,sizeof(sbuf),
"Protocol error, got %s as reply type byte", cbuf);
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf);
}
static void __redisReaderSetErrorOOM(redisReader *r) {
__redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory");
}
static char *readBytes(redisReader *r, unsigned int bytes) {
char *p;
if (r->len-r->pos >= bytes) {
p = r->buf+r->pos;
r->pos += bytes;
return p;
}
return NULL;
}
/* Find pointer to \r\n. */
static char *seekNewline(char *s, size_t len) {
int pos = 0;
int _len = len-1;
/* Position should be < len-1 because the character at "pos" should be
* followed by a \n. Note that strchr cannot be used because it doesn't
* allow to search a limited length and the buffer that is being searched
* might not have a trailing NULL character. */
while (pos < _len) {
while(pos < _len && s[pos] != '\r') pos++;
if (s[pos] != '\r') {
/* Not found. */
return NULL;
} else {
if (s[pos+1] == '\n') {
/* Found. */
return s+pos;
} else {
/* Continue searching. */
pos++;
}
}
}
return NULL;
}
/* Read a long long value starting at *s, under the assumption that it will be
* terminated by \r\n. Ambiguously returns -1 for unexpected input. */
static long long readLongLong(char *s) {
long long v = 0;
int dec, mult = 1;
char c;
if (*s == '-') {
mult = -1;
s++;
} else if (*s == '+') {
mult = 1;
s++;
}
while ((c = *(s++)) != '\r') {
dec = c - '0';
if (dec >= 0 && dec < 10) {
v *= 10;
v += dec;
} else {
/* Should not happen... */
return -1;
}
}
return mult*v;
}
static char *readLine(redisReader *r, int *_len) {
char *p, *s;
int len;
p = r->buf+r->pos;
s = seekNewline(p,(r->len-r->pos));
if (s != NULL) {
len = s-(r->buf+r->pos);
r->pos += len+2; /* skip \r\n */
if (_len) *_len = len;
return p;
}
return NULL;
}
static void moveToNextTask(redisReader *r) {
redisReadTask *cur, *prv;
while (r->ridx >= 0) {
/* Return a.s.a.p. when the stack is now empty. */
if (r->ridx == 0) {
r->ridx--;
return;
}
cur = &(r->rstack[r->ridx]);
prv = &(r->rstack[r->ridx-1]);
assert(prv->type == REDIS_REPLY_ARRAY);
if (cur->idx == prv->elements-1) {
r->ridx--;
} else {
/* Reset the type because the next item can be anything */
assert(cur->idx < prv->elements);
cur->type = -1;
cur->elements = -1;
cur->idx++;
return;
}
}
}
static int processLineItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
int len;
if ((p = readLine(r,&len)) != NULL) {
if (cur->type == REDIS_REPLY_INTEGER) {
if (r->fn && r->fn->createInteger)
obj = r->fn->createInteger(cur,readLongLong(p));
else
obj = (void*)REDIS_REPLY_INTEGER;
} else {
/* Type will be error or status. */
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,p,len);
else
obj = (void*)(size_t)(cur->type);
}
if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
/* Set reply if this is the root object. */
if (r->ridx == 0) r->reply = obj;
moveToNextTask(r);
return REDIS_OK;
}
return REDIS_ERR;
}
static int processBulkItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj = NULL;
char *p, *s;
long len;
unsigned long bytelen;
int success = 0;
p = r->buf+r->pos;
s = seekNewline(p,r->len-r->pos);
if (s != NULL) {
p = r->buf+r->pos;
bytelen = s-(r->buf+r->pos)+2; /* include \r\n */
len = readLongLong(p);
if (len < 0) {
/* The nil object can always be created. */
if (r->fn && r->fn->createNil)
obj = r->fn->createNil(cur);
else
obj = (void*)REDIS_REPLY_NIL;
success = 1;
} else {
/* Only continue when the buffer contains the entire bulk item. */
bytelen += len+2; /* include \r\n */
if (r->pos+bytelen <= r->len) {
if (r->fn && r->fn->createString)
obj = r->fn->createString(cur,s+2,len);
else
obj = (void*)REDIS_REPLY_STRING;
success = 1;
}
}
/* Proceed when obj was created. */
if (success) {
if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
r->pos += bytelen;
/* Set reply if this is the root object. */
if (r->ridx == 0) r->reply = obj;
moveToNextTask(r);
return REDIS_OK;
}
}
return REDIS_ERR;
}
static int processMultiBulkItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
void *obj;
char *p;
long elements;
int root = 0;
/* Set error for nested multi bulks with depth > 7 */
if (r->ridx == 8) {
__redisReaderSetError(r,REDIS_ERR_PROTOCOL,
"No support for nested multi bulk replies with depth > 7");
return REDIS_ERR;
}
if ((p = readLine(r,NULL)) != NULL) {
elements = readLongLong(p);
root = (r->ridx == 0);
if (elements == -1) {
if (r->fn && r->fn->createNil)
obj = r->fn->createNil(cur);
else
obj = (void*)REDIS_REPLY_NIL;
if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
moveToNextTask(r);
} else {
if (r->fn && r->fn->createArray)
obj = r->fn->createArray(cur,elements);
else
obj = (void*)REDIS_REPLY_ARRAY;
if (obj == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
/* Modify task stack when there are more than 0 elements. */
if (elements > 0) {
cur->elements = elements;
cur->obj = obj;
r->ridx++;
r->rstack[r->ridx].type = -1;
r->rstack[r->ridx].elements = -1;
r->rstack[r->ridx].idx = 0;
r->rstack[r->ridx].obj = NULL;
r->rstack[r->ridx].parent = cur;
r->rstack[r->ridx].privdata = r->privdata;
} else {
moveToNextTask(r);
}
}
/* Set reply if this is the root object. */
if (root) r->reply = obj;
return REDIS_OK;
}
return REDIS_ERR;
}
static int processItem(redisReader *r) {
redisReadTask *cur = &(r->rstack[r->ridx]);
char *p;
/* check if we need to read type */
if (cur->type < 0) {
if ((p = readBytes(r,1)) != NULL) {
switch (p[0]) {
case '-':
cur->type = REDIS_REPLY_ERROR;
break;
case '+':
cur->type = REDIS_REPLY_STATUS;
break;
case ':':
cur->type = REDIS_REPLY_INTEGER;
break;
case '$':
cur->type = REDIS_REPLY_STRING;
break;
case '*':
cur->type = REDIS_REPLY_ARRAY;
break;
default:
__redisReaderSetErrorProtocolByte(r,*p);
return REDIS_ERR;
}
} else {
/* could not consume 1 byte */
return REDIS_ERR;
}
}
/* process typed item */
switch(cur->type) {
case REDIS_REPLY_ERROR:
case REDIS_REPLY_STATUS:
case REDIS_REPLY_INTEGER:
return processLineItem(r);
case REDIS_REPLY_STRING:
return processBulkItem(r);
case REDIS_REPLY_ARRAY:
return processMultiBulkItem(r);
default:
assert(NULL);
return REDIS_ERR; /* Avoid warning. */
}
}
redisReader *redisReaderCreate(void) {
redisReader *r;
r = calloc(sizeof(redisReader),1);
if (r == NULL)
return NULL;
r->err = 0;
r->errstr[0] = '\0';
r->fn = &defaultFunctions;
r->buf = sdsempty();
r->maxbuf = REDIS_READER_MAX_BUF;
if (r->buf == NULL) {
free(r);
return NULL;
}
r->ridx = -1;
return r;
}
void redisReaderFree(redisReader *r) {
if (r->reply != NULL && r->fn && r->fn->freeObject)
r->fn->freeObject(r->reply);
if (r->buf != NULL)
sdsfree(r->buf);
free(r);
}
int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
sds newbuf;
/* Return early when this reader is in an erroneous state. */
if (r->err)
return REDIS_ERR;
/* Copy the provided buffer. */
if (buf != NULL && len >= 1) {
/* Destroy internal buffer when it is empty and is quite large. */
if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
sdsfree(r->buf);
r->buf = sdsempty();
r->pos = 0;
/* r->buf should not be NULL since we just free'd a larger one. */
assert(r->buf != NULL);
}
newbuf = sdscatlen(r->buf,buf,len);
if (newbuf == NULL) {
__redisReaderSetErrorOOM(r);
return REDIS_ERR;
}
r->buf = newbuf;
r->len = sdslen(r->buf);
}
return REDIS_OK;
}
int redisReaderGetReply(redisReader *r, void **reply) {
/* Default target pointer to NULL. */
if (reply != NULL)
*reply = NULL;
/* Return early when this reader is in an erroneous state. */
if (r->err)
return REDIS_ERR;
/* When the buffer is empty, there will never be a reply. */
if (r->len == 0)
return REDIS_OK;
/* Set first item to process when the stack is empty. */
if (r->ridx == -1) {
r->rstack[0].type = -1;
r->rstack[0].elements = -1;
r->rstack[0].idx = -1;
r->rstack[0].obj = NULL;
r->rstack[0].parent = NULL;
r->rstack[0].privdata = r->privdata;
r->ridx = 0;
}
/* Process items in reply. */
while (r->ridx >= 0)
if (processItem(r) != REDIS_OK)
break;
/* Return ASAP when an error occurred. */
if (r->err)
return REDIS_ERR;
/* 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) {
sdsrange(r->buf,r->pos,-1);
r->pos = 0;
r->len = sdslen(r->buf);
}
/* Emit a reply when there is one. */
if (r->ridx == -1) {
if (reply != NULL)
*reply = r->reply;
r->reply = NULL;
}
return REDIS_OK;
}
/* Calculate the number of bytes needed to represent an integer as string. */
static int intlen(int i) {
int len = 0;
if (i < 0) {
len++;
i = -i;
}
do {
len++;
i /= 10;
} while(i);
return len;
}
/* Helper that calculates the bulk length given a certain string length. */
static size_t bulklen(size_t len) {
return 1+intlen(len)+2+len+2;
}
int redisvFormatCommand(char **target, const char *format, va_list ap) {
const char *c = format;
char *cmd = NULL; /* final command */
int pos; /* position in final command */
sds curarg, newarg; /* current argument */
int touched = 0; /* was the current argument touched? */
char **curargv = NULL, **newargv = NULL;
int argc = 0;
int totlen = 0;
int j;
/* Abort if there is not target to set */
if (target == NULL)
return -1;
/* Build the command string accordingly to protocol */
curarg = sdsempty();
if (curarg == NULL)
return -1;
while(*c != '\0') {
if (*c != '%' || c[1] == '\0') {
if (*c == ' ') {
if (touched) {
newargv = realloc(curargv,sizeof(char*)*(argc+1));
if (newargv == NULL) goto err;
curargv = newargv;
curargv[argc++] = curarg;
totlen += bulklen(sdslen(curarg));
/* curarg is put in argv so it can be overwritten. */
curarg = sdsempty();
if (curarg == NULL) goto err;
touched = 0;
}
} else {
newarg = sdscatlen(curarg,c,1);
if (newarg == NULL) goto err;
curarg = newarg;
touched = 1;
}
} else {
char *arg;
size_t size;
/* Set newarg so it can be checked even if it is not touched. */
newarg = curarg;
switch(c[1]) {
case 's':
arg = va_arg(ap,char*);
size = strlen(arg);
if (size > 0)
newarg = sdscatlen(curarg,arg,size);
break;
case 'b':
arg = va_arg(ap,char*);
size = va_arg(ap,size_t);
if (size > 0)
newarg = sdscatlen(curarg,arg,size);
break;
case '%':
newarg = sdscat(curarg,"%");
break;
default:
/* Try to detect printf format */
{
static const char intfmts[] = "diouxX";
char _format[16];
const char *_p = c+1;
size_t _l = 0;
va_list _cpy;
/* Flags */
if (*_p != '\0' && *_p == '#') _p++;
if (*_p != '\0' && *_p == '0') _p++;
if (*_p != '\0' && *_p == '-') _p++;
if (*_p != '\0' && *_p == ' ') _p++;
if (*_p != '\0' && *_p == '+') _p++;
/* Field width */
while (*_p != '\0' && isdigit(*_p)) _p++;
/* Precision */
if (*_p == '.') {
_p++;
while (*_p != '\0' && isdigit(*_p)) _p++;
}
/* Copy va_list before consuming with va_arg */
va_copy(_cpy,ap);
/* Integer conversion (without modifiers) */
if (strchr(intfmts,*_p) != NULL) {
va_arg(ap,int);
goto fmt_valid;
}
/* Double conversion (without modifiers) */
if (strchr("eEfFgGaA",*_p) != NULL) {
va_arg(ap,double);
goto fmt_valid;
}
/* Size: char */
if (_p[0] == 'h' && _p[1] == 'h') {
_p += 2;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,int); /* char gets promoted to int */
goto fmt_valid;
}
goto fmt_invalid;
}
/* Size: short */
if (_p[0] == 'h') {
_p += 1;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,int); /* short gets promoted to int */
goto fmt_valid;
}
goto fmt_invalid;
}
/* Size: long long */
if (_p[0] == 'l' && _p[1] == 'l') {
_p += 2;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,long long);
goto fmt_valid;
}
goto fmt_invalid;
}
/* Size: long */
if (_p[0] == 'l') {
_p += 1;
if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
va_arg(ap,long);
goto fmt_valid;
}
goto fmt_invalid;
}
fmt_invalid:
va_end(_cpy);
goto err;
fmt_valid:
_l = (_p+1)-c;
if (_l < sizeof(_format)-2) {
memcpy(_format,c,_l);
_format[_l] = '\0';
newarg = sdscatvprintf(curarg,_format,_cpy);
/* Update current position (note: outer blocks
* increment c twice so compensate here) */
c = _p-1;
}
va_end(_cpy);
break;
}
}
if (newarg == NULL) goto err;
curarg = newarg;
touched = 1;
c++;
}
c++;
}
/* Add the last argument if needed */
if (touched) {
newargv = realloc(curargv,sizeof(char*)*(argc+1));
if (newargv == NULL) goto err;
curargv = newargv;
curargv[argc++] = curarg;
totlen += bulklen(sdslen(curarg));
} else {
sdsfree(curarg);
}
/* Clear curarg because it was put in curargv or was free'd. */
curarg = NULL;
/* Add bytes needed to hold multi bulk count */
totlen += 1+intlen(argc)+2;
/* Build the command at protocol level */
cmd = malloc(totlen+1);
if (cmd == NULL) goto err;
pos = sprintf(cmd,"*%d\r\n",argc);
for (j = 0; j < argc; j++) {
pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j]));
memcpy(cmd+pos,curargv[j],sdslen(curargv[j]));
pos += sdslen(curargv[j]);
sdsfree(c
gitextract_1opxwdmk/
├── .gitignore
├── .travis.yml
├── COPYING
├── Makefile
├── README.md
├── deps/
│ ├── Makefile
│ ├── README.md
│ ├── hiredis/
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── CHANGELOG.md
│ │ ├── COPYING
│ │ ├── Makefile
│ │ ├── README.md
│ │ ├── adapters/
│ │ │ ├── ae.h
│ │ │ ├── libev.h
│ │ │ ├── libevent.h
│ │ │ └── libuv.h
│ │ ├── async.c
│ │ ├── async.h
│ │ ├── dict.c
│ │ ├── dict.h
│ │ ├── examples/
│ │ │ ├── example-ae.c
│ │ │ ├── example-libev.c
│ │ │ ├── example-libevent.c
│ │ │ ├── example-libuv.c
│ │ │ └── example.c
│ │ ├── fmacros.h
│ │ ├── hiredis.c
│ │ ├── hiredis.h
│ │ ├── net.c
│ │ ├── net.h
│ │ ├── sds.c
│ │ ├── sds.h
│ │ ├── sdsalloc.h
│ │ ├── test.c
│ │ └── zmalloc.h
│ ├── jemalloc/
│ │ ├── .autom4te.cfg
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── COPYING
│ │ ├── ChangeLog
│ │ ├── INSTALL
│ │ ├── Makefile.in
│ │ ├── README
│ │ ├── VERSION
│ │ ├── autogen.sh
│ │ ├── bin/
│ │ │ ├── jemalloc-config.in
│ │ │ ├── jemalloc.sh.in
│ │ │ └── jeprof.in
│ │ ├── config.guess
│ │ ├── config.stamp.in
│ │ ├── config.sub
│ │ ├── configure
│ │ ├── configure.ac
│ │ ├── coverage.sh
│ │ ├── doc/
│ │ │ ├── html.xsl.in
│ │ │ ├── jemalloc.3
│ │ │ ├── jemalloc.html
│ │ │ ├── jemalloc.xml.in
│ │ │ ├── manpages.xsl.in
│ │ │ └── stylesheet.xsl
│ │ ├── include/
│ │ │ ├── jemalloc/
│ │ │ │ ├── internal/
│ │ │ │ │ ├── arena.h
│ │ │ │ │ ├── atomic.h
│ │ │ │ │ ├── base.h
│ │ │ │ │ ├── bitmap.h
│ │ │ │ │ ├── chunk.h
│ │ │ │ │ ├── chunk_dss.h
│ │ │ │ │ ├── chunk_mmap.h
│ │ │ │ │ ├── ckh.h
│ │ │ │ │ ├── ctl.h
│ │ │ │ │ ├── extent.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── huge.h
│ │ │ │ │ ├── jemalloc_internal.h.in
│ │ │ │ │ ├── jemalloc_internal_decls.h
│ │ │ │ │ ├── jemalloc_internal_defs.h.in
│ │ │ │ │ ├── jemalloc_internal_macros.h
│ │ │ │ │ ├── mb.h
│ │ │ │ │ ├── mutex.h
│ │ │ │ │ ├── pages.h
│ │ │ │ │ ├── private_namespace.sh
│ │ │ │ │ ├── private_symbols.txt
│ │ │ │ │ ├── private_unnamespace.sh
│ │ │ │ │ ├── prng.h
│ │ │ │ │ ├── prof.h
│ │ │ │ │ ├── public_namespace.sh
│ │ │ │ │ ├── public_unnamespace.sh
│ │ │ │ │ ├── ql.h
│ │ │ │ │ ├── qr.h
│ │ │ │ │ ├── quarantine.h
│ │ │ │ │ ├── rb.h
│ │ │ │ │ ├── rtree.h
│ │ │ │ │ ├── size_classes.sh
│ │ │ │ │ ├── stats.h
│ │ │ │ │ ├── tcache.h
│ │ │ │ │ ├── tsd.h
│ │ │ │ │ ├── util.h
│ │ │ │ │ └── valgrind.h
│ │ │ │ ├── jemalloc.sh
│ │ │ │ ├── jemalloc_defs.h.in
│ │ │ │ ├── jemalloc_macros.h.in
│ │ │ │ ├── jemalloc_mangle.sh
│ │ │ │ ├── jemalloc_protos.h.in
│ │ │ │ ├── jemalloc_rename.sh
│ │ │ │ └── jemalloc_typedefs.h.in
│ │ │ └── msvc_compat/
│ │ │ ├── C99/
│ │ │ │ ├── stdbool.h
│ │ │ │ └── stdint.h
│ │ │ ├── strings.h
│ │ │ └── windows_extra.h
│ │ ├── install-sh
│ │ ├── jemalloc.pc.in
│ │ ├── src/
│ │ │ ├── arena.c
│ │ │ ├── atomic.c
│ │ │ ├── base.c
│ │ │ ├── bitmap.c
│ │ │ ├── chunk.c
│ │ │ ├── chunk_dss.c
│ │ │ ├── chunk_mmap.c
│ │ │ ├── ckh.c
│ │ │ ├── ctl.c
│ │ │ ├── extent.c
│ │ │ ├── hash.c
│ │ │ ├── huge.c
│ │ │ ├── jemalloc.c
│ │ │ ├── mb.c
│ │ │ ├── mutex.c
│ │ │ ├── pages.c
│ │ │ ├── prof.c
│ │ │ ├── quarantine.c
│ │ │ ├── rtree.c
│ │ │ ├── stats.c
│ │ │ ├── tcache.c
│ │ │ ├── tsd.c
│ │ │ ├── util.c
│ │ │ ├── valgrind.c
│ │ │ └── zone.c
│ │ └── test/
│ │ ├── include/
│ │ │ └── test/
│ │ │ ├── SFMT-alti.h
│ │ │ ├── SFMT-params.h
│ │ │ ├── SFMT-params11213.h
│ │ │ ├── SFMT-params1279.h
│ │ │ ├── SFMT-params132049.h
│ │ │ ├── SFMT-params19937.h
│ │ │ ├── SFMT-params216091.h
│ │ │ ├── SFMT-params2281.h
│ │ │ ├── SFMT-params4253.h
│ │ │ ├── SFMT-params44497.h
│ │ │ ├── SFMT-params607.h
│ │ │ ├── SFMT-params86243.h
│ │ │ ├── SFMT-sse2.h
│ │ │ ├── SFMT.h
│ │ │ ├── btalloc.h
│ │ │ ├── jemalloc_test.h.in
│ │ │ ├── jemalloc_test_defs.h.in
│ │ │ ├── math.h
│ │ │ ├── mq.h
│ │ │ ├── mtx.h
│ │ │ ├── test.h
│ │ │ ├── thd.h
│ │ │ └── timer.h
│ │ ├── integration/
│ │ │ ├── MALLOCX_ARENA.c
│ │ │ ├── aligned_alloc.c
│ │ │ ├── allocated.c
│ │ │ ├── chunk.c
│ │ │ ├── mallocx.c
│ │ │ ├── overflow.c
│ │ │ ├── posix_memalign.c
│ │ │ ├── rallocx.c
│ │ │ ├── sdallocx.c
│ │ │ ├── thread_arena.c
│ │ │ ├── thread_tcache_enabled.c
│ │ │ └── xallocx.c
│ │ ├── src/
│ │ │ ├── SFMT.c
│ │ │ ├── btalloc.c
│ │ │ ├── btalloc_0.c
│ │ │ ├── btalloc_1.c
│ │ │ ├── math.c
│ │ │ ├── mq.c
│ │ │ ├── mtx.c
│ │ │ ├── test.c
│ │ │ ├── thd.c
│ │ │ └── timer.c
│ │ ├── stress/
│ │ │ └── microbench.c
│ │ ├── test.sh.in
│ │ └── unit/
│ │ ├── SFMT.c
│ │ ├── atomic.c
│ │ ├── bitmap.c
│ │ ├── ckh.c
│ │ ├── hash.c
│ │ ├── junk.c
│ │ ├── junk_alloc.c
│ │ ├── junk_free.c
│ │ ├── lg_chunk.c
│ │ ├── mallctl.c
│ │ ├── math.c
│ │ ├── mq.c
│ │ ├── mtx.c
│ │ ├── prof_accum.c
│ │ ├── prof_active.c
│ │ ├── prof_gdump.c
│ │ ├── prof_idump.c
│ │ ├── prof_reset.c
│ │ ├── prof_thread_name.c
│ │ ├── ql.c
│ │ ├── qr.c
│ │ ├── quarantine.c
│ │ ├── rb.c
│ │ ├── rtree.c
│ │ ├── size_classes.c
│ │ ├── stats.c
│ │ ├── tsd.c
│ │ ├── util.c
│ │ └── zero.c
│ ├── linenoise/
│ │ ├── .gitignore
│ │ ├── Makefile
│ │ ├── README.markdown
│ │ ├── example.c
│ │ ├── linenoise.c
│ │ └── linenoise.h
│ └── update-jemalloc.sh
├── disque.conf
├── runtest
├── src/
│ ├── .gitignore
│ ├── 00-RELEASENOTES
│ ├── Makefile
│ ├── Makefile.dep
│ ├── ack.c
│ ├── ack.h
│ ├── adlist.c
│ ├── adlist.h
│ ├── ae.c
│ ├── ae.h
│ ├── ae_epoll.c
│ ├── ae_evport.c
│ ├── ae_kqueue.c
│ ├── ae_select.c
│ ├── anet.c
│ ├── anet.h
│ ├── aof.c
│ ├── asciilogo.h
│ ├── atomicvar.h
│ ├── bio.c
│ ├── bio.h
│ ├── blocked.c
│ ├── cluster.c
│ ├── cluster.h
│ ├── config.c
│ ├── config.h
│ ├── crc64.c
│ ├── crc64.h
│ ├── debug.c
│ ├── dict.c
│ ├── dict.h
│ ├── disque-check-aof.c
│ ├── disque-cli.c
│ ├── disqueassert.h
│ ├── endianconv.c
│ ├── endianconv.h
│ ├── fmacros.h
│ ├── help.h
│ ├── job.c
│ ├── job.h
│ ├── latency.c
│ ├── latency.h
│ ├── lzf.h
│ ├── lzfP.h
│ ├── lzf_c.c
│ ├── lzf_d.c
│ ├── memtest.c
│ ├── mkreleasehdr.sh
│ ├── networking.c
│ ├── object.c
│ ├── pqsort.c
│ ├── pqsort.h
│ ├── queue.c
│ ├── queue.h
│ ├── release.c
│ ├── rio.c
│ ├── rio.h
│ ├── sds.c
│ ├── sds.h
│ ├── sdsalloc.h
│ ├── server.c
│ ├── server.h
│ ├── setproctitle.c
│ ├── sha1.c
│ ├── sha1.h
│ ├── skiplist.c
│ ├── skiplist.h
│ ├── slowlog.c
│ ├── slowlog.h
│ ├── solarisfixes.h
│ ├── sparkline.c
│ ├── sparkline.h
│ ├── syncio.c
│ ├── testhelp.h
│ ├── util.c
│ ├── util.h
│ ├── valgrind.sup
│ ├── version.h
│ ├── zmalloc.c
│ └── zmalloc.h
└── tests/
├── cluster/
│ ├── cluster.tcl
│ ├── run.tcl
│ ├── tests/
│ │ ├── 00-base.tcl
│ │ ├── 01-faildet.tcl
│ │ ├── 02-jobs-replication.tcl
│ │ ├── 03-jobs-queueing.tcl
│ │ ├── 04-ttl.tcl
│ │ ├── 05-acks.tcl
│ │ ├── 06-federation.tcl
│ │ ├── 07-persistence.tcl
│ │ ├── 08-qscan.tcl
│ │ ├── 09-jscan.tcl
│ │ ├── 10-leaving.tcl
│ │ ├── 11-waiting-nack.tcl
│ │ ├── 12-nack-and-counters.tcl
│ │ └── includes/
│ │ ├── init-tests.tcl
│ │ └── job-utils.tcl
│ └── tmp/
│ └── .gitignore
├── instances.tcl
├── support/
│ ├── cluster.tcl
│ ├── redis.tcl
│ ├── server.tcl
│ ├── test.tcl
│ ├── tmpfile.tcl
│ └── util.tcl
└── test_helper.tcl
SYMBOL INDEX (2281 symbols across 177 files)
FILE: deps/hiredis/adapters/ae.h
type redisAeEvents (line 38) | typedef struct redisAeEvents {
function redisAeReadEvent (line 45) | static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, in...
function redisAeWriteEvent (line 52) | static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, i...
function redisAeAddRead (line 59) | static void redisAeAddRead(void *privdata) {
function redisAeDelRead (line 68) | static void redisAeDelRead(void *privdata) {
function redisAeAddWrite (line 77) | static void redisAeAddWrite(void *privdata) {
function redisAeDelWrite (line 86) | static void redisAeDelWrite(void *privdata) {
function redisAeCleanup (line 95) | static void redisAeCleanup(void *privdata) {
function redisAeAttach (line 102) | static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
FILE: deps/hiredis/adapters/libev.h
type redisLibevEvents (line 39) | typedef struct redisLibevEvents {
function redisLibevReadEvent (line 46) | static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
function redisLibevWriteEvent (line 56) | static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
function redisLibevAddRead (line 66) | static void redisLibevAddRead(void *privdata) {
function redisLibevDelRead (line 76) | static void redisLibevDelRead(void *privdata) {
function redisLibevAddWrite (line 86) | static void redisLibevAddWrite(void *privdata) {
function redisLibevDelWrite (line 96) | static void redisLibevDelWrite(void *privdata) {
function redisLibevCleanup (line 106) | static void redisLibevCleanup(void *privdata) {
function redisLibevAttach (line 113) | static int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
FILE: deps/hiredis/adapters/libevent.h
type redisLibeventEvents (line 37) | typedef struct redisLibeventEvents {
function redisLibeventReadEvent (line 42) | static void redisLibeventReadEvent(int fd, short event, void *arg) {
function redisLibeventWriteEvent (line 48) | static void redisLibeventWriteEvent(int fd, short event, void *arg) {
function redisLibeventAddRead (line 54) | static void redisLibeventAddRead(void *privdata) {
function redisLibeventDelRead (line 59) | static void redisLibeventDelRead(void *privdata) {
function redisLibeventAddWrite (line 64) | static void redisLibeventAddWrite(void *privdata) {
function redisLibeventDelWrite (line 69) | static void redisLibeventDelWrite(void *privdata) {
function redisLibeventCleanup (line 74) | static void redisLibeventCleanup(void *privdata) {
function redisLibeventAttach (line 81) | static int redisLibeventAttach(redisAsyncContext *ac, struct event_base ...
FILE: deps/hiredis/adapters/libuv.h
type redisLibuvEvents (line 8) | typedef struct redisLibuvEvents {
function redisLibuvPoll (line 16) | static void redisLibuvPoll(uv_poll_t* handle, int status, int events) {
function redisLibuvAddRead (line 32) | static void redisLibuvAddRead(void *privdata) {
function redisLibuvDelRead (line 41) | static void redisLibuvDelRead(void *privdata) {
function redisLibuvAddWrite (line 54) | static void redisLibuvAddWrite(void *privdata) {
function redisLibuvDelWrite (line 63) | static void redisLibuvDelWrite(void *privdata) {
function on_close (line 76) | static void on_close(uv_handle_t* handle) {
function redisLibuvCleanup (line 83) | static void redisLibuvCleanup(void *privdata) {
function redisLibuvAttach (line 90) | static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) {
FILE: deps/hiredis/async.c
function callbackHash (line 64) | static unsigned int callbackHash(const void *key) {
function callbackKeyCompare (line 76) | static int callbackKeyCompare(void *privdata, const void *key1, const vo...
function callbackKeyDestructor (line 86) | static void callbackKeyDestructor(void *privdata, void *key) {
function callbackValDestructor (line 91) | static void callbackValDestructor(void *privdata, void *val) {
function redisAsyncContext (line 105) | static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
function __redisAsyncCopyError (line 144) | static void __redisAsyncCopyError(redisAsyncContext *ac) {
function redisAsyncContext (line 150) | redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
function redisAsyncContext (line 168) | redisAsyncContext *redisAsyncConnectBind(const char *ip, int port,
function redisAsyncContext (line 176) | redisAsyncContext *redisAsyncConnectUnix(const char *path) {
function redisAsyncSetConnectCallback (line 194) | int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCall...
function redisAsyncSetDisconnectCallback (line 207) | int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconne...
function __redisPushCallback (line 216) | static int __redisPushCallback(redisCallbackList *list, redisCallback *s...
function __redisShiftCallback (line 238) | static int __redisShiftCallback(redisCallbackList *list, redisCallback *...
function __redisRunCallback (line 254) | static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb,...
function __redisAsyncFree (line 264) | static void __redisAsyncFree(redisAsyncContext *ac) {
function redisAsyncFree (line 312) | void redisAsyncFree(redisAsyncContext *ac) {
function __redisAsyncDisconnect (line 320) | static void __redisAsyncDisconnect(redisAsyncContext *ac) {
function redisAsyncDisconnect (line 346) | void redisAsyncDisconnect(redisAsyncContext *ac) {
function __redisGetSubscribeCallback (line 353) | static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply...
function redisProcessCallbacks (line 400) | void redisProcessCallbacks(redisAsyncContext *ac) {
function __redisAsyncHandleConnect (line 481) | static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
function redisAsyncHandleRead (line 503) | void redisAsyncHandleRead(redisAsyncContext *ac) {
function redisAsyncHandleWrite (line 524) | void redisAsyncHandleWrite(redisAsyncContext *ac) {
function __redisAsyncCommand (line 570) | static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *f...
function redisvAsyncCommand (line 634) | int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void ...
function redisAsyncCommand (line 644) | int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *...
function redisAsyncCommandArgv (line 653) | int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, vo...
FILE: deps/hiredis/async.h
type redisAsyncContext (line 40) | struct redisAsyncContext
type dict (line 41) | struct dict
type redisAsyncContext (line 44) | struct redisAsyncContext
type redisCallback (line 45) | typedef struct redisCallback {
type redisCallbackList (line 52) | typedef struct redisCallbackList {
type redisAsyncContext (line 57) | struct redisAsyncContext
type redisAsyncContext (line 58) | struct redisAsyncContext
type redisAsyncContext (line 61) | typedef struct redisAsyncContext {
FILE: deps/hiredis/dict.c
function dictGenHashFunction (line 53) | static unsigned int dictGenHashFunction(const unsigned char *buf, int le...
function _dictReset (line 65) | static void _dictReset(dict *ht) {
function dict (line 73) | static dict *dictCreate(dictType *type, void *privDataPtr) {
function _dictInit (line 80) | static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
function dictExpand (line 88) | static int dictExpand(dict *ht, unsigned long size) {
function dictAdd (line 135) | static int dictAdd(dict *ht, void *key, void *val) {
function dictReplace (line 160) | static int dictReplace(dict *ht, void *key, void *val) {
function dictDelete (line 182) | static int dictDelete(dict *ht, const void *key) {
function _dictClear (line 213) | static int _dictClear(dict *ht) {
function dictRelease (line 238) | static void dictRelease(dict *ht) {
function dictEntry (line 243) | static dictEntry *dictFind(dict *ht, const void *key) {
function dictIterator (line 258) | static dictIterator *dictGetIterator(dict *ht) {
function dictEntry (line 268) | static dictEntry *dictNext(dictIterator *iter) {
function dictReleaseIterator (line 288) | static void dictReleaseIterator(dictIterator *iter) {
function _dictExpandIfNeeded (line 295) | static int _dictExpandIfNeeded(dict *ht) {
function _dictNextPower (line 306) | static unsigned long _dictNextPower(unsigned long size) {
function _dictKeyIndex (line 320) | static int _dictKeyIndex(dict *ht, const void *key) {
FILE: deps/hiredis/dict.h
type dictEntry (line 45) | typedef struct dictEntry {
type dictType (line 51) | typedef struct dictType {
type dict (line 60) | typedef struct dict {
type dictIterator (line 69) | typedef struct dictIterator {
FILE: deps/hiredis/examples/example-ae.c
function getCallback (line 13) | void getCallback(redisAsyncContext *c, void *r, void *privdata) {
function connectCallback (line 22) | void connectCallback(const redisAsyncContext *c, int status) {
function disconnectCallback (line 32) | void disconnectCallback(const redisAsyncContext *c, int status) {
function main (line 43) | int main (int argc, char **argv) {
FILE: deps/hiredis/examples/example-libev.c
function getCallback (line 10) | void getCallback(redisAsyncContext *c, void *r, void *privdata) {
function connectCallback (line 19) | void connectCallback(const redisAsyncContext *c, int status) {
function disconnectCallback (line 27) | void disconnectCallback(const redisAsyncContext *c, int status) {
function main (line 35) | int main (int argc, char **argv) {
FILE: deps/hiredis/examples/example-libevent.c
function getCallback (line 10) | void getCallback(redisAsyncContext *c, void *r, void *privdata) {
function connectCallback (line 19) | void connectCallback(const redisAsyncContext *c, int status) {
function disconnectCallback (line 27) | void disconnectCallback(const redisAsyncContext *c, int status) {
function main (line 35) | int main (int argc, char **argv) {
FILE: deps/hiredis/examples/example-libuv.c
function getCallback (line 10) | void getCallback(redisAsyncContext *c, void *r, void *privdata) {
function connectCallback (line 19) | void connectCallback(const redisAsyncContext *c, int status) {
function disconnectCallback (line 27) | void disconnectCallback(const redisAsyncContext *c, int status) {
function main (line 35) | int main (int argc, char **argv) {
FILE: deps/hiredis/examples/example.c
function main (line 7) | int main(int argc, char **argv) {
FILE: deps/hiredis/hiredis.c
function redisReply (line 61) | static redisReply *createReplyObject(int type) {
function freeReplyObject (line 72) | void freeReplyObject(void *reply) {
function __redisReaderSetError (line 186) | static void __redisReaderSetError(redisReader *r, int type, const char *...
function chrtos (line 212) | static size_t chrtos(char *buf, size_t size, char byte) {
function __redisReaderSetErrorProtocolByte (line 236) | static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) {
function __redisReaderSetErrorOOM (line 245) | static void __redisReaderSetErrorOOM(redisReader *r) {
function readLongLong (line 288) | static long long readLongLong(char *s) {
function moveToNextTask (line 330) | static void moveToNextTask(redisReader *r) {
function processLineItem (line 355) | static int processLineItem(redisReader *r) {
function processBulkItem (line 389) | static int processBulkItem(redisReader *r) {
function processMultiBulkItem (line 442) | static int processMultiBulkItem(redisReader *r) {
function processItem (line 507) | static int processItem(redisReader *r) {
function redisReader (line 556) | redisReader *redisReaderCreate(void) {
function redisReaderFree (line 577) | void redisReaderFree(redisReader *r) {
function redisReaderFeed (line 585) | int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
function redisReaderGetReply (line 617) | int redisReaderGetReply(redisReader *r, void **reply) {
function intlen (line 668) | static int intlen(int i) {
function bulklen (line 682) | static size_t bulklen(size_t len) {
function redisvFormatCommand (line 686) | int redisvFormatCommand(char **target, const char *format, va_list ap) {
function redisFormatCommand (line 925) | int redisFormatCommand(char **target, const char *format, ...) {
function redisFormatCommandArgv (line 939) | int redisFormatCommandArgv(char **target, int argc, const char **argv, c...
function __redisSetError (line 973) | void __redisSetError(redisContext *c, int type, const char *str) {
function redisContext (line 989) | static redisContext *redisContextInit(void) {
function redisFree (line 1003) | void redisFree(redisContext *c) {
function redisFreeKeepFd (line 1013) | int redisFreeKeepFd(redisContext *c) {
function redisContext (line 1023) | redisContext *redisConnect(const char *ip, int port) {
function redisContext (line 1035) | redisContext *redisConnectWithTimeout(const char *ip, int port, const st...
function redisContext (line 1047) | redisContext *redisConnectNonBlock(const char *ip, int port) {
function redisContext (line 1059) | redisContext *redisConnectBindNonBlock(const char *ip, int port,
function redisContext (line 1067) | redisContext *redisConnectUnix(const char *path) {
function redisContext (line 1079) | redisContext *redisConnectUnixWithTimeout(const char *path, const struct...
function redisContext (line 1091) | redisContext *redisConnectUnixNonBlock(const char *path) {
function redisContext (line 1103) | redisContext *redisConnectFd(int fd) {
function redisSetTimeout (line 1116) | int redisSetTimeout(redisContext *c, const struct timeval tv) {
function redisEnableKeepAlive (line 1123) | int redisEnableKeepAlive(redisContext *c) {
function redisBufferRead (line 1134) | int redisBufferRead(redisContext *c) {
function redisBufferWrite (line 1171) | int redisBufferWrite(redisContext *c, int *done) {
function redisGetReplyFromReader (line 1202) | int redisGetReplyFromReader(redisContext *c, void **reply) {
function redisGetReply (line 1210) | int redisGetReply(redisContext *c, void **reply) {
function __redisAppendCommand (line 1247) | int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) {
function redisAppendFormattedCommand (line 1260) | int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t...
function redisvAppendCommand (line 1269) | int redisvAppendCommand(redisContext *c, const char *format, va_list ap) {
function redisAppendCommand (line 1288) | int redisAppendCommand(redisContext *c, const char *format, ...) {
function redisAppendCommandArgv (line 1298) | int redisAppendCommandArgv(redisContext *c, int argc, const char **argv,...
FILE: deps/hiredis/hiredis.h
type redisReply (line 98) | typedef struct redisReply {
type redisReadTask (line 107) | typedef struct redisReadTask {
type redisReplyObjectFunctions (line 116) | typedef struct redisReplyObjectFunctions {
type redisReader (line 125) | typedef struct redisReader {
type redisContext (line 166) | typedef struct redisContext {
type timeval (line 176) | struct timeval
type timeval (line 180) | struct timeval
type timeval (line 183) | struct timeval
FILE: deps/hiredis/net.c
function redisContextCloseFd (line 57) | static void redisContextCloseFd(redisContext *c) {
function __redisSetErrorFromErrno (line 64) | static void __redisSetErrorFromErrno(redisContext *c, int type, const ch...
function redisSetReuseAddr (line 74) | static int redisSetReuseAddr(redisContext *c) {
function redisCreateSocket (line 84) | static int redisCreateSocket(redisContext *c, int type) {
function redisSetBlocking (line 99) | static int redisSetBlocking(redisContext *c, int blocking) {
function redisKeepAlive (line 124) | int redisKeepAlive(redisContext *c, int interval) {
function redisSetTcpNoDelay (line 166) | static int redisSetTcpNoDelay(redisContext *c) {
function redisContextWaitReady (line 178) | static int redisContextWaitReady(redisContext *c, const struct timeval *...
function redisCheckSocketError (line 226) | int redisCheckSocketError(redisContext *c) {
function redisContextSetTimeout (line 244) | int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
function _redisContextConnectTcp (line 256) | static int _redisContextConnectTcp(redisContext *c, const char *addr, in...
function redisContextConnectTcp (line 345) | int redisContextConnectTcp(redisContext *c, const char *addr, int port,
function redisContextConnectBindTcp (line 350) | int redisContextConnectBindTcp(redisContext *c, const char *addr, int port,
function redisContextConnectUnix (line 356) | int redisContextConnectUnix(redisContext *c, const char *path, const str...
FILE: deps/hiredis/net.h
type timeval (line 43) | struct timeval
type timeval (line 44) | struct timeval
type timeval (line 46) | struct timeval
type timeval (line 48) | struct timeval
FILE: deps/hiredis/sds.c
function sdsHdrSize (line 41) | static inline int sdsHdrSize(char type) {
function sdsReqType (line 57) | static inline char sdsReqType(size_t string_size) {
function sds (line 81) | sds sdsnewlen(const void *init, size_t initlen) {
function sds (line 139) | sds sdsempty(void) {
function sds (line 144) | sds sdsnew(const char *init) {
function sds (line 150) | sds sdsdup(const sds s) {
function sdsfree (line 155) | void sdsfree(sds s) {
function sdsupdatelen (line 174) | void sdsupdatelen(sds s) {
function sdsclear (line 183) | void sdsclear(sds s) {
function sds (line 194) | sds sdsMakeRoomFor(sds s, size_t addlen) {
function sds (line 245) | sds sdsRemoveFreeSpace(sds s) {
function sdsAllocSize (line 278) | size_t sdsAllocSize(sds s) {
function sdsIncrLen (line 312) | void sdsIncrLen(sds s, int incr) {
function sds (line 358) | sds sdsgrowzero(sds s, size_t len) {
function sds (line 376) | sds sdscatlen(sds s, const void *t, size_t len) {
function sds (line 391) | sds sdscat(sds s, const char *t) {
function sds (line 399) | sds sdscatsds(sds s, const sds t) {
function sds (line 405) | sds sdscpylen(sds s, const char *t, size_t len) {
function sds (line 418) | sds sdscpy(sds s, const char *t) {
function sdsll2str (line 429) | int sdsll2str(char *s, long long value) {
function sdsull2str (line 461) | int sdsull2str(char *s, unsigned long long v) {
function sds (line 493) | sds sdsfromlonglong(long long value) {
function sds (line 501) | sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
function sds (line 554) | sds sdscatprintf(sds s, const char *fmt, ...) {
function sds (line 579) | sds sdscatfmt(sds s, char const *fmt, ...) {
function sds (line 683) | sds sdstrim(sds s, const char *cset) {
function sdsrange (line 714) | void sdsrange(sds s, int start, int end) {
function sdstolower (line 743) | void sdstolower(sds s) {
function sdstoupper (line 750) | void sdstoupper(sds s) {
function sdscmp (line 767) | int sdscmp(const sds s1, const sds s2) {
function sds (line 795) | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, in...
function sdsfreesplitres (line 845) | void sdsfreesplitres(sds *tokens, int count) {
function sds (line 858) | sds sdscatrepr(sds s, const char *p, size_t len) {
function is_hex_digit (line 885) | int is_hex_digit(char c) {
function hex_digit_to_int (line 892) | int hex_digit_to_int(char c) {
function sds (line 933) | sds *sdssplitargs(const char *line, int *argc) {
function sds (line 1052) | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
function sds (line 1068) | sds sdsjoin(char **argv, int argc, char *sep) {
function sds (line 1080) | sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
function sdsTest (line 1097) | int sdsTest(void) {
function main (line 1262) | int main(void) {
FILE: deps/hiredis/sds.h
type sdshdr5 (line 46) | struct __attribute__ ((__packed__)) sdshdr5 {
type sdshdr8 (line 50) | struct __attribute__ ((__packed__)) sdshdr8 {
type sdshdr16 (line 56) | struct __attribute__ ((__packed__)) sdshdr16 {
type sdshdr32 (line 62) | struct __attribute__ ((__packed__)) sdshdr32 {
type sdshdr64 (line 68) | struct __attribute__ ((__packed__)) sdshdr64 {
function sdslen (line 86) | static inline size_t sdslen(const sds s) {
function sdsavail (line 103) | static inline size_t sdsavail(const sds s) {
function sdssetlen (line 129) | static inline void sdssetlen(sds s, size_t newlen) {
function sdsinclen (line 153) | static inline void sdsinclen(sds s, size_t inc) {
function sdsalloc (line 179) | static inline size_t sdsalloc(const sds s) {
function sdssetalloc (line 196) | static inline void sdssetalloc(sds s, size_t newlen) {
FILE: deps/hiredis/test.c
type connection_type (line 15) | enum connection_type {
type config (line 21) | struct config {
function usec (line 40) | static long long usec(void) {
function redisContext (line 46) | static redisContext *select_database(redisContext *c) {
function disconnect (line 68) | static int disconnect(redisContext *c, int keep_fd) {
function redisContext (line 86) | static redisContext *connect(struct config config) {
function test_format_commands (line 116) | static void test_format_commands(void) {
function test_append_formatted_commands (line 220) | static void test_append_formatted_commands(struct config config) {
function test_reply_reader (line 242) | static void test_reply_reader(void) {
function test_blocking_connection_errors (line 321) | static void test_blocking_connection_errors(void) {
function test_blocking_connection (line 346) | static void test_blocking_connection(struct config config) {
function test_blocking_io_errors (line 424) | static void test_blocking_io_errors(struct config config) {
function test_invalid_timeout_errors (line 475) | static void test_invalid_timeout_errors(struct config config) {
function test_throughput (line 499) | static void test_throughput(struct config config) {
function main (line 663) | int main(int argc, char **argv) {
FILE: deps/jemalloc/include/jemalloc/internal/arena.h
type arena_runs_dirty_link_t (line 26) | typedef struct arena_runs_dirty_link_s arena_runs_dirty_link_t;
type arena_run_t (line 27) | typedef struct arena_run_s arena_run_t;
type arena_chunk_map_bits_t (line 28) | typedef struct arena_chunk_map_bits_s arena_chunk_map_bits_t;
type arena_chunk_map_misc_t (line 29) | typedef struct arena_chunk_map_misc_s arena_chunk_map_misc_t;
type arena_chunk_t (line 30) | typedef struct arena_chunk_s arena_chunk_t;
type arena_bin_info_t (line 31) | typedef struct arena_bin_info_s arena_bin_info_t;
type arena_bin_t (line 32) | typedef struct arena_bin_s arena_bin_t;
type arena_t (line 33) | typedef struct arena_s arena_t;
type arena_run_s (line 40) | struct arena_run_s {
type arena_chunk_map_bits_s (line 52) | struct arena_chunk_map_bits_s {
type arena_runs_dirty_link_s (line 132) | struct arena_runs_dirty_link_s {
type arena_chunk_map_misc_s (line 141) | struct arena_chunk_map_misc_s {
type arena_avail_tree_t (line 165) | typedef rb_tree(arena_chunk_map_misc_t) arena_avail_tree_t;
type arena_run_tree_t (line 166) | typedef rb_tree(arena_chunk_map_misc_t) arena_run_tree_t;
type arena_chunk_s (line 171) | struct arena_chunk_s {
type arena_bin_info_s (line 221) | struct arena_bin_info_s {
type arena_bin_s (line 247) | struct arena_bin_s {
type arena_s (line 275) | struct arena_s {
function JEMALLOC_ALWAYS_INLINE (line 571) | JEMALLOC_ALWAYS_INLINE arena_chunk_map_bits_t *
function JEMALLOC_ALWAYS_INLINE (line 581) | JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t *
function JEMALLOC_ALWAYS_INLINE (line 592) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 605) | JEMALLOC_ALWAYS_INLINE void *
function JEMALLOC_ALWAYS_INLINE (line 614) | JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t *
function JEMALLOC_ALWAYS_INLINE (line 626) | JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t *
function JEMALLOC_ALWAYS_INLINE (line 638) | JEMALLOC_ALWAYS_INLINE size_t *
function JEMALLOC_ALWAYS_INLINE (line 645) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 652) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 659) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 675) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 685) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 696) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 707) | JEMALLOC_ALWAYS_INLINE szind_t
function JEMALLOC_ALWAYS_INLINE (line 719) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 730) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 741) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 752) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 761) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 770) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 777) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 794) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 808) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 821) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 830) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 845) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 859) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_INLINE (line 872) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 879) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 886) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 893) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 908) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 919) | JEMALLOC_INLINE bool
function JEMALLOC_ALWAYS_INLINE (line 938) | JEMALLOC_ALWAYS_INLINE szind_t
function JEMALLOC_INLINE (line 987) | JEMALLOC_INLINE szind_t
function arena_run_regind (line 995) | JEMALLOC_INLINE unsigned
function JEMALLOC_INLINE (line 1069) | JEMALLOC_INLINE prof_tctx_t *
function JEMALLOC_INLINE (line 1096) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 1131) | JEMALLOC_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 1160) | JEMALLOC_ALWAYS_INLINE void *
function JEMALLOC_ALWAYS_INLINE (line 1191) | JEMALLOC_ALWAYS_INLINE arena_t *
function JEMALLOC_ALWAYS_INLINE (line 1204) | JEMALLOC_ALWAYS_INLINE size_t
function JEMALLOC_ALWAYS_INLINE (line 1253) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 1296) | JEMALLOC_ALWAYS_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/atomic.h
function JEMALLOC_INLINE (line 71) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 85) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 101) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 117) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 129) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 136) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 143) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 150) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 157) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 170) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 179) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 188) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 197) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 204) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 211) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 218) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 229) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 236) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 243) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 252) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 260) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 267) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 274) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 281) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 295) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 309) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 325) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 341) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 353) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 360) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 367) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 374) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 381) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 388) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 395) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 402) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 409) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 416) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 423) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 430) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 441) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 448) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 455) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 464) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 472) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 479) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 486) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 493) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 505) | JEMALLOC_INLINE void *
function JEMALLOC_INLINE (line 516) | JEMALLOC_INLINE void *
function JEMALLOC_INLINE (line 529) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 540) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 553) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 564) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 577) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 588) | JEMALLOC_INLINE void
function atomic_add_u (line 601) | JEMALLOC_INLINE unsigned
function atomic_sub_u (line 612) | JEMALLOC_INLINE unsigned
function JEMALLOC_INLINE (line 625) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 636) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/bitmap.h
type bitmap_level_t (line 8) | typedef struct bitmap_level_s bitmap_level_t;
type bitmap_info_t (line 9) | typedef struct bitmap_info_s bitmap_info_t;
type bitmap_t (line 10) | typedef unsigned long bitmap_t;
type bitmap_level_s (line 72) | struct bitmap_level_s {
type bitmap_info_s (line 77) | struct bitmap_info_s {
function JEMALLOC_INLINE (line 113) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 122) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 134) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 168) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 190) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/chunk.h
function JEMALLOC_INLINE (line 87) | JEMALLOC_INLINE extent_node_t *
FILE: deps/jemalloc/include/jemalloc/internal/chunk_dss.h
type dss_prec_t (line 4) | typedef enum {
FILE: deps/jemalloc/include/jemalloc/internal/ckh.h
type ckh_t (line 4) | typedef struct ckh_s ckh_t;
type ckhc_t (line 5) | typedef struct ckhc_s ckhc_t;
type ckhc_s (line 27) | struct ckhc_s {
type ckh_s (line 32) | struct ckh_s {
FILE: deps/jemalloc/include/jemalloc/internal/ctl.h
type ctl_node_t (line 4) | typedef struct ctl_node_s ctl_node_t;
type ctl_named_node_t (line 5) | typedef struct ctl_named_node_s ctl_named_node_t;
type ctl_indexed_node_t (line 6) | typedef struct ctl_indexed_node_s ctl_indexed_node_t;
type ctl_arena_stats_t (line 7) | typedef struct ctl_arena_stats_s ctl_arena_stats_t;
type ctl_stats_t (line 8) | typedef struct ctl_stats_s ctl_stats_t;
type ctl_node_s (line 14) | struct ctl_node_s {
type ctl_named_node_s (line 18) | struct ctl_named_node_s {
type ctl_indexed_node_s (line 28) | struct ctl_indexed_node_s {
type ctl_arena_stats_s (line 33) | struct ctl_arena_stats_s {
type ctl_stats_s (line 53) | struct ctl_stats_s {
FILE: deps/jemalloc/include/jemalloc/internal/extent.h
type extent_node_t (line 4) | typedef struct extent_node_s extent_node_t;
type extent_node_s (line 11) | struct extent_node_s {
type extent_tree_t (line 58) | typedef rb_tree(extent_node_t) extent_tree_t;
function JEMALLOC_INLINE (line 96) | JEMALLOC_INLINE arena_t *
function JEMALLOC_INLINE (line 103) | JEMALLOC_INLINE void *
function JEMALLOC_INLINE (line 110) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 117) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 124) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 132) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 139) | JEMALLOC_INLINE prof_tctx_t *
function JEMALLOC_INLINE (line 146) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 153) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 160) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 167) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 174) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 181) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 188) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 195) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 210) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 218) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 227) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/hash.h
function JEMALLOC_INLINE (line 34) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 41) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 48) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 55) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 62) | JEMALLOC_INLINE uint32_t
function JEMALLOC_INLINE (line 75) | JEMALLOC_INLINE uint64_t
function JEMALLOC_INLINE (line 88) | JEMALLOC_INLINE uint32_t
function hash_x86_128 (line 139) | void
function hash_x64_128 (line 241) | void
function JEMALLOC_INLINE (line 321) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h
function isblank (line 52) | static int
FILE: deps/jemalloc/include/jemalloc/internal/mb.h
function JEMALLOC_INLINE (line 31) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 58) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 69) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 80) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 91) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 102) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/mutex.h
type malloc_mutex_t (line 4) | typedef struct malloc_mutex_s malloc_mutex_t;
type malloc_mutex_s (line 27) | struct malloc_mutex_s {
function JEMALLOC_INLINE (line 71) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 90) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/prof.h
type prof_bt_t (line 4) | typedef struct prof_bt_s prof_bt_t;
type prof_cnt_t (line 5) | typedef struct prof_cnt_s prof_cnt_t;
type prof_tctx_t (line 6) | typedef struct prof_tctx_s prof_tctx_t;
type prof_gctx_t (line 7) | typedef struct prof_gctx_s prof_gctx_t;
type prof_tdata_t (line 8) | typedef struct prof_tdata_s prof_tdata_t;
type prof_bt_s (line 59) | struct prof_bt_s {
type prof_unwind_data_t (line 67) | typedef struct {
type prof_cnt_s (line 73) | struct prof_cnt_s {
type prof_tctx_state_t (line 81) | typedef enum {
type prof_tctx_s (line 88) | struct prof_tctx_s {
type prof_tctx_tree_t (line 138) | typedef rb_tree(prof_tctx_t) prof_tctx_tree_t;
type prof_gctx_s (line 140) | struct prof_gctx_s {
type prof_gctx_tree_t (line 174) | typedef rb_tree(prof_gctx_t) prof_gctx_tree_t;
type prof_tdata_s (line 176) | struct prof_tdata_s {
type prof_tdata_tree_t (line 240) | typedef rb_tree(prof_tdata_t) prof_tdata_tree_t;
function JEMALLOC_ALWAYS_INLINE (line 350) | JEMALLOC_ALWAYS_INLINE bool
function JEMALLOC_ALWAYS_INLINE (line 363) | JEMALLOC_ALWAYS_INLINE bool
function JEMALLOC_ALWAYS_INLINE (line 375) | JEMALLOC_ALWAYS_INLINE prof_tdata_t *
function JEMALLOC_ALWAYS_INLINE (line 399) | JEMALLOC_ALWAYS_INLINE prof_tctx_t *
function JEMALLOC_ALWAYS_INLINE (line 409) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 419) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 430) | JEMALLOC_ALWAYS_INLINE bool
function JEMALLOC_ALWAYS_INLINE (line 460) | JEMALLOC_ALWAYS_INLINE prof_tctx_t *
function JEMALLOC_ALWAYS_INLINE (line 481) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 495) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 531) | JEMALLOC_ALWAYS_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/quarantine.h
type quarantine_obj_t (line 4) | typedef struct quarantine_obj_s quarantine_obj_t;
type quarantine_t (line 5) | typedef struct quarantine_s quarantine_t;
type quarantine_obj_s (line 14) | struct quarantine_obj_s {
type quarantine_s (line 19) | struct quarantine_s {
function JEMALLOC_ALWAYS_INLINE (line 45) | JEMALLOC_ALWAYS_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/rtree.h
type rtree_node_elm_t (line 9) | typedef struct rtree_node_elm_s rtree_node_elm_t;
type rtree_level_t (line 10) | typedef struct rtree_level_s rtree_level_t;
type rtree_t (line 11) | typedef struct rtree_s rtree_t;
type rtree_node_elm_t (line 30) | typedef rtree_node_elm_t *(rtree_node_alloc_t)(size_t);
type rtree_node_elm_s (line 37) | struct rtree_node_elm_s {
type rtree_level_s (line 45) | struct rtree_level_s {
type rtree_s (line 81) | struct rtree_s {
function rtree_start_level (line 129) | JEMALLOC_INLINE unsigned
function JEMALLOC_INLINE (line 143) | JEMALLOC_INLINE uintptr_t
function JEMALLOC_INLINE (line 152) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 159) | JEMALLOC_INLINE rtree_node_elm_t *
function JEMALLOC_INLINE (line 171) | JEMALLOC_INLINE rtree_node_elm_t *
function JEMALLOC_INLINE (line 182) | JEMALLOC_INLINE extent_node_t *
function JEMALLOC_INLINE (line 204) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 211) | JEMALLOC_INLINE rtree_node_elm_t *
function JEMALLOC_INLINE (line 223) | JEMALLOC_INLINE rtree_node_elm_t *
function JEMALLOC_INLINE (line 234) | JEMALLOC_INLINE extent_node_t *
function JEMALLOC_INLINE (line 262) | JEMALLOC_INLINE bool
FILE: deps/jemalloc/include/jemalloc/internal/stats.h
type tcache_bin_stats_t (line 4) | typedef struct tcache_bin_stats_s tcache_bin_stats_t;
type malloc_bin_stats_t (line 5) | typedef struct malloc_bin_stats_s malloc_bin_stats_t;
type malloc_large_stats_t (line 6) | typedef struct malloc_large_stats_s malloc_large_stats_t;
type malloc_huge_stats_t (line 7) | typedef struct malloc_huge_stats_s malloc_huge_stats_t;
type arena_stats_t (line 8) | typedef struct arena_stats_s arena_stats_t;
type chunk_stats_t (line 9) | typedef struct chunk_stats_s chunk_stats_t;
type tcache_bin_stats_s (line 15) | struct tcache_bin_stats_s {
type malloc_bin_stats_s (line 23) | struct malloc_bin_stats_s {
type malloc_large_stats_s (line 65) | struct malloc_large_stats_s {
type malloc_huge_stats_s (line 89) | struct malloc_huge_stats_s {
type arena_stats_s (line 101) | struct arena_stats_s {
function JEMALLOC_INLINE (line 160) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 167) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 174) | JEMALLOC_INLINE void
FILE: deps/jemalloc/include/jemalloc/internal/tcache.h
type tcache_bin_info_t (line 4) | typedef struct tcache_bin_info_s tcache_bin_info_t;
type tcache_bin_t (line 5) | typedef struct tcache_bin_s tcache_bin_t;
type tcache_t (line 6) | typedef struct tcache_s tcache_t;
type tcaches_t (line 7) | typedef struct tcaches_s tcaches_t;
type tcache_enabled_t (line 54) | typedef enum {
type tcache_bin_info_s (line 64) | struct tcache_bin_info_s {
type tcache_bin_s (line 68) | struct tcache_bin_s {
type tcache_s (line 76) | struct tcache_s {
type tcaches_s (line 91) | struct tcaches_s {
function JEMALLOC_INLINE (line 171) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 182) | JEMALLOC_INLINE bool
function JEMALLOC_INLINE (line 200) | JEMALLOC_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 217) | JEMALLOC_ALWAYS_INLINE tcache_t *
function JEMALLOC_ALWAYS_INLINE (line 236) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 249) | JEMALLOC_ALWAYS_INLINE void *
function JEMALLOC_ALWAYS_INLINE (line 265) | JEMALLOC_ALWAYS_INLINE void *
function JEMALLOC_ALWAYS_INLINE (line 310) | JEMALLOC_ALWAYS_INLINE void *
function JEMALLOC_ALWAYS_INLINE (line 362) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 386) | JEMALLOC_ALWAYS_INLINE void
function JEMALLOC_ALWAYS_INLINE (line 415) | JEMALLOC_ALWAYS_INLINE tcache_t *
FILE: deps/jemalloc/include/jemalloc/internal/tsd.h
type tsd_init_block_t (line 11) | typedef struct tsd_init_block_s tsd_init_block_t;
type tsd_init_head_t (line 12) | typedef struct tsd_init_head_s tsd_init_head_t;
type tsd_t (line 15) | typedef struct tsd_s tsd_t;
type tsd_state_t (line 17) | typedef enum {
type tsd_init_block_s (line 522) | struct tsd_init_block_s {
type tsd_init_head_s (line 527) | struct tsd_init_head_s {
type tsd_s (line 560) | struct tsd_s {
function malloc_tsd_funcs (line 608) | malloc_tsd_externs(, tsd_t)
function JEMALLOC_INLINE (line 631) | JEMALLOC_INLINE bool
FILE: deps/jemalloc/include/jemalloc/internal/util.h
function JEMALLOC_ALWAYS_INLINE (line 181) | JEMALLOC_ALWAYS_INLINE int
function JEMALLOC_ALWAYS_INLINE (line 188) | JEMALLOC_ALWAYS_INLINE int
function JEMALLOC_INLINE (line 196) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 214) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 228) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 245) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 260) | JEMALLOC_INLINE size_t
function JEMALLOC_INLINE (line 289) | JEMALLOC_INLINE void
function JEMALLOC_INLINE (line 301) | JEMALLOC_INLINE int
FILE: deps/jemalloc/include/msvc_compat/C99/stdbool.h
type BOOL (line 11) | typedef BOOL _Bool;
FILE: deps/jemalloc/include/msvc_compat/C99/stdint.h
type int_least8_t (line 94) | typedef int8_t int_least8_t;
type int_least16_t (line 95) | typedef int16_t int_least16_t;
type int_least32_t (line 96) | typedef int32_t int_least32_t;
type int_least64_t (line 97) | typedef int64_t int_least64_t;
type uint_least8_t (line 98) | typedef uint8_t uint_least8_t;
type uint_least16_t (line 99) | typedef uint16_t uint_least16_t;
type uint_least32_t (line 100) | typedef uint32_t uint_least32_t;
type uint_least64_t (line 101) | typedef uint64_t uint_least64_t;
type int_fast8_t (line 104) | typedef int8_t int_fast8_t;
type int_fast16_t (line 105) | typedef int16_t int_fast16_t;
type int_fast32_t (line 106) | typedef int32_t int_fast32_t;
type int_fast64_t (line 107) | typedef int64_t int_fast64_t;
type uint_fast8_t (line 108) | typedef uint8_t uint_fast8_t;
type uint_fast16_t (line 109) | typedef uint16_t uint_fast16_t;
type uint_fast32_t (line 110) | typedef uint32_t uint_fast32_t;
type uint_fast64_t (line 111) | typedef uint64_t uint_fast64_t;
type intmax_t (line 123) | typedef int64_t intmax_t;
type uintmax_t (line 124) | typedef uint64_t uintmax_t;
FILE: deps/jemalloc/include/msvc_compat/strings.h
function ffsl (line 9) | static __forceinline int ffsl(long x)
function ffs (line 18) | static __forceinline int ffs(int x)
FILE: deps/jemalloc/src/arena.c
function JEMALLOC_INLINE_C (line 38) | JEMALLOC_INLINE_C arena_chunk_map_misc_t *
function JEMALLOC_INLINE_C (line 46) | JEMALLOC_INLINE_C bool
function JEMALLOC_INLINE_C (line 55) | JEMALLOC_INLINE_C size_t
function JEMALLOC_INLINE_C (line 64) | JEMALLOC_INLINE_C size_t
function JEMALLOC_INLINE_C (line 78) | JEMALLOC_INLINE_C int
function run_quantize_next (line 118) | static size_t
function run_quantize_first (line 152) | static size_t
function JEMALLOC_INLINE_C (line 171) | JEMALLOC_INLINE_C int
function arena_avail_remove (line 216) | static void
function arena_run_dirty_insert (line 227) | static void
function arena_run_dirty_remove (line 244) | static void
function arena_chunk_dirty_npages (line 261) | static size_t
function arena_chunk_cache_maybe_insert (line 268) | void
function arena_chunk_cache_maybe_remove (line 280) | void
function JEMALLOC_INLINE_C (line 291) | JEMALLOC_INLINE_C void *
function JEMALLOC_INLINE_C (line 311) | JEMALLOC_INLINE_C void
function JEMALLOC_INLINE_C (line 337) | JEMALLOC_INLINE_C void
function JEMALLOC_INLINE_C (line 347) | JEMALLOC_INLINE_C void
function JEMALLOC_INLINE_C (line 355) | JEMALLOC_INLINE_C void
function arena_cactive_update (line 366) | static void
function arena_run_split_remove (line 379) | static void
function arena_run_split_large_helper (line 422) | static bool
function arena_run_split_large (line 495) | static bool
function arena_run_init_large (line 502) | static bool
function arena_run_split_small (line 509) | static bool
function arena_chunk_t (line 547) | static arena_chunk_t *
function arena_chunk_register (line 569) | static bool
function arena_chunk_t (line 584) | static arena_chunk_t *
function arena_chunk_t (line 618) | static arena_chunk_t *
function arena_chunk_t (line 647) | static arena_chunk_t *
function arena_chunk_t (line 701) | static arena_chunk_t *
function arena_chunk_dalloc (line 720) | static void
function arena_huge_malloc_stats_update (line 780) | static void
function arena_huge_malloc_stats_update_undo (line 793) | static void
function arena_huge_dalloc_stats_update (line 806) | static void
function arena_huge_dalloc_stats_update_undo (line 819) | static void
function arena_huge_ralloc_stats_update (line 832) | static void
function arena_huge_ralloc_stats_update_undo (line 840) | static void
function extent_node_t (line 849) | extent_node_t *
function arena_node_dalloc (line 865) | void
function arena_chunk_dalloc_huge (line 928) | void
function arena_chunk_ralloc_huge_similar (line 947) | void
function arena_chunk_ralloc_huge_shrink (line 972) | void
function arena_chunk_ralloc_huge_expand_hard (line 999) | static bool
function arena_chunk_ralloc_huge_expand (line 1028) | bool
function arena_run_t (line 1071) | static arena_run_t *
function arena_run_t (line 1083) | static arena_run_t *
function arena_run_t (line 1094) | static arena_run_t *
function arena_run_t (line 1127) | static arena_run_t *
function arena_run_t (line 1138) | static arena_run_t *
function arena_lg_dirty_mult_valid (line 1172) | static bool
function arena_lg_dirty_mult_get (line 1180) | ssize_t
function arena_lg_dirty_mult_set (line 1192) | bool
function arena_maybe_purge (line 1207) | void
function arena_dirty_count (line 1235) | static size_t
function arena_compute_npurge (line 1269) | static size_t
function arena_stash_dirty (line 1289) | static size_t
function arena_purge_stashed (line 1369) | static size_t
function arena_unstash_purged (line 1462) | static void
function arena_purge (line 1502) | static void
function arena_purge_all (line 1541) | void
function arena_run_coalesce (line 1550) | static void
function arena_run_size_get (line 1642) | static size_t
function arena_run_decommit (line 1663) | static bool
function arena_run_dalloc (line 1675) | static void
function arena_run_dalloc_decommit (line 1752) | static void
function arena_run_trim_head (line 1761) | static void
function arena_run_trim_tail (line 1801) | static void
function arena_run_t (line 1846) | static arena_run_t *
function arena_bin_runs_insert (line 1856) | static void
function arena_bin_runs_remove (line 1866) | static void
function arena_run_t (line 1876) | static arena_run_t *
function arena_run_t (line 1888) | static arena_run_t *
function arena_tcache_fill_small (line 1988) | void
function arena_alloc_junk_small (line 2040) | void
function arena_redzone_corruption (line 2060) | static void
function arena_redzones_validate (line 2076) | static void
function arena_dalloc_junk_small (line 2116) | void
function arena_quarantine_junk_small (line 2132) | void
function arena_prof_promoted (line 2384) | void
function arena_dissociate_bin_run (line 2408) | static void
function arena_dalloc_bin_run (line 2432) | static void
function arena_bin_lower_run (line 2452) | static void
function arena_dalloc_bin_locked_impl (line 2473) | static void
function arena_dalloc_bin_junked_locked (line 2506) | void
function arena_dalloc_bin (line 2514) | void
function arena_dalloc_small (line 2530) | void
function arena_dalloc_junk_large (line 2549) | void
function arena_dalloc_large_locked_impl (line 2563) | static void
function arena_dalloc_large_junked_locked (line 2590) | void
function arena_dalloc_large (line 2598) | void
function arena_ralloc_large_shrink (line 2607) | static void
function arena_ralloc_large_grow (line 2643) | static bool
function arena_ralloc_junk_large (line 2741) | static void
function arena_ralloc_large (line 2761) | static bool
function arena_ralloc_no_move (line 2798) | bool
function dss_prec_t (line 2891) | dss_prec_t
function arena_dss_prec_set (line 2902) | bool
function arena_lg_dirty_mult_default_get (line 2914) | ssize_t
function arena_lg_dirty_mult_default_set (line 2921) | bool
function arena_stats_merge (line 2931) | void
function arena_t (line 2992) | arena_t *
function bin_info_run_size_calc (line 3099) | static void
function bin_info_init (line 3186) | static void
function small_run_size_init (line 3205) | static bool
function arena_boot (line 3231) | bool
function arena_prefork (line 3281) | void
function arena_postfork_parent (line 3294) | void
function arena_postfork_child (line 3307) | void
FILE: deps/jemalloc/src/base.c
function extent_node_t (line 17) | static extent_node_t *
function base_node_dalloc (line 31) | static void
function extent_node_t (line 41) | static extent_node_t *
function base_stats_get (line 130) | void
function base_boot (line 143) | bool
function base_prefork (line 155) | void
function base_postfork_parent (line 162) | void
function base_postfork_child (line 169) | void
FILE: deps/jemalloc/src/bitmap.c
function bitmap_info_init (line 6) | void
function bitmap_info_ngroups (line 35) | size_t
function bitmap_size (line 42) | size_t
function bitmap_init (line 51) | void
FILE: deps/jemalloc/src/chunk.c
function chunk_hooks_t (line 58) | static chunk_hooks_t
function chunk_hooks_t (line 65) | chunk_hooks_t
function chunk_hooks_t (line 77) | chunk_hooks_t
function chunk_hooks_assure_initialized_impl (line 112) | static void
function chunk_hooks_assure_initialized_locked (line 126) | static void
function chunk_hooks_assure_initialized (line 134) | static void
function chunk_register (line 141) | bool
function chunk_deregister (line 168) | void
function extent_node_t (line 187) | static extent_node_t *
function arena_t (line 416) | static arena_t *
function chunk_record (line 466) | static void
function chunk_dalloc_cache (line 558) | void
function chunk_dalloc_arena (line 573) | void
function chunk_dalloc_default (line 598) | static bool
function chunk_dalloc_wrapper (line 608) | void
function chunk_commit_default (line 619) | static bool
function chunk_decommit_default (line 628) | static bool
function chunk_purge_arena (line 637) | bool
function chunk_purge_default (line 651) | static bool
function chunk_purge_wrapper (line 660) | bool
function chunk_split_default (line 669) | static bool
function chunk_merge_default (line 679) | static bool
function rtree_node_elm_t (line 692) | static rtree_node_elm_t *
function chunk_boot (line 700) | bool
function chunk_prefork (line 742) | void
function chunk_postfork_parent (line 749) | void
function chunk_postfork_child (line 756) | void
FILE: deps/jemalloc/src/chunk_dss.c
function dss_prec_t (line 43) | dss_prec_t
function chunk_dss_prec_set (line 56) | bool
function chunk_in_dss (line 157) | bool
function chunk_dss_boot (line 175) | bool
function chunk_dss_prefork (line 190) | void
function chunk_dss_postfork_parent (line 198) | void
function chunk_dss_postfork_child (line 206) | void
FILE: deps/jemalloc/src/chunk_mmap.c
function chunk_dalloc_mmap (line 72) | bool
FILE: deps/jemalloc/src/ckh.c
function JEMALLOC_INLINE_C (line 52) | JEMALLOC_INLINE_C size_t
function JEMALLOC_INLINE_C (line 70) | JEMALLOC_INLINE_C size_t
function JEMALLOC_INLINE_C (line 91) | JEMALLOC_INLINE_C bool
function JEMALLOC_INLINE_C (line 123) | JEMALLOC_INLINE_C bool
function JEMALLOC_INLINE_C (line 193) | JEMALLOC_INLINE_C bool
function JEMALLOC_INLINE_C (line 222) | JEMALLOC_INLINE_C bool
function ckh_grow (line 245) | static bool
function ckh_shrink (line 301) | static void
function ckh_new (line 349) | bool
function ckh_delete (line 406) | void
function ckh_count (line 429) | size_t
function ckh_iter (line 438) | bool
function ckh_insert (line 458) | bool
function ckh_remove (line 482) | bool
function ckh_search (line 514) | bool
function ckh_string_hash (line 533) | void
function ckh_string_keycomp (line 540) | bool
function ckh_pointer_hash (line 550) | void
function ckh_pointer_keycomp (line 563) | bool
FILE: deps/jemalloc/src/ctl.c
function JEMALLOC_INLINE_C (line 19) | JEMALLOC_INLINE_C const ctl_named_node_t *
function JEMALLOC_INLINE_C (line 26) | JEMALLOC_INLINE_C const ctl_named_node_t *
function JEMALLOC_INLINE_C (line 34) | JEMALLOC_INLINE_C const ctl_indexed_node_t *
function CTL_PROTO (line 65) | CTL_PROTO(version)
function thread_prof_name_ctl (line 1392) | static int
function thread_prof_active_ctl (line 1426) | static int
function tcache_create_ctl (line 1456) | static int
function tcache_flush_ctl (line 1483) | static int
function tcache_destroy_ctl (line 1510) | static int
function arena_purge (line 1540) | static void
function arena_i_purge_ctl (line 1570) | static int
function arena_i_dss_ctl (line 1587) | static int
function arena_i_lg_dirty_mult_ctl (line 1643) | static int
function arena_i_chunk_hooks_ctl (line 1677) | static int
function ctl_named_node_t (line 1708) | static const ctl_named_node_t *
function arenas_narenas_ctl (line 1727) | static int
function arenas_initialized_ctl (line 1749) | static int
function arenas_lg_dirty_mult_ctl (line 1775) | static int
function ctl_named_node_t (line 1809) | static const ctl_named_node_t *
function ctl_named_node_t (line 1820) | static const ctl_named_node_t *
function ctl_named_node_t (line 1831) | static const ctl_named_node_t *
function arenas_extend_ctl (line 1840) | static int
function prof_thread_active_init_ctl (line 1864) | static int
function prof_active_ctl (line 1889) | static int
function prof_dump_ctl (line 1914) | static int
function prof_gdump_ctl (line 1937) | static int
function prof_reset_ctl (line 1962) | static int
function ctl_named_node_t (line 2080) | static const ctl_named_node_t *
function ctl_named_node_t (line 2099) | static const ctl_named_node_t *
function ctl_named_node_t (line 2108) | static const ctl_named_node_t *
FILE: deps/jemalloc/src/extent.c
function JEMALLOC_INLINE_C (line 6) | JEMALLOC_INLINE_C size_t
function JEMALLOC_INLINE_C (line 17) | JEMALLOC_INLINE_C int
function extent_ad_comp (line 43) | int
FILE: deps/jemalloc/src/huge.c
function extent_node_t (line 6) | static extent_node_t *
function huge_node_set (line 17) | static bool
function huge_node_unset (line 26) | static void
function huge_dalloc_junk (line 109) | static void
function huge_ralloc_no_move_similar (line 128) | static void
function huge_ralloc_no_move_shrink (line 187) | static bool
function huge_ralloc_no_move_expand (line 237) | static bool
function huge_ralloc_no_move (line 282) | bool
function huge_dalloc (line 358) | void
function arena_t (line 378) | arena_t *
function huge_salloc (line 385) | size_t
function prof_tctx_t (line 401) | prof_tctx_t *
function huge_prof_tctx_set (line 417) | void
function huge_prof_tctx_reset (line 430) | void
FILE: deps/jemalloc/src/jemalloc.c
type malloc_init_t (line 65) | typedef enum {
function WINAPI (line 185) | WINAPI
type malloc_utrace_t (line 212) | typedef struct {
function JEMALLOC_ALWAYS_INLINE_C (line 248) | JEMALLOC_ALWAYS_INLINE_C bool
function JEMALLOC_ALWAYS_INLINE_C (line 255) | JEMALLOC_ALWAYS_INLINE_C void
function JEMALLOC_ALWAYS_INLINE_C (line 272) | JEMALLOC_ALWAYS_INLINE_C bool
function JEMALLOC_ALWAYS_INLINE_C (line 281) | JEMALLOC_ALWAYS_INLINE_C bool
function arena_t (line 297) | arena_t *
function a0idalloc (line 315) | static void
function a0dalloc (line 329) | void
function bootstrap_free (line 366) | void
function arena_t (line 377) | static arena_t *
function arena_t (line 420) | arena_t *
function narenas_total_get (line 431) | unsigned
function arena_bind_locked (line 443) | static void
function arena_bind (line 455) | static void
function arena_migrate (line 464) | void
function arena_nbound (line 478) | unsigned
function arena_unbind (line 489) | static void
function arena_t (line 501) | arena_t *
function arena_t (line 573) | arena_t *
function thread_allocated_cleanup (line 634) | void
function thread_deallocated_cleanup (line 641) | void
function arena_cleanup (line 648) | void
function arenas_cache_cleanup (line 658) | void
function narenas_cache_cleanup (line 670) | void
function arenas_cache_bypass_cleanup (line 677) | void
function stats_print_atexit (line 684) | static void
function malloc_ncpus (line 741) | static unsigned
function malloc_conf_next (line 756) | static bool
function malloc_conf_error (line 832) | static void
function malloc_conf_init (line 841) | static void
function malloc_init_hard_needed (line 1149) | static bool
function malloc_init_hard_a0_locked (line 1177) | static bool
function malloc_init_hard_a0 (line 1225) | static bool
function malloc_init_hard_recursible (line 1241) | static void
function malloc_init_hard_finish (line 1264) | static bool
function malloc_init_hard (line 1310) | static bool
function JEMALLOC_ALWAYS_INLINE_C (line 1375) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 1395) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 1465) | JEMALLOC_ALWAYS_INLINE_C void *
function imemalign (line 1486) | static int
function JEMALLOC_NOTHROW (line 1551) | JEMALLOC_NOTHROW
function JEMALLOC_ALWAYS_INLINE_C (line 1596) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 1703) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_INLINE_C (line 1727) | JEMALLOC_INLINE_C void
function JEMALLOC_INLINE_C (line 1749) | JEMALLOC_INLINE_C void
function JEMALLOC_NOTHROW (line 1832) | JEMALLOC_NOTHROW
function JEMALLOC_ALWAYS_INLINE_C (line 1914) | JEMALLOC_ALWAYS_INLINE_C bool
function JEMALLOC_ALWAYS_INLINE_C (line 1945) | JEMALLOC_ALWAYS_INLINE_C bool
function JEMALLOC_ALWAYS_INLINE_C (line 1964) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 1996) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 2027) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 2111) | JEMALLOC_ALWAYS_INLINE_C void *
function JEMALLOC_ALWAYS_INLINE_C (line 2227) | JEMALLOC_ALWAYS_INLINE_C size_t
function ixallocx_prof_sample (line 2240) | static size_t
function JEMALLOC_ALWAYS_INLINE_C (line 2253) | JEMALLOC_ALWAYS_INLINE_C size_t
function JEMALLOC_NOTHROW (line 2290) | JEMALLOC_NOTHROW
function JEMALLOC_NOTHROW (line 2342) | JEMALLOC_NOTHROW
function JEMALLOC_ALWAYS_INLINE_C (line 2381) | JEMALLOC_ALWAYS_INLINE_C size_t
function JEMALLOC_NOTHROW (line 2394) | JEMALLOC_NOTHROW
function JEMALLOC_NOTHROW (line 2419) | JEMALLOC_NOTHROW
function JEMALLOC_NOTHROW (line 2453) | JEMALLOC_NOTHROW
function JEMALLOC_NOTHROW (line 2464) | JEMALLOC_NOTHROW
function JEMALLOC_NOTHROW (line 2472) | JEMALLOC_NOTHROW
function jemalloc_constructor (line 2510) | JEMALLOC_ATTR(constructor)
function jemalloc_prefork (line 2519) | void
function jemalloc_postfork_parent (line 2547) | void
function jemalloc_postfork_child (line 2574) | void
FILE: deps/jemalloc/src/mutex.c
function pthread_create_once (line 37) | static void
function JEMALLOC_EXPORT (line 51) | JEMALLOC_EXPORT int
function malloc_mutex_init (line 71) | bool
function malloc_mutex_prefork (line 109) | void
function malloc_mutex_postfork_parent (line 116) | void
function malloc_mutex_postfork_child (line 123) | void
function mutex_boot (line 139) | bool
FILE: deps/jemalloc/src/pages.c
function pages_commit_impl (line 100) | static bool
function pages_commit (line 131) | bool
function pages_decommit (line 138) | bool
function pages_purge (line 145) | bool
FILE: deps/jemalloc/src/prof.c
function JEMALLOC_INLINE_C (line 135) | JEMALLOC_INLINE_C int
function prof_malloc_sample_object (line 225) | void
function prof_free_sampled_object (line 242) | void
function bt_init (line 258) | void
function JEMALLOC_INLINE_C (line 268) | JEMALLOC_INLINE_C void
function JEMALLOC_INLINE_C (line 283) | JEMALLOC_INLINE_C void
function prof_backtrace (line 310) | void
function _Unwind_Reason_Code (line 325) | static _Unwind_Reason_Code
function _Unwind_Reason_Code (line 334) | static _Unwind_Reason_Code
function prof_backtrace (line 353) | void
function prof_backtrace (line 363) | void
function prof_backtrace (line 524) | void
function malloc_mutex_t (line 533) | static malloc_mutex_t *
function malloc_mutex_t (line 541) | static malloc_mutex_t *
function prof_gctx_t (line 548) | static prof_gctx_t *
function prof_gctx_try_destroy (line 573) | static void
function prof_tctx_should_destroy (line 610) | static bool
function prof_gctx_should_destroy (line 623) | static bool
function prof_tctx_destroy (line 637) | static void
function prof_lookup_global (line 707) | static bool
function prof_tctx_t (line 755) | prof_tctx_t *
function prof_sample_threshold_update (line 826) | void
function prof_tdata_t (line 882) | static prof_tdata_t *
function prof_tdata_count (line 892) | size_t
function prof_bt_count (line 907) | size_t
function prof_dump_open (line 931) | static int
function prof_dump_flush (line 952) | static bool
function prof_dump_close (line 975) | static bool
function prof_dump_write (line 988) | static bool
function prof_dump_printf (line 1019) | static bool
function prof_tctx_merge_tdata (line 1035) | static void
function prof_tctx_merge_gctx (line 1067) | static void
function prof_tctx_t (line 1080) | static prof_tctx_t *
function prof_tctx_t (line 1100) | static prof_tctx_t *
function prof_tctx_t (line 1126) | static prof_tctx_t *
function prof_dump_gctx_prep (line 1150) | static void
function prof_gctx_t (line 1171) | static prof_gctx_t *
function prof_gctx_finish (line 1185) | static void
function prof_tdata_t (line 1229) | static prof_tdata_t *
function prof_tdata_t (line 1261) | static prof_tdata_t *
function prof_dump_header (line 1284) | static bool
function prof_dump_gctx (line 1309) | static bool
function prof_open_maps (line 1362) | static int
function prof_dump_maps (line 1377) | static bool
function prof_leakcheck (line 1429) | static void
function prof_gctx_t (line 1446) | static prof_gctx_t *
function prof_dump (line 1465) | static bool
function prof_dump_filename (line 1547) | static void
function prof_fdump (line 1567) | static void
function prof_idump (line 1587) | void
function prof_mdump (line 1616) | bool
function prof_gdump (line 1641) | void
function prof_bt_hash (line 1670) | static void
function prof_bt_keycomp (line 1680) | static bool
function JEMALLOC_INLINE_C (line 1693) | JEMALLOC_INLINE_C uint64_t
function prof_tdata_t (line 1706) | static prof_tdata_t *
function prof_tdata_t (line 1753) | prof_tdata_t *
function prof_tdata_should_destroy (line 1762) | static bool
function prof_tdata_destroy_locked (line 1774) | static void
function prof_tdata_destroy (line 1792) | static void
function prof_tdata_detach (line 1801) | static void
function prof_tdata_t (line 1823) | prof_tdata_t *
function prof_tdata_expire (line 1837) | static bool
function prof_tdata_t (line 1854) | static prof_tdata_t *
function prof_reset (line 1861) | void
function prof_tdata_cleanup (line 1888) | void
function prof_active_get (line 1901) | bool
function prof_active_set (line 1912) | bool
function prof_thread_name_set (line 1957) | int
function prof_thread_active_get (line 1991) | bool
function prof_thread_active_set (line 2004) | bool
function prof_thread_active_init_get (line 2018) | bool
function prof_thread_active_init_set (line 2029) | bool
function prof_gdump_get (line 2041) | bool
function prof_gdump_set (line 2052) | bool
function prof_boot0 (line 2064) | void
function prof_boot1 (line 2074) | void
function prof_boot2 (line 2100) | bool
function prof_prefork (line 2183) | void
function prof_postfork_parent (line 2201) | void
function prof_postfork_child (line 2219) | void
FILE: deps/jemalloc/src/quarantine.c
function quarantine_t (line 22) | static quarantine_t *
function quarantine_alloc_hook_work (line 42) | void
function quarantine_t (line 61) | static quarantine_t *
function quarantine_drain_one (line 96) | static void
function quarantine_drain (line 108) | static void
function quarantine (line 116) | void
function quarantine_cleanup (line 169) | void
FILE: deps/jemalloc/src/rtree.c
function hmin (line 4) | static unsigned
function rtree_new (line 12) | bool
function rtree_delete_subtree (line 62) | static void
function rtree_delete (line 79) | void
function rtree_node_elm_t (line 91) | static rtree_node_elm_t *
function rtree_node_elm_t (line 115) | rtree_node_elm_t *
function rtree_node_elm_t (line 122) | rtree_node_elm_t *
FILE: deps/jemalloc/src/stats.c
function stats_arena_bins_print (line 49) | static void
function stats_arena_lruns_print (line 160) | static void
function stats_arena_hchunks_print (line 206) | static void
function stats_arena_print (line 255) | static void
function stats_print (line 359) | void
FILE: deps/jemalloc/src/tcache.c
function tcache_salloc (line 26) | size_t tcache_salloc(const void *ptr)
function tcache_event_hard (line 32) | void
function tcache_bin_flush_small (line 88) | void
function tcache_bin_flush_large (line 168) | void
function tcache_arena_associate (line 251) | void
function tcache_arena_reassociate (line 264) | void
function tcache_arena_dissociate (line 272) | void
function tcache_t (line 296) | tcache_t *
function tcache_t (line 312) | tcache_t *
function tcache_destroy (line 344) | static void
function tcache_cleanup (line 385) | void
function tcache_enabled_cleanup (line 399) | void
function tcache_stats_merge (line 407) | void
function tcaches_create (line 433) | bool
function tcaches_elm_flush (line 467) | static void
function tcaches_flush (line 477) | void
function tcaches_destroy (line 484) | void
function tcache_boot (line 493) | bool
FILE: deps/jemalloc/src/tsd.c
function malloc_tsd_dalloc (line 21) | void
function malloc_tsd_no_cleanup (line 28) | void
function _malloc_thread_cleanup (line 39) | void
function malloc_tsd_cleanup_register (line 61) | void
function tsd_cleanup (line 70) | void
function malloc_tsd_boot0 (line 109) | bool
function malloc_tsd_boot1 (line 120) | void
function BOOL (line 129) | static BOOL WINAPI
function tsd_init_finish (line 185) | void
FILE: deps/jemalloc/src/util.c
function wrtmessage (line 43) | static void
function malloc_write (line 65) | void
function buferror (line 79) | int
function uintmax_t (line 99) | uintmax_t
function malloc_vsnprintf (line 309) | int
function malloc_cprintf (line 629) | void
function malloc_printf (line 642) | void
FILE: deps/jemalloc/src/valgrind.c
function valgrind_make_mem_noaccess (line 8) | void
function valgrind_make_mem_undefined (line 15) | void
function valgrind_make_mem_defined (line 22) | void
function valgrind_freelike_block (line 29) | void
FILE: deps/jemalloc/src/zone.c
type malloc_introspection_t (line 17) | struct malloc_introspection_t
function zone_size (line 46) | static size_t
function zone_free (line 86) | static void
function zone_free_definite_size (line 121) | static void
function zone_good_size (line 144) | static size_t
function zone_force_lock (line 153) | static void
function zone_force_unlock (line 161) | static void
function register_zone (line 169) | JEMALLOC_ATTR(constructor)
FILE: deps/jemalloc/test/include/test/SFMT-alti.h
function vec_recursion (line 64) | unsigned int vec_recursion(vector unsigned int a,
function JEMALLOC_INLINE (line 98) | JEMALLOC_INLINE void gen_rand_all(sfmt_t *ctx) {
function JEMALLOC_INLINE (line 125) | JEMALLOC_INLINE void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) {
function JEMALLOC_INLINE (line 176) | JEMALLOC_INLINE void swap(w128_t *array, int size) {
FILE: deps/jemalloc/test/include/test/SFMT-sse2.h
function JEMALLOC_ALWAYS_INLINE (line 63) | JEMALLOC_ALWAYS_INLINE __m128i mm_recursion(__m128i *a, __m128i *b,
function JEMALLOC_INLINE (line 84) | JEMALLOC_INLINE void gen_rand_all(sfmt_t *ctx) {
function JEMALLOC_INLINE (line 114) | JEMALLOC_INLINE void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) {
FILE: deps/jemalloc/test/include/test/SFMT.h
type sfmt_t (line 69) | typedef struct sfmt_s sfmt_t;
function JEMALLOC_INLINE (line 100) | JEMALLOC_INLINE double to_real1(uint32_t v)
function JEMALLOC_INLINE (line 107) | JEMALLOC_INLINE double genrand_real1(sfmt_t *ctx)
function JEMALLOC_INLINE (line 113) | JEMALLOC_INLINE double to_real2(uint32_t v)
function JEMALLOC_INLINE (line 120) | JEMALLOC_INLINE double genrand_real2(sfmt_t *ctx)
function JEMALLOC_INLINE (line 126) | JEMALLOC_INLINE double to_real3(uint32_t v)
function JEMALLOC_INLINE (line 133) | JEMALLOC_INLINE double genrand_real3(sfmt_t *ctx)
function JEMALLOC_INLINE (line 140) | JEMALLOC_INLINE double to_res53(uint64_t v)
function JEMALLOC_INLINE (line 147) | JEMALLOC_INLINE double to_res53_mix(uint32_t x, uint32_t y)
function JEMALLOC_INLINE (line 154) | JEMALLOC_INLINE double genrand_res53(sfmt_t *ctx)
function JEMALLOC_INLINE (line 162) | JEMALLOC_INLINE double genrand_res53_mix(sfmt_t *ctx)
FILE: deps/jemalloc/test/include/test/math.h
function JEMALLOC_INLINE (line 18) | JEMALLOC_INLINE double
function JEMALLOC_INLINE (line 53) | JEMALLOC_INLINE double
function JEMALLOC_INLINE (line 134) | JEMALLOC_INLINE double
function JEMALLOC_INLINE (line 221) | JEMALLOC_INLINE double
function JEMALLOC_INLINE (line 305) | JEMALLOC_INLINE double
FILE: deps/jemalloc/test/include/test/mtx.h
type mtx_t (line 8) | typedef struct {
FILE: deps/jemalloc/test/include/test/test.h
type test_status_t (line 289) | typedef enum {
FILE: deps/jemalloc/test/include/test/thd.h
type HANDLE (line 3) | typedef HANDLE thd_t;
type pthread_t (line 5) | typedef pthread_t thd_t;
FILE: deps/jemalloc/test/include/test/timer.h
type timedelta_t (line 9) | typedef struct {
FILE: deps/jemalloc/test/integration/MALLOCX_ARENA.c
function TEST_BEGIN (line 48) | TEST_BEGIN(test_MALLOCX_ARENA)
function TEST_END (line 61) | TEST_END
FILE: deps/jemalloc/test/integration/aligned_alloc.c
function TEST_BEGIN (line 8) | TEST_BEGIN(test_alignment_errors)
function TEST_END (line 28) | TEST_END
function TEST_END (line 73) | TEST_END
function TEST_END (line 115) | TEST_END
FILE: deps/jemalloc/test/integration/allocated.c
function TEST_BEGIN (line 98) | TEST_BEGIN(test_main_thread)
function TEST_END (line 103) | TEST_END
function TEST_END (line 112) | TEST_END
FILE: deps/jemalloc/test/integration/chunk.c
function chunk_dalloc (line 40) | bool
function chunk_commit (line 52) | bool
function chunk_decommit (line 66) | bool
function chunk_purge (line 82) | bool
function chunk_split (line 94) | bool
function chunk_merge (line 107) | bool
function TEST_BEGIN (line 120) | TEST_BEGIN(test_chunk)
function TEST_END (line 269) | TEST_END
FILE: deps/jemalloc/test/integration/mallocx.c
function get_nsizes_impl (line 3) | static unsigned
function get_nhuge (line 16) | static unsigned
function get_size_impl (line 23) | static size_t
function get_huge_size (line 42) | static size_t
function TEST_BEGIN (line 49) | TEST_BEGIN(test_oom)
function TEST_END (line 81) | TEST_END
function TEST_END (line 114) | TEST_END
function TEST_END (line 172) | TEST_END
FILE: deps/jemalloc/test/integration/overflow.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_overflow)
function TEST_END (line 41) | TEST_END
FILE: deps/jemalloc/test/integration/posix_memalign.c
function TEST_BEGIN (line 8) | TEST_BEGIN(test_alignment_errors)
function TEST_END (line 26) | TEST_END
function TEST_END (line 65) | TEST_END
function TEST_END (line 109) | TEST_END
FILE: deps/jemalloc/test/integration/rallocx.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_grow_and_shrink)
function TEST_END (line 46) | TEST_END
function TEST_BEGIN (line 68) | TEST_BEGIN(test_zero)
function TEST_END (line 111) | TEST_END
function TEST_END (line 136) | TEST_END
function TEST_END (line 174) | TEST_END
FILE: deps/jemalloc/test/integration/sdallocx.c
function TEST_BEGIN (line 6) | TEST_BEGIN(test_basic)
function TEST_END (line 11) | TEST_END
function TEST_END (line 48) | TEST_END
FILE: deps/jemalloc/test/integration/thread_arena.c
function TEST_BEGIN (line 40) | TEST_BEGIN(test_thread_arena)
function TEST_END (line 71) | TEST_END
FILE: deps/jemalloc/test/integration/thread_tcache_enabled.c
function TEST_BEGIN (line 86) | TEST_BEGIN(test_main_thread)
function TEST_END (line 91) | TEST_END
function TEST_END (line 100) | TEST_END
FILE: deps/jemalloc/test/integration/xallocx.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_same_size)
function TEST_END (line 17) | TEST_END
function TEST_END (line 33) | TEST_END
function TEST_END (line 49) | TEST_END
function get_nsmall (line 64) | static unsigned
function get_nlarge (line 71) | static unsigned
function get_nhuge (line 78) | static unsigned
function get_size_impl (line 85) | static size_t
function get_small_size (line 104) | static size_t
function get_large_size (line 111) | static size_t
function get_huge_size (line 118) | static size_t
function TEST_BEGIN (line 125) | TEST_BEGIN(test_size)
function TEST_END (line 153) | TEST_END
function TEST_END (line 185) | TEST_END
function TEST_END (line 217) | TEST_END
function TEST_END (line 283) | TEST_END
function TEST_END (line 348) | TEST_END
function validate_fill (line 370) | static bool
function test_zero (line 388) | static void
function TEST_BEGIN (line 432) | TEST_BEGIN(test_zero_large)
function TEST_END (line 442) | TEST_END
function TEST_END (line 454) | TEST_END
FILE: deps/jemalloc/test/src/SFMT.c
type w128_t (line 77) | typedef union W128_T w128_t;
type w128_t (line 86) | typedef union W128_T w128_t;
type W128_T (line 91) | struct W128_T {
type w128_t (line 95) | typedef struct W128_T w128_t;
type sfmt_s (line 99) | struct sfmt_s {
function JEMALLOC_INLINE_C (line 145) | JEMALLOC_INLINE_C int idxof(int i) {
function JEMALLOC_INLINE_C (line 149) | JEMALLOC_INLINE_C int idxof(int i) {
function JEMALLOC_INLINE_C (line 163) | JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shif...
function JEMALLOC_INLINE_C (line 178) | JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shif...
function JEMALLOC_INLINE_C (line 202) | JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shif...
function JEMALLOC_INLINE_C (line 217) | JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shif...
function JEMALLOC_INLINE_C (line 244) | JEMALLOC_INLINE_C void do_recursion(w128_t *r, w128_t *a, w128_t *b, w12...
function JEMALLOC_INLINE_C (line 261) | JEMALLOC_INLINE_C void do_recursion(w128_t *r, w128_t *a, w128_t *b, w12...
function JEMALLOC_INLINE_C (line 285) | JEMALLOC_INLINE_C void gen_rand_all(sfmt_t *ctx) {
function JEMALLOC_INLINE_C (line 312) | JEMALLOC_INLINE_C void gen_rand_array(sfmt_t *ctx, w128_t *array, int si...
function JEMALLOC_INLINE_C (line 346) | JEMALLOC_INLINE_C void swap(w128_t *array, int size) {
function func1 (line 366) | static uint32_t func1(uint32_t x) {
function func2 (line 376) | static uint32_t func2(uint32_t x) {
function period_certification (line 383) | static void period_certification(sfmt_t *ctx) {
function get_min_array_size32 (line 428) | int get_min_array_size32(void) {
function get_min_array_size64 (line 437) | int get_min_array_size64(void) {
function gen_rand32 (line 447) | uint32_t gen_rand32(sfmt_t *ctx) {
function gen_rand32_range (line 461) | uint32_t gen_rand32_range(sfmt_t *ctx, uint32_t limit) {
function gen_rand64 (line 482) | uint64_t gen_rand64(sfmt_t *ctx) {
function gen_rand64_range (line 511) | uint64_t gen_rand64_range(sfmt_t *ctx, uint64_t limit) {
function fill_array32 (line 551) | void fill_array32(sfmt_t *ctx, uint32_t *array, int size) {
function fill_array64 (line 587) | void fill_array64(sfmt_t *ctx, uint64_t *array, int size) {
function sfmt_t (line 607) | sfmt_t *init_gen_rand(uint32_t seed) {
function sfmt_t (line 638) | sfmt_t *init_by_array(uint32_t *init_key, int key_length) {
function fini_gen_rand (line 714) | void fini_gen_rand(sfmt_t *ctx) {
FILE: deps/jemalloc/test/src/mq.c
function mq_nanosleep (line 7) | void
FILE: deps/jemalloc/test/src/mtx.c
function mtx_init (line 7) | bool
function mtx_fini (line 31) | void
function mtx_lock (line 42) | void
function mtx_unlock (line 55) | void
FILE: deps/jemalloc/test/src/test.c
function test_skip (line 9) | void
function test_fail (line 22) | void
function p_test_init (line 46) | void
function p_test_fini (line 55) | void
function test_status_t (line 63) | test_status_t
function p_test_fail (line 101) | void
FILE: deps/jemalloc/test/src/thd.c
function thd_create (line 4) | void
function thd_join (line 13) | void
function thd_create (line 25) | void
function thd_join (line 33) | void
FILE: deps/jemalloc/test/src/timer.c
function timer_start (line 3) | void
function timer_stop (line 20) | void
function timer_usec (line 33) | uint64_t
function timer_ratio (line 53) | void
FILE: deps/jemalloc/test/stress/microbench.c
function JEMALLOC_INLINE_C (line 3) | JEMALLOC_INLINE_C void
function compare_funcs (line 16) | void
function malloc_free (line 42) | static void
function mallocx_free (line 54) | static void
function TEST_BEGIN (line 65) | TEST_BEGIN(test_malloc_vs_mallocx)
function TEST_END (line 71) | TEST_END
function malloc_sdallocx (line 84) | static void
function TEST_BEGIN (line 95) | TEST_BEGIN(test_free_vs_dallocx)
function TEST_END (line 101) | TEST_END
function TEST_END (line 109) | TEST_END
function malloc_sallocx_free (line 125) | static void
function TEST_BEGIN (line 140) | TEST_BEGIN(test_mus_vs_sallocx)
function TEST_END (line 146) | TEST_END
function TEST_BEGIN (line 163) | TEST_BEGIN(test_sallocx_vs_nallocx)
function TEST_END (line 169) | TEST_END
FILE: deps/jemalloc/test/unit/SFMT.c
function TEST_BEGIN (line 1452) | TEST_BEGIN(test_gen_rand_32)
function TEST_END (line 1485) | TEST_END
function TEST_END (line 1521) | TEST_END
function TEST_END (line 1557) | TEST_END
function TEST_END (line 1594) | TEST_END
FILE: deps/jemalloc/test/unit/atomic.c
function TEST_BEGIN (line 69) | TEST_BEGIN(test_atomic_uint64)
function TEST_END (line 78) | TEST_END
function TEST_END (line 86) | TEST_END
function TEST_END (line 94) | TEST_END
function TEST_END (line 102) | TEST_END
function TEST_END (line 110) | TEST_END
FILE: deps/jemalloc/test/unit/bitmap.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_bitmap_size)
function TEST_END (line 15) | TEST_END
function TEST_END (line 38) | TEST_END
function TEST_END (line 61) | TEST_END
function TEST_END (line 90) | TEST_END
function TEST_END (line 147) | TEST_END
FILE: deps/jemalloc/test/unit/ckh.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_new_delete)
function TEST_END (line 18) | TEST_END
function TEST_END (line 106) | TEST_END
function TEST_END (line 204) | TEST_END
FILE: deps/jemalloc/test/unit/hash.c
type hash_variant_t (line 32) | typedef enum {
function hash_variant_bits (line 38) | static size_t
function hash_variant_verify (line 62) | static void
function TEST_BEGIN (line 142) | TEST_BEGIN(test_hash_x86_32)
function TEST_END (line 147) | TEST_END
function TEST_END (line 154) | TEST_END
function TEST_END (line 161) | TEST_END
FILE: deps/jemalloc/test/unit/junk.c
function watch_junking (line 17) | static void
function arena_dalloc_junk_small_intercept (line 25) | static void
function arena_dalloc_junk_large_intercept (line 40) | static void
function huge_dalloc_junk_intercept (line 55) | static void
function test_junk (line 69) | static void
function TEST_BEGIN (line 131) | TEST_BEGIN(test_junk_small)
function TEST_END (line 137) | TEST_END
function TEST_END (line 145) | TEST_END
function shrink_size (line 158) | static size_t
function arena_ralloc_junk_large_intercept (line 170) | static void
function TEST_BEGIN (line 180) | TEST_BEGIN(test_junk_large_ralloc_shrink)
function arena_redzone_corruption_replacement (line 202) | static void
function TEST_BEGIN (line 210) | TEST_BEGIN(test_junk_redzone)
function TEST_END (line 241) | TEST_END
FILE: deps/jemalloc/test/unit/lg_chunk.c
function TEST_BEGIN (line 10) | TEST_BEGIN(test_lg_chunk_clamp)
function TEST_END (line 18) | TEST_END
FILE: deps/jemalloc/test/unit/mallctl.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_mallctl_errors)
function TEST_END (line 27) | TEST_END
function TEST_END (line 38) | TEST_END
function TEST_END (line 73) | TEST_END
function TEST_END (line 100) | TEST_END
function TEST_END (line 115) | TEST_END
function TEST_END (line 146) | TEST_END
function TEST_END (line 188) | TEST_END
function TEST_END (line 213) | TEST_END
function TEST_END (line 239) | TEST_END
function TEST_END (line 333) | TEST_END
function TEST_END (line 350) | TEST_END
function TEST_END (line 382) | TEST_END
function TEST_END (line 402) | TEST_END
function TEST_END (line 444) | TEST_END
function TEST_END (line 461) | TEST_END
function TEST_END (line 493) | TEST_END
function TEST_END (line 514) | TEST_END
function TEST_END (line 533) | TEST_END
function TEST_END (line 550) | TEST_END
function TEST_END (line 567) | TEST_END
function TEST_END (line 585) | TEST_END
function TEST_END (line 604) | TEST_END
FILE: deps/jemalloc/test/unit/math.c
function double_eq_rel (line 12) | static bool
function factorial (line 23) | static uint64_t
function TEST_BEGIN (line 35) | TEST_BEGIN(test_ln_gamma_factorial)
function TEST_BEGIN (line 187) | TEST_BEGIN(test_ln_gamma_misc)
function TEST_BEGIN (line 238) | TEST_BEGIN(test_pt_norm)
function TEST_BEGIN (line 288) | TEST_BEGIN(test_pt_chi2)
function TEST_BEGIN (line 350) | TEST_BEGIN(test_pt_gamma_shape)
function TEST_END (line 368) | TEST_END
function TEST_END (line 381) | TEST_END
FILE: deps/jemalloc/test/unit/mq.c
type mq_msg_t (line 6) | typedef struct mq_msg_s mq_msg_t;
type mq_msg_s (line 7) | struct mq_msg_s {
function TEST_BEGIN (line 12) | TEST_BEGIN(test_mq_basic)
function TEST_END (line 31) | TEST_END
function TEST_BEGIN (line 64) | TEST_BEGIN(test_mq_threaded)
function TEST_END (line 83) | TEST_END
FILE: deps/jemalloc/test/unit/mtx.c
function TEST_BEGIN (line 6) | TEST_BEGIN(test_mtx_basic)
function TEST_END (line 15) | TEST_END
function TEST_BEGIN (line 36) | TEST_BEGIN(test_mtx_race)
function TEST_END (line 51) | TEST_END
FILE: deps/jemalloc/test/unit/prof_accum.c
function prof_dump_open_intercept (line 13) | static int
function TEST_BEGIN (line 61) | TEST_BEGIN(test_idump)
function TEST_END (line 83) | TEST_END
FILE: deps/jemalloc/test/unit/prof_active.c
function mallctl_bool_get (line 8) | static void
function mallctl_bool_set (line 21) | static void
function mallctl_prof_active_get_impl (line 36) | static void
function mallctl_prof_active_set_impl (line 46) | static void
function mallctl_thread_prof_active_get_impl (line 57) | static void
function mallctl_thread_prof_active_set_impl (line 68) | static void
function prof_sampling_probe_impl (line 79) | static void
function TEST_BEGIN (line 96) | TEST_BEGIN(test_prof_active)
function TEST_END (line 128) | TEST_END
FILE: deps/jemalloc/test/unit/prof_gdump.c
function prof_dump_open_intercept (line 9) | static int
function TEST_BEGIN (line 22) | TEST_BEGIN(test_gdump)
function TEST_END (line 73) | TEST_END
FILE: deps/jemalloc/test/unit/prof_idump.c
function prof_dump_open_intercept (line 11) | static int
function TEST_BEGIN (line 24) | TEST_BEGIN(test_idump)
function TEST_END (line 43) | TEST_END
FILE: deps/jemalloc/test/unit/prof_reset.c
function prof_dump_open_intercept (line 8) | static int
function set_prof_active (line 19) | static void
function get_lg_prof_sample (line 27) | static size_t
function do_prof_reset (line 38) | static void
function TEST_BEGIN (line 48) | TEST_BEGIN(test_prof_reset_basic)
function prof_dump_header_intercept (line 96) | static bool
function TEST_BEGIN (line 106) | TEST_BEGIN(test_prof_reset_cleanup)
function TEST_BEGIN (line 195) | TEST_BEGIN(test_prof_reset)
function TEST_BEGIN (line 240) | TEST_BEGIN(test_xallocx)
function main (line 290) | int
FILE: deps/jemalloc/test/unit/prof_thread_name.c
function mallctl_thread_name_get_impl (line 7) | static void
function mallctl_thread_name_set_impl (line 24) | static void
function TEST_BEGIN (line 38) | TEST_BEGIN(test_prof_thread_name_validation)
function TEST_BEGIN (line 103) | TEST_BEGIN(test_prof_thread_name_threaded)
function main (line 122) | int
FILE: deps/jemalloc/test/unit/ql.c
type list_t (line 6) | typedef struct list_s list_t;
type list_head_t (line 7) | typedef ql_head(list_t) list_head_t;
type list_s (line 9) | struct list_s {
function test_empty_list (line 14) | static void
function TEST_BEGIN (line 37) | TEST_BEGIN(test_ql_empty)
function TEST_END (line 44) | TEST_END
function test_entries_list (line 57) | static void
function TEST_BEGIN (line 94) | TEST_BEGIN(test_ql_tail_insert)
function TEST_END (line 107) | TEST_END
function TEST_END (line 126) | TEST_END
function TEST_END (line 141) | TEST_END
function TEST_END (line 160) | TEST_END
function TEST_END (line 196) | TEST_END
FILE: deps/jemalloc/test/unit/qr.c
type ring_t (line 8) | typedef struct ring_s ring_t;
type ring_s (line 10) | struct ring_s {
function init_entries (line 15) | static void
function test_independent_entries (line 26) | static void
function TEST_BEGIN (line 64) | TEST_BEGIN(test_qr_one)
function TEST_END (line 71) | TEST_END
function TEST_BEGIN (line 107) | TEST_BEGIN(test_qr_after_insert)
function TEST_END (line 117) | TEST_END
function TEST_END (line 146) | TEST_END
function TEST_END (line 184) | TEST_END
function TEST_BEGIN (line 209) | TEST_BEGIN(test_qr_meld_split)
function TEST_END (line 236) | TEST_END
FILE: deps/jemalloc/test/unit/quarantine.c
function quarantine_clear (line 12) | void
function TEST_BEGIN (line 22) | TEST_BEGIN(test_quarantine)
function arena_redzone_corruption_replacement (line 61) | static void
function TEST_BEGIN (line 69) | TEST_BEGIN(test_quarantine_redzone)
function TEST_END (line 99) | TEST_END
FILE: deps/jemalloc/test/unit/rb.c
type node_t (line 14) | typedef struct node_s node_t;
type node_s (line 16) | struct node_s {
function node_cmp (line 23) | static int
type tree_t (line 42) | typedef rb_tree(node_t) tree_t;
function TEST_BEGIN (line 45) | TEST_BEGIN(test_rb_empty)
function TEST_END (line 68) | TEST_END
function node_t (line 109) | static node_t *
function tree_iterate (line 137) | static unsigned
function tree_iterate_reverse (line 148) | static unsigned
function node_remove (line 159) | static void
function node_t (line 193) | static node_t *
function node_t (line 204) | static node_t *
function TEST_BEGIN (line 215) | TEST_BEGIN(test_rb_random)
function TEST_END (line 327) | TEST_END
FILE: deps/jemalloc/test/unit/rtree.c
function rtree_node_elm_t (line 3) | static rtree_node_elm_t *
function node_dalloc (line 10) | static void
function TEST_BEGIN (line 17) | TEST_BEGIN(test_rtree_get_empty)
function TEST_END (line 30) | TEST_END
function TEST_END (line 55) | TEST_END
function TEST_END (line 92) | TEST_END
function TEST_END (line 140) | TEST_END
FILE: deps/jemalloc/test/unit/size_classes.c
function get_max_size_class (line 3) | static size_t
function TEST_BEGIN (line 26) | TEST_BEGIN(test_size_classes)
function TEST_END (line 81) | TEST_END
FILE: deps/jemalloc/test/unit/stats.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_stats_summary)
function TEST_END (line 34) | TEST_END
function TEST_END (line 73) | TEST_END
function TEST_END (line 124) | TEST_END
function no_lazy_lock (line 133) | static void
function TEST_BEGIN (line 142) | TEST_BEGIN(test_stats_arenas_small)
function TEST_END (line 189) | TEST_END
function TEST_END (line 233) | TEST_END
function TEST_END (line 273) | TEST_END
function TEST_END (line 347) | TEST_END
function TEST_END (line 391) | TEST_END
function TEST_END (line 431) | TEST_END
FILE: deps/jemalloc/test/unit/tsd.c
type data_t (line 5) | typedef unsigned int data_t;
function data_cleanup (line 10) | malloc_tsd_protos(, data_, data_t)
function TEST_BEGIN (line 79) | TEST_BEGIN(test_tsd_main_thread)
function TEST_END (line 84) | TEST_END
function TEST_END (line 96) | TEST_END
FILE: deps/jemalloc/test/unit/util.c
function TEST_BEGIN (line 3) | TEST_BEGIN(test_pow2_ceil)
function TEST_END (line 32) | TEST_END
function TEST_END (line 43) | TEST_END
function TEST_END (line 136) | TEST_END
function TEST_END (line 169) | TEST_END
function TEST_END (line 282) | TEST_END
FILE: deps/jemalloc/test/unit/zero.c
function test_zero (line 8) | static void
function TEST_BEGIN (line 46) | TEST_BEGIN(test_zero_small)
function TEST_END (line 52) | TEST_END
function TEST_END (line 60) | TEST_END
function TEST_END (line 68) | TEST_END
FILE: deps/linenoise/example.c
function completion (line 7) | void completion(const char *buf, linenoiseCompletions *lc) {
function main (line 14) | int main(int argc, char **argv) {
FILE: deps/linenoise/linenoise.c
type termios (line 124) | struct termios
type linenoiseState (line 135) | struct linenoiseState {
type KEY_ACTION (line 150) | enum KEY_ACTION{
type linenoiseState (line 174) | struct linenoiseState
function linenoiseSetMultiLine (line 198) | void linenoiseSetMultiLine(int ml) {
function isUnsupportedTerm (line 204) | static int isUnsupportedTerm(void) {
function enableRawMode (line 215) | static int enableRawMode(int fd) {
function disableRawMode (line 250) | static void disableRawMode(int fd) {
function getCursorPosition (line 259) | static int getCursorPosition(int ifd, int ofd) {
function getColumns (line 283) | static int getColumns(int ifd, int ofd) {
function linenoiseClearScreen (line 317) | void linenoiseClearScreen(void) {
function linenoiseBeep (line 325) | static void linenoiseBeep(void) {
function freeCompletions (line 333) | static void freeCompletions(linenoiseCompletions *lc) {
function completeLine (line 347) | static int completeLine(struct linenoiseState *ls) {
function linenoiseSetCompletionCallback (line 406) | void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
function linenoiseAddCompletion (line 414) | void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
type abuf (line 436) | struct abuf {
function abInit (line 441) | static void abInit(struct abuf *ab) {
function abAppend (line 446) | static void abAppend(struct abuf *ab, const char *s, int len) {
function abFree (line 455) | static void abFree(struct abuf *ab) {
function refreshSingleLine (line 463) | static void refreshSingleLine(struct linenoiseState *l) {
function refreshMultiLine (line 502) | static void refreshMultiLine(struct linenoiseState *l) {
function refreshLine (line 584) | static void refreshLine(struct linenoiseState *l) {
function linenoiseEditInsert (line 594) | int linenoiseEditInsert(struct linenoiseState *l, char c) {
function linenoiseEditMoveLeft (line 621) | void linenoiseEditMoveLeft(struct linenoiseState *l) {
function linenoiseEditMoveRight (line 629) | void linenoiseEditMoveRight(struct linenoiseState *l) {
function linenoiseEditMoveHome (line 637) | void linenoiseEditMoveHome(struct linenoiseState *l) {
function linenoiseEditMoveEnd (line 645) | void linenoiseEditMoveEnd(struct linenoiseState *l) {
function linenoiseEditHistoryNext (line 656) | void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) {
function linenoiseEditDelete (line 680) | void linenoiseEditDelete(struct linenoiseState *l) {
function linenoiseEditBackspace (line 690) | void linenoiseEditBackspace(struct linenoiseState *l) {
function linenoiseEditDeletePrevWord (line 702) | void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
function linenoiseEdit (line 724) | static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t ...
function linenoisePrintKeyCodes (line 903) | void linenoisePrintKeyCodes(void) {
function linenoiseRaw (line 930) | static int linenoiseRaw(char *buf, size_t buflen, const char *prompt) {
function freeHistory (line 987) | static void freeHistory(void) {
function linenoiseAtExit (line 998) | static void linenoiseAtExit(void) {
function linenoiseHistoryAdd (line 1010) | int linenoiseHistoryAdd(const char *line) {
function linenoiseHistorySetMaxLen (line 1043) | int linenoiseHistorySetMaxLen(int len) {
function linenoiseHistorySave (line 1073) | int linenoiseHistorySave(const char *filename) {
function linenoiseHistoryLoad (line 1089) | int linenoiseHistoryLoad(const char *filename) {
FILE: deps/linenoise/linenoise.h
type linenoiseCompletions (line 44) | typedef struct linenoiseCompletions {
FILE: src/ack.c
function acknowledgeJob (line 40) | void acknowledgeJob(job *job) {
function mstime_t (line 60) | mstime_t getNextGCRetryTime(job *job) {
function tryJobGC (line 69) | void tryJobGC(job *job) {
function gotAckReceived (line 126) | void gotAckReceived(clusterNode *sender, job *job, int known) {
function ackjobCommand (line 218) | void ackjobCommand(client *c) {
function fastackCommand (line 270) | void fastackCommand(client *c) {
FILE: src/adlist.c
function list (line 41) | list *listCreate(void)
function listRelease (line 58) | void listRelease(list *list)
function list (line 80) | list *listAddNodeHead(list *list, void *value)
function list (line 106) | list *listAddNodeTail(list *list, void *value)
function list (line 126) | list *listInsertNode(list *list, listNode *old_node, void *value, int af...
function listDelNode (line 159) | void listDelNode(list *list, listNode *node)
function listIter (line 178) | listIter *listGetIterator(list *list, int direction)
function listReleaseIterator (line 192) | void listReleaseIterator(listIter *iter) {
function listRewind (line 197) | void listRewind(list *list, listIter *li) {
function listRewindTail (line 202) | void listRewindTail(list *list, listIter *li) {
function listNode (line 221) | listNode *listNext(listIter *iter)
function list (line 242) | list *listDup(list *orig)
function listNode (line 285) | listNode *listSearchKey(list *list, void *key)
function listNode (line 313) | listNode *listIndex(list *list, long index) {
function listRotate (line 328) | void listRotate(list *list) {
FILE: src/adlist.h
type listNode (line 36) | typedef struct listNode {
type listIter (line 42) | typedef struct listIter {
type list (line 47) | typedef struct list {
FILE: src/ae.c
function aeEventLoop (line 63) | aeEventLoop *aeCreateEventLoop(int setsize) {
function aeGetSetSize (line 95) | int aeGetSetSize(aeEventLoop *eventLoop) {
function aeResizeSetSize (line 106) | int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) {
function aeDeleteEventLoop (line 124) | void aeDeleteEventLoop(aeEventLoop *eventLoop) {
function aeStop (line 131) | void aeStop(aeEventLoop *eventLoop) {
function aeCreateFileEvent (line 135) | int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask,
function aeDeleteFileEvent (line 155) | void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask)
function aeGetFileEvents (line 173) | int aeGetFileEvents(aeEventLoop *eventLoop, int fd) {
function aeGetTime (line 180) | static void aeGetTime(long *seconds, long *milliseconds)
function aeAddMillisecondsToNow (line 189) | static void aeAddMillisecondsToNow(long long milliseconds, long *sec, lo...
function aeCreateTimeEvent (line 203) | long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
function aeDeleteTimeEvent (line 222) | int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
function aeTimeEvent (line 246) | static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
function processTimeEvents (line 262) | static int processTimeEvents(aeEventLoop *eventLoop) {
function aeProcessEvents (line 349) | int aeProcessEvents(aeEventLoop *eventLoop, int flags)
function aeWait (line 430) | int aeWait(int fd, int mask, long long milliseconds) {
function aeMain (line 450) | void aeMain(aeEventLoop *eventLoop) {
function aeSetBeforeSleepProc (line 463) | void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *bef...
FILE: src/ae.h
type aeEventLoop (line 56) | struct aeEventLoop
type aeEventLoop (line 59) | struct aeEventLoop
type aeEventLoop (line 60) | struct aeEventLoop
type aeEventLoop (line 61) | struct aeEventLoop
type aeEventLoop (line 62) | struct aeEventLoop
type aeFileEvent (line 65) | typedef struct aeFileEvent {
type aeTimeEvent (line 73) | typedef struct aeTimeEvent {
type aeFiredEvent (line 84) | typedef struct aeFiredEvent {
type aeEventLoop (line 90) | typedef struct aeEventLoop {
FILE: src/ae_epoll.c
type aeApiState (line 34) | typedef struct aeApiState {
function aeApiCreate (line 39) | static int aeApiCreate(aeEventLoop *eventLoop) {
function aeApiResize (line 58) | static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
function aeApiFree (line 65) | static void aeApiFree(aeEventLoop *eventLoop) {
function aeApiAddEvent (line 73) | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiDelEvent (line 91) | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) {
function aeApiPoll (line 110) | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
FILE: src/ae_evport.c
type aeApiState (line 68) | typedef struct aeApiState {
function aeApiCreate (line 75) | static int aeApiCreate(aeEventLoop *eventLoop) {
function aeApiResize (line 97) | static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
function aeApiFree (line 102) | static void aeApiFree(aeEventLoop *eventLoop) {
function aeApiLookupPending (line 109) | static int aeApiLookupPending(aeApiState *state, int fd) {
function aeApiAssociate (line 123) | static int aeApiAssociate(const char *where, int portfd, int fd, int mas...
function aeApiAddEvent (line 152) | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiDelEvent (line 183) | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiPoll (line 243) | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
FILE: src/ae_kqueue.c
type aeApiState (line 36) | typedef struct aeApiState {
function aeApiCreate (line 41) | static int aeApiCreate(aeEventLoop *eventLoop) {
function aeApiResize (line 60) | static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
function aeApiFree (line 67) | static void aeApiFree(aeEventLoop *eventLoop) {
function aeApiAddEvent (line 75) | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiDelEvent (line 90) | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiPoll (line 104) | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
FILE: src/ae_select.c
type aeApiState (line 34) | typedef struct aeApiState {
function aeApiCreate (line 41) | static int aeApiCreate(aeEventLoop *eventLoop) {
function aeApiResize (line 51) | static int aeApiResize(aeEventLoop *eventLoop, int setsize) {
function aeApiFree (line 57) | static void aeApiFree(aeEventLoop *eventLoop) {
function aeApiAddEvent (line 61) | static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiDelEvent (line 69) | static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) {
function aeApiPoll (line 76) | static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
FILE: src/anet.c
function anetSetError (line 51) | static void anetSetError(char *err, const char *fmt, ...)
function anetSetBlock (line 61) | int anetSetBlock(char *err, int fd, int non_block) {
function anetNonBlock (line 84) | int anetNonBlock(char *err, int fd) {
function anetBlock (line 88) | int anetBlock(char *err, int fd) {
function anetKeepAlive (line 95) | int anetKeepAlive(char *err, int fd, int interval)
function anetSetTcpNoDelay (line 141) | static int anetSetTcpNoDelay(char *err, int fd, int val)
function anetEnableTcpNoDelay (line 151) | int anetEnableTcpNoDelay(char *err, int fd)
function anetDisableTcpNoDelay (line 156) | int anetDisableTcpNoDelay(char *err, int fd)
function anetSetSendBuffer (line 162) | int anetSetSendBuffer(char *err, int fd, int buffsize)
function anetTcpKeepAlive (line 172) | int anetTcpKeepAlive(char *err, int fd)
function anetSendTimeout (line 184) | int anetSendTimeout(char *err, int fd, long long ms) {
function anetGenericResolve (line 203) | int anetGenericResolve(char *err, char *host, char *ipbuf, size_t ipbuf_...
function anetResolve (line 230) | int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len) {
function anetResolveIP (line 234) | int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len) {
function anetSetReuseAddr (line 238) | static int anetSetReuseAddr(char *err, int fd) {
function anetCreateSocket (line 249) | static int anetCreateSocket(char *err, int domain) {
function anetTcpGenericConnect (line 268) | static int anetTcpGenericConnect(char *err, char *addr, int port,
function anetTcpConnect (line 348) | int anetTcpConnect(char *err, char *addr, int port)
function anetTcpNonBlockConnect (line 353) | int anetTcpNonBlockConnect(char *err, char *addr, int port)
function anetTcpNonBlockBindConnect (line 358) | int anetTcpNonBlockBindConnect(char *err, char *addr, int port,
function anetTcpNonBlockBestEffortBindConnect (line 365) | int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port,
function anetUnixGenericConnect (line 372) | int anetUnixGenericConnect(char *err, char *path, int flags)
function anetUnixConnect (line 398) | int anetUnixConnect(char *err, char *path)
function anetUnixNonBlockConnect (line 403) | int anetUnixNonBlockConnect(char *err, char *path)
function anetRead (line 410) | int anetRead(int fd, char *buf, int count)
function anetWrite (line 425) | int anetWrite(int fd, char *buf, int count)
function anetListen (line 438) | static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t l...
function anetV6Only (line 453) | static int anetV6Only(char *err, int s) {
function _anetTcpServer (line 463) | static int _anetTcpServer(char *err, int port, char *bindaddr, int af, i...
function anetTcpServer (line 500) | int anetTcpServer(char *err, int port, char *bindaddr, int backlog)
function anetTcp6Server (line 505) | int anetTcp6Server(char *err, int port, char *bindaddr, int backlog)
function anetUnixServer (line 510) | int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
function anetGenericAccept (line 528) | static int anetGenericAccept(char *err, int s, struct sockaddr *sa, sock...
function anetTcpAccept (line 545) | int anetTcpAccept(char *err, int s, char *ip, size_t ip_len, int *port) {
function anetUnixAccept (line 564) | int anetUnixAccept(char *err, int s) {
function anetPeerToString (line 574) | int anetPeerToString(int fd, char *ip, size_t ip_len, int *port) {
function anetFormatAddr (line 613) | int anetFormatAddr(char *buf, size_t buf_len, char *ip, int port) {
function anetFormatPeer (line 619) | int anetFormatPeer(int fd, char *buf, size_t buf_len) {
function anetSockName (line 627) | int anetSockName(int fd, char *ip, size_t ip_len, int *port) {
function anetFormatSock (line 649) | int anetFormatSock(int fd, char *fmt, size_t fmt_len) {
FILE: src/aof.c
function startLoading (line 48) | void startLoading(FILE *fp) {
function loadingProgress (line 62) | void loadingProgress(off_t pos) {
function stopLoading (line 69) | void stopLoading(void) {
type aofrwblock (line 99) | typedef struct aofrwblock {
function aofRewriteBufferReset (line 107) | void aofRewriteBufferReset(void) {
function aofRewriteBufferSize (line 116) | unsigned long aofRewriteBufferSize(void) {
function aofChildWriteDiffData (line 132) | void aofChildWriteDiffData(aeEventLoop *el, int fd, void *privdata, int ...
function aofRewriteBufferAppend (line 161) | void aofRewriteBufferAppend(unsigned char *s, unsigned long len) {
function aofRewriteBufferWrite (line 210) | ssize_t aofRewriteBufferWrite(int fd) {
function aof_background_fsync (line 238) | void aof_background_fsync(int fd) {
function stopAppendOnly (line 244) | void stopAppendOnly(void) {
function startAppendOnly (line 273) | int startAppendOnly(void) {
function flushAppendOnlyFile (line 311) | void flushAppendOnlyFile(int force) {
function sds (line 472) | sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv) {
function feedAppendOnlyFile (line 497) | void feedAppendOnlyFile(robj **argv, int argc) {
type client (line 524) | struct client
type client (line 525) | struct client
function freeFakeClientArgv (line 545) | void freeFakeClientArgv(struct client *c) {
function freeFakeClient (line 553) | void freeFakeClient(struct client *c) {
function loadAppendOnlyFile (line 562) | int loadAppendOnlyFile(char *filename) {
function rioWriteBulkObject (line 715) | int rioWriteBulkObject(rio *r, robj *obj) {
function aofReadDiffFromParent (line 730) | ssize_t aofReadDiffFromParent(void) {
function rewriteAppendOnlyFile (line 753) | int rewriteAppendOnlyFile(char *filename, int background) {
function aofChildPipeReadable (line 873) | void aofChildPipeReadable(aeEventLoop *el, int fd, void *privdata, int m...
function aofCreatePipes (line 901) | int aofCreatePipes(void) {
function aofClosePipes (line 929) | void aofClosePipes(void) {
function rewriteAppendOnlyFileBackground (line 956) | int rewriteAppendOnlyFileBackground(void) {
function bgrewriteaofCommand (line 1009) | void bgrewriteaofCommand(client *c) {
function aofRemoveTempFile (line 1019) | void aofRemoveTempFile(pid_t childpid) {
function aofUpdateCurrentSize (line 1030) | void aofUpdateCurrentSize(void) {
function backgroundRewriteDoneHandler (line 1047) | void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
FILE: src/bio.c
type bio_job (line 77) | struct bio_job {
function bioInit (line 91) | void bioInit(void) {
function bioCreateBackgroundJob (line 126) | void bioCreateBackgroundJob(int type, void *arg1, void *arg2, void *arg3) {
type bio_job (line 141) | struct bio_job
function bioPendingJobsOfType (line 196) | unsigned long long bioPendingJobsOfType(int type) {
function bioWaitStepOfType (line 214) | unsigned long long bioWaitStepOfType(int type) {
function bioKillThreads (line 230) | void bioKillThreads(void) {
FILE: src/blocked.c
function getTimeoutFromObjectOrReply (line 76) | int getTimeoutFromObjectOrReply(client *c, robj *object, mstime_t *timeo...
function blockClient (line 100) | void blockClient(client *c, int btype) {
function processUnblockedClients (line 109) | void processUnblockedClients(void) {
function unblockClient (line 136) | void unblockClient(client *c) {
function replyToBlockedClientTimedOut (line 159) | void replyToBlockedClientTimedOut(client *c) {
FILE: src/cluster.c
function clusterLoadConfig (line 84) | int clusterLoadConfig(char *filename) {
function clusterSaveConfig (line 221) | int clusterSaveConfig(int do_fsync) {
function clusterSaveConfigOrDie (line 270) | void clusterSaveConfigOrDie(int do_fsync) {
function clusterLockConfig (line 286) | int clusterLockConfig(char *filename) {
function clusterInit (line 324) | void clusterInit(void) {
function clusterReset (line 404) | void clusterReset(int hard) {
function clusterLink (line 450) | clusterLink *createClusterLink(clusterNode *node) {
function freeClusterLink (line 463) | void freeClusterLink(clusterLink *link) {
function clusterAcceptHandler (line 477) | void clusterAcceptHandler(aeEventLoop *el, int fd, void *privdata, int m...
function clusterNode (line 521) | clusterNode *createClusterNode(char *nodename, int flags) {
function clusterNodeAddFailureReport (line 550) | int clusterNodeAddFailureReport(clusterNode *failing, clusterNode *sende...
function clusterNodeCleanupFailureReports (line 580) | void clusterNodeCleanupFailureReports(clusterNode *node) {
function clusterNodeDelFailureReport (line 607) | int clusterNodeDelFailureReport(clusterNode *node, clusterNode *sender) {
function clusterNodeFailureReportsCount (line 630) | int clusterNodeFailureReportsCount(clusterNode *node) {
function freeClusterNode (line 644) | void freeClusterNode(clusterNode *n) {
function clusterAddNode (line 660) | int clusterAddNode(clusterNode *node) {
function clusterDelNode (line 671) | void clusterDelNode(clusterNode *delnode) {
function clusterNode (line 690) | clusterNode *clusterLookupNode(char *name) {
function clusterRenameNode (line 700) | void clusterRenameNode(clusterNode *node, char *newname) {
function clusterBlacklistCleanup (line 744) | void clusterBlacklistCleanup(void) {
function clusterBlacklistAddNode (line 759) | void clusterBlacklistAddNode(clusterNode *node) {
function clusterBlacklistExists (line 777) | int clusterBlacklistExists(char *nodeid) {
function markNodeAsFailingIfNeeded (line 812) | void markNodeAsFailingIfNeeded(clusterNode *node) {
function clearNodeFailureIfNeeded (line 841) | void clearNodeFailureIfNeeded(clusterNode *node) {
function clusterHandshakeInProgress (line 855) | int clusterHandshakeInProgress(char *ip, int port) {
function clusterStartHandshake (line 877) | int clusterStartHandshake(char *ip, int port) {
function clusterProcessGossipSection (line 933) | void clusterProcessGossipSection(clusterMsg *hdr, clusterLink *link) {
function nodeIp2String (line 1003) | void nodeIp2String(char *buf, clusterLink *link) {
function nodeUpdateAddressIfNeeded (line 1017) | int nodeUpdateAddressIfNeeded(clusterNode *node, clusterLink *link, int ...
function clusterProcessPacket (line 1051) | int clusterProcessPacket(clusterLink *link) {
function handleLinkIOError (line 1508) | void handleLinkIOError(clusterLink *link) {
function clusterWriteHandler (line 1515) | void clusterWriteHandler(aeEventLoop *el, int fd, void *privdata, int ma...
function clusterReadHandler (line 1536) | void clusterReadHandler(aeEventLoop *el, int fd, void *privdata, int mas...
function clusterSendMessage (line 1604) | void clusterSendMessage(clusterLink *link, unsigned char *msg, size_t ms...
function clusterBroadcastMessage (line 1623) | void clusterBroadcastMessage(dict *nodes, void *buf, size_t len) {
function clusterBuildMessageHdr (line 1640) | void clusterBuildMessageHdr(clusterMsg *hdr, int type) {
function clusterSendPing (line 1678) | void clusterSendPing(clusterLink *link, int type) {
function clusterSendFail (line 1801) | void clusterSendFail(char *nodename) {
function clusterReplicateJob (line 1830) | int clusterReplicateJob(job *j, int repl, int noreply) {
function clusterSendJobIDMessage (line 1906) | void clusterSendJobIDMessage(int type, clusterNode *node, char *id, int ...
function clusterBroadcastJobIDMessage (line 1919) | void clusterBroadcastJobIDMessage(dict *nodes, char *id, int type, uint3...
function clusterSendGotJob (line 1945) | void clusterSendGotJob(clusterNode *node, job *j) {
function clusterSendEnqueue (line 1951) | void clusterSendEnqueue(clusterNode *node, job *j, uint32_t delay) {
function clusterBroadcastQueued (line 1963) | void clusterBroadcastQueued(job *j, unsigned char flags) {
function clusterBroadcastWorking (line 1970) | void clusterBroadcastWorking(job *j) {
function clusterBroadcastDelJob (line 1977) | void clusterBroadcastDelJob(job *j) {
function clusterSendWillQueue (line 1986) | void clusterSendWillQueue(job *j) {
function clusterSendSetAck (line 1993) | void clusterSendSetAck(clusterNode *node, job *j) {
function clusterSendGotAck (line 1999) | void clusterSendGotAck(clusterNode *node, char *jobid, int known) {
function clusterSendNeedJobs (line 2004) | void clusterSendNeedJobs(robj *qname, int numjobs, dict *nodes) {
function clusterSendPause (line 2028) | void clusterSendPause(robj *qname, uint32_t flags, dict *nodes) {
function clusterBroadcastPause (line 2053) | void clusterBroadcastPause(robj *qname, uint32_t flags) {
function clusterSendYourJobs (line 2059) | void clusterSendYourJobs(clusterNode *node, job **jobs, uint32_t count) {
function clusterCron (line 2100) | void clusterCron(void) {
function clusterBeforeSleep (line 2287) | void clusterBeforeSleep(void) {
function clusterDoBeforeSleep (line 2304) | void clusterDoBeforeSleep(int flags) {
function clusterUpdateState (line 2320) | void clusterUpdateState(void) {
type disqueNodeFlags (line 2352) | struct disqueNodeFlags {
type disqueNodeFlags (line 2357) | struct disqueNodeFlags
function sds (line 2368) | sds representClusterNodeFlags(sds ci, uint16_t flags) {
function sds (line 2386) | sds clusterGenNodeDescription(clusterNode *node) {
function sds (line 2420) | sds clusterGenNodesDescription(int filter) {
function clusterUpdateReachableNodes (line 2448) | void clusterUpdateReachableNodes(void) {
function clusterShuffleReachableNodes (line 2475) | void clusterShuffleReachableNodes(void) {
function clusterCommand (line 2490) | void clusterCommand(client *c) {
function helloCommand (line 2625) | void helloCommand(client *c) {
FILE: src/cluster.h
type clusterNode (line 22) | struct clusterNode
type clusterLink (line 25) | typedef struct clusterLink {
type clusterNodeFailReport (line 53) | typedef struct clusterNodeFailReport {
type clusterNode (line 58) | typedef struct clusterNode {
type clusterState (line 71) | typedef struct clusterState {
type clusterMsgDataGossip (line 120) | typedef struct {
type clusterMsgDataFail (line 131) | typedef struct {
type clusterMsgDataJob (line 139) | typedef struct {
type clusterMsgDataJobID (line 152) | typedef struct {
type clusterMsgDataQueueOp (line 162) | typedef struct {
type clusterMsg (line 199) | typedef struct {
FILE: src/config.c
type configEnum (line 41) | typedef struct configEnum {
function configEnumGetValue (line 90) | int configEnumGetValue(configEnum *ce, char *name) {
function yesnotoi (line 123) | int yesnotoi(char *s) {
function loadServerConfigFromString (line 129) | void loadServerConfigFromString(char *config) {
function loadServerConfig (line 437) | void loadServerConfig(char *filename, char *options) {
function configSetCommand (line 501) | void configSetCommand(client *c) {
FILE: src/crc64.c
function crc64 (line 173) | uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) {
function main (line 186) | int main(void) {
FILE: src/debug.c
function debugCommand (line 54) | void debugCommand(client *c) {
function _serverAssert (line 127) | void _serverAssert(char *estr, char *file, int line) {
function _serverAssertPrintClientInfo (line 140) | void _serverAssertPrintClientInfo(client *c) {
function _serverAssertPrintObject (line 164) | void _serverAssertPrintObject(robj *o) {
function serverLogObjectDebugInfo (line 170) | void serverLogObjectDebugInfo(robj *o) {
function _serverAssertWithInfo (line 184) | void _serverAssertWithInfo(client *c, robj *o, char *estr, char *file, i...
function _serverPanic (line 190) | void _serverPanic(char *msg, char *file, int line) {
function bugReportStart (line 202) | void bugReportStart(void) {
function logStackContent (line 242) | void logStackContent(void **sp) {
function logRegisters (line 255) | void logRegisters(ucontext_t *uc) {
function logStackTrace (line 386) | void logStackTrace(ucontext_t *uc) {
function logCurrentClient (line 414) | void logCurrentClient(void) {
function memtest_test_linux_anonymous_maps (line 439) | int memtest_test_linux_anonymous_maps(void) {
function sigsegvHandler (line 517) | void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
function serverLogHexDump (line 586) | void serverLogHexDump(int level, char *descr, void *value, size_t len) {
function watchdogSignalHandler (line 611) | void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) {
function watchdogScheduleSignal (line 630) | void watchdogScheduleSignal(int period) {
function enableWatchdog (line 643) | void enableWatchdog(int period) {
function disableWatchdog (line 666) | void disableWatchdog(void) {
FILE: src/dict.c
function dictIntHashFunction (line 71) | unsigned int dictIntHashFunction(unsigned int key)
function dictSetHashFunctionSeed (line 84) | void dictSetHashFunctionSeed(uint32_t seed) {
function dictGetHashFunctionSeed (line 88) | uint32_t dictGetHashFunctionSeed(void) {
function dictGenHashFunction (line 103) | unsigned int dictGenHashFunction(const void *key, int len) {
function dictGenCaseHashFunction (line 147) | unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {
function _dictReset (line 159) | static void _dictReset(dictht *ht)
function dict (line 168) | dict *dictCreate(dictType *type,
function _dictInit (line 178) | int _dictInit(dict *d, dictType *type,
function dictResize (line 192) | int dictResize(dict *d)
function dictExpand (line 204) | int dictExpand(dict *d, unsigned long size)
function dictRehash (line 245) | int dictRehash(dict *d, int n) {
function timeInMilliseconds (line 290) | long long timeInMilliseconds(void) {
function dictRehashMilliseconds (line 298) | int dictRehashMilliseconds(dict *d, int ms) {
function _dictRehashStep (line 317) | static void _dictRehashStep(dict *d) {
function dictAdd (line 322) | int dictAdd(dict *d, void *key, void *val)
function dictEntry (line 346) | dictEntry *dictAddRaw(dict *d, void *key)
function dictReplace (line 375) | int dictReplace(dict *d, void *key, void *val)
function dictEntry (line 402) | dictEntry *dictReplaceRaw(dict *d, void *key) {
function dictGenericDelete (line 409) | static int dictGenericDelete(dict *d, const void *key, int nofree)
function dictDelete (line 446) | int dictDelete(dict *ht, const void *key) {
function dictDeleteNoFree (line 450) | int dictDeleteNoFree(dict *ht, const void *key) {
function _dictClear (line 455) | int _dictClear(dict *d, dictht *ht, void(callback)(void *)) {
function dictRelease (line 482) | void dictRelease(dict *d)
function dictEntry (line 489) | dictEntry *dictFind(dict *d, const void *key)
function dictFingerprint (line 523) | long long dictFingerprint(dict *d) {
function dictIterator (line 555) | dictIterator *dictGetIterator(dict *d)
function dictIterator (line 568) | dictIterator *dictGetSafeIterator(dict *d) {
function dictEntry (line 575) | dictEntry *dictNext(dictIterator *iter)
function dictReleaseIterator (line 610) | void dictReleaseIterator(dictIterator *iter)
function dictEntry (line 623) | dictEntry *dictGetRandomKey(dict *d)
function dictGetSomeKeys (line 686) | unsigned int dictGetSomeKeys(dict *d, dictEntry **des, unsigned int coun...
function rev (line 755) | static unsigned long rev(unsigned long v) {
function dictScan (line 849) | unsigned long dictScan(dict *d,
function _dictExpandIfNeeded (line 923) | static int _dictExpandIfNeeded(dict *d)
function _dictNextPower (line 945) | static unsigned long _dictNextPower(unsigned long size)
function _dictKeyIndex (line 963) | static int _dictKeyIndex(dict *d, const void *key)
function dictEmpty (line 987) | void dictEmpty(dict *d, void(callback)(void*)) {
function dictEnableResize (line 994) | void dictEnableResize(void) {
function dictDisableResize (line 998) | void dictDisableResize(void) {
function _dictPrintStatsHt (line 1010) | static void _dictPrintStatsHt(dictht *ht) {
function dictPrintStats (line 1054) | void dictPrintStats(dict *d) {
function _dictStringCopyHTHashFunction (line 1064) | static unsigned int _dictStringCopyHTHashFunction(const void *key)
function _dictStringCopyHTKeyCompare (line 1080) | static int _dictStringCopyHTKeyCompare(void *privdata, const void *key1,
function _dictStringDestructor (line 1088) | static void _dictStringDestructor(void *privdata, void *key)
FILE: src/dict.h
type dictEntry (line 47) | typedef struct dictEntry {
type dictType (line 58) | typedef struct dictType {
type dictht (line 69) | typedef struct dictht {
type dict (line 76) | typedef struct dict {
type dictIterator (line 88) | typedef struct dictIterator {
FILE: src/disque-check-aof.c
function consumeNewline (line 48) | int consumeNewline(char *buf) {
function readLong (line 56) | int readLong(FILE *fp, char prefix, long *target) {
function readBytes (line 70) | int readBytes(FILE *fp, char *target, long length) {
function readString (line 81) | int readString(FILE *fp, char** target) {
function readArgc (line 101) | int readArgc(FILE *fp, long *target) {
function off_t (line 105) | off_t process(FILE *fp) {
function main (line 149) | int main(int argc, char **argv) {
FILE: src/disque-cli.c
type config (line 65) | struct config {
function ustime (line 110) | static long long ustime(void) {
function mstime (line 120) | static long long mstime(void) {
function cliRefreshPrompt (line 124) | static void cliRefreshPrompt(void) {
type helpEntry (line 148) | typedef struct {
function sds (line 161) | static sds cliVersion(void) {
function cliInitHelp (line 175) | static void cliInitHelp(void) {
function cliOutputCommandHelp (line 204) | static void cliOutputCommandHelp(struct commandHelp *help, int group) {
function cliOutputGenericHelp (line 214) | static void cliOutputGenericHelp(void) {
function cliOutputHelp (line 228) | static void cliOutputHelp(int argc, char **argv) {
function completionCallback (line 272) | static void completionCallback(const char *buf, linenoiseCompletions *lc) {
function cliAuth (line 305) | static int cliAuth() {
function cliSelect (line 318) | static int cliSelect() {
function cliConnect (line 334) | static int cliConnect(int force) {
function cliPrintContextError (line 371) | static void cliPrintContextError(void) {
function sds (line 376) | static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
function sds (line 443) | static sds cliFormatReplyRaw(redisReply *r) {
function sds (line 477) | static sds cliFormatReplyCSV(redisReply *r) {
function cliReadReply (line 513) | static int cliReadReply(int output_raw_strings) {
function cliSendCommand (line 593) | static int cliSendCommand(int argc, char **argv, int repeat) {
function redisReply (line 676) | static redisReply *reconnectingInfo(void) {
function parseOptions (line 709) | static int parseOptions(int argc, char **argv) {
function sds (line 795) | static sds readArgFromStdin(void) {
function usage (line 812) | static void usage(void) {
function repl (line 880) | static void repl(void) {
function noninteractive (line 971) | static int noninteractive(int argc, char **argv) {
function evalMode (line 988) | static int evalMode(int argc, char **argv) {
function latencyMode (line 1032) | static void latencyMode(void) {
function sendSync (line 1080) | unsigned long long sendSync(int fd) {
function slaveMode (line 1113) | static void slaveMode(void) {
function getRDB (line 1147) | static void getRDB(void) {
function pipeMode (line 1194) | static void pipeMode(void) {
function redisReply (line 1356) | static redisReply *sendScan(unsigned long long *it) {
function getDbSize (line 1384) | static int getDbSize(void) {
function toIntType (line 1402) | static int toIntType(char *key, char *type) {
function getKeyTypes (line 1421) | static void getKeyTypes(redisReply *keys, int *types) {
function getKeySizes (line 1447) | static void getKeySizes(redisReply *keys, int *types,
function findBigKeys (line 1492) | static void findBigKeys(void) {
function getLongInfoField (line 1648) | static long getLongInfoField(char *info, char *field) {
function bytesToHuman (line 1660) | void bytesToHuman(char *s, long long n) {
function statMode (line 1684) | static void statMode(void) {
function scanMode (line 1770) | static void scanMode(void) {
function compute_something_fast (line 1810) | unsigned long compute_something_fast(void) {
function intrinsicLatencyModeStop (line 1830) | static void intrinsicLatencyModeStop(int s) {
function intrinsicLatencyMode (line 1835) | static void intrinsicLatencyMode(void) {
function main (line 1876) | int main(int argc, char **argv) {
FILE: src/endianconv.c
function memrev16 (line 49) | void memrev16(void *p) {
function memrev32 (line 59) | void memrev32(void *p) {
function memrev64 (line 72) | void memrev64(void *p) {
function intrev16 (line 89) | uint16_t intrev16(uint16_t v) {
function intrev32 (line 94) | uint32_t intrev32(uint32_t v) {
function intrev64 (line 99) | uint64_t intrev64(uint64_t v) {
function main (line 107) | int main(void) {
FILE: src/help.h
type commandHelp (line 14) | struct commandHelp {
FILE: src/job.c
function generateJobID (line 74) | void generateJobID(char *id, int ttl, int retry) {
function hexToInt (line 136) | uint64_t hexToInt(char *p, size_t count) {
function compareNodeIDsByJob (line 168) | int compareNodeIDsByJob(clusterNode *nodea, clusterNode *nodeb, job *j) {
function getRawTTLFromJobID (line 185) | int getRawTTLFromJobID(char *id) {
function setJobTTLFromID (line 193) | void setJobTTLFromID(job *job) {
function validateJobID (line 203) | int validateJobID(char *id, size_t len) {
function validateJobIdOrReply (line 214) | int validateJobIdOrReply(client *c, char *id, size_t len) {
function job (line 227) | job *createJob(char *id, int state, int ttl, int retry) {
function freeJob (line 252) | void freeJob(job *j) {
function registerJob (line 268) | int registerJob(job *j) {
function job (line 277) | job *lookupJob(char *id) {
function unregisterJob (line 285) | int unregisterJob(job *j) {
function setJobAssociatedValue (line 327) | void setJobAssociatedValue(job *j, void *val) {
type dictEntry (line 334) | struct dictEntry
function jobStateFromString (line 348) | int jobStateFromString(char *state) {
function updateJobAwakeTime (line 384) | void updateJobAwakeTime(job *j, mstime_t at) {
function updateJobRequeueTime (line 421) | void updateJobRequeueTime(job *j, mstime_t qtime) {
function skiplistCompareJobsToAwake (line 430) | int skiplistCompareJobsToAwake(const void *a, const void *b) {
function logJobsDebugInfo (line 441) | void logJobsDebugInfo(int level, char *msg, job *j) {
function processJob (line 462) | void processJob(job *j) {
function processJobs (line 537) | int processJobs(struct aeEventLoop *eventLoop, long long id, void *clien...
function sds (line 665) | sds serializeJob(sds jobs, job *j, int sertype) {
function job (line 764) | job *deserializeJob(unsigned char *p, size_t len, unsigned char **next, ...
function updateJobNodes (line 864) | void updateJobNodes(job *j) {
function deleteJobFromCluster (line 895) | void deleteJobFromCluster(job *j) {
function validateJobIDs (line 908) | int validateJobIDs(client *c, robj **ids, int count) {
function AOFLoadJob (line 924) | void AOFLoadJob(job *job) {
function AOFDelJob (line 943) | void AOFDelJob(job *job) {
function AOFAckJob (line 961) | void AOFAckJob(job *job) {
function loadjobCommand (line 969) | void loadjobCommand(client *c) {
function unblockClientWaitingJobRepl (line 1007) | void unblockClientWaitingJobRepl(client *c) {
function addReplyJobID (line 1022) | void addReplyJobID(client *c, job *j) {
function jobReplicationAchieved (line 1044) | int jobReplicationAchieved(job *j) {
function clientsCronHandleDelayedJobReplication (line 1098) | int clientsCronHandleDelayedJobReplication(client *c) {
function addjobCommand (line 1135) | void addjobCommand(client *c) {
function addReplyJobInfo (line 1377) | void addReplyJobInfo(client *c, job *j) {
function showCommand (line 1459) | void showCommand(client *c) {
function deljobCommand (line 1480) | void deljobCommand(client *c) {
type jscanFilter (line 1528) | struct jscanFilter {
function jscanCallback (line 1535) | void jscanCallback(void *privdata, const dictEntry *de) {
function jscanCommand (line 1554) | void jscanCommand(client *c) {
FILE: src/job.h
type job (line 100) | typedef struct job {
type clusterNode (line 152) | struct clusterNode
type clusterNode (line 155) | struct clusterNode
type clusterNode (line 155) | struct clusterNode
FILE: src/latency.c
function dictStringKeyCompare (line 39) | int dictStringKeyCompare(void *privdata, const void *key1, const void *k...
function dictStringHash (line 44) | unsigned int dictStringHash(const void *key) {
function latencyMonitorInit (line 64) | void latencyMonitorInit(void) {
function latencyAddSample (line 72) | void latencyAddSample(char *event, mstime_t latency) {
function latencyResetEvent (line 108) | int latencyResetEvent(char *event_to_reset) {
function analyzeLatencyForEvent (line 133) | void analyzeLatencyForEvent(char *event, struct latencyStats *ls) {
function sds (line 190) | sds createLatencyReport(void) {
function latencyCommandReplyWithSamples (line 430) | void latencyCommandReplyWithSamples(client *c, struct latencyTimeSeries ...
function latencyCommandReplyWithLatestEvents (line 448) | void latencyCommandReplyWithLatestEvents(client *c) {
function sds (line 469) | sds latencyCommandGenSparkeline(char *event, struct latencyTimeSeries *t...
function latencyCommand (line 522) | void latencyCommand(client *c) {
FILE: src/latency.h
type latencySample (line 41) | struct latencySample {
type latencyTimeSeries (line 47) | struct latencyTimeSeries {
type latencyStats (line 54) | struct latencyStats {
FILE: src/lzfP.h
type u8 (line 127) | typedef unsigned char u8;
type u8 (line 129) | typedef const u8 *LZF_STATE[1 << (HLOG)];
type u16 (line 135) | typedef unsigned short u16;
type u16 (line 137) | typedef unsigned int u16;
FILE: src/lzf_c.c
function lzf_compress (line 98) | unsigned int
FILE: src/lzf_d.c
function lzf_decompress (line 55) | unsigned int
FILE: src/memtest.c
type winsize (line 56) | struct winsize
function memtest_progress_start (line 60) | void memtest_progress_start(char *title, int pass) {
function memtest_progress_end (line 75) | void memtest_progress_end(void) {
function memtest_progress_step (line 79) | void memtest_progress_step(size_t curr, size_t size, char c) {
function memtest_addressing (line 90) | void memtest_addressing(unsigned long *l, size_t bytes) {
function memtest_fill_random (line 118) | void memtest_fill_random(unsigned long *l, size_t bytes) {
function memtest_fill_value (line 148) | void memtest_fill_value(unsigned long *l, size_t bytes, unsigned long v1,
function memtest_compare (line 179) | void memtest_compare(unsigned long *l, size_t bytes) {
function memtest_compare_times (line 198) | void memtest_compare_times(unsigned long *m, size_t bytes, int pass, int...
function memtest_test (line 208) | void memtest_test(size_t megabytes, int passes) {
function memtest_non_destructive_invert (line 243) | void memtest_non_destructive_invert(void *addr, size_t size) {
function memtest_non_destructive_swap (line 253) | void memtest_non_destructive_swap(void *addr, size_t size) {
function memtest (line 269) | void memtest(size_t megabytes, int passes) {
FILE: src/networking.c
function sdsZmallocSize (line 39) | size_t sdsZmallocSize(sds s) {
function getStringObjectSdsUsedMemory (line 46) | size_t getStringObjectSdsUsedMemory(robj *o) {
function freeClientReplyValue (line 60) | void freeClientReplyValue(void *o) {
function listMatchObjects (line 64) | int listMatchObjects(void *a, void *b) {
function client (line 68) | client *createClient(int fd) {
function prepareClientToWrite (line 134) | int prepareClientToWrite(client *c) {
function _addReplyToBuffer (line 165) | int _addReplyToBuffer(client *c, const char *s, size_t len) {
function _addReplyObjectToList (line 182) | void _addReplyObjectToList(client *c, robj *o) {
function _addReplySdsToList (line 210) | void _addReplySdsToList(client *c, sds s) {
function _addReplyStringToList (line 238) | void _addReplyStringToList(client *c, const char *s, size_t len) {
function addReply (line 269) | void addReply(client *c, robj *obj) {
function addReplySds (line 305) | void addReplySds(client *c, sds s) {
function addReplyString (line 319) | void addReplyString(client *c, const char *s, size_t len) {
function addReplyErrorLength (line 325) | void addReplyErrorLength(client *c, const char *s, size_t len) {
function addReplyError (line 331) | void addReplyError(client *c, const char *err) {
function addReplyErrorFormat (line 335) | void addReplyErrorFormat(client *c, const char *fmt, ...) {
function addReplyStatusLength (line 351) | void addReplyStatusLength(client *c, const char *s, size_t len) {
function addReplyStatus (line 357) | void addReplyStatus(client *c, const char *status) {
function addReplyStatusFormat (line 361) | void addReplyStatusFormat(client *c, const char *fmt, ...) {
function setDeferredMultiBulkLength (line 382) | void setDeferredMultiBulkLength(client *c, void *node, long length) {
function addReplyDouble (line 409) | void addReplyDouble(client *c, double d) {
function addReplyLongLongWithPrefix (line 425) | void addReplyLongLongWithPrefix(client *c, long long ll, char prefix) {
function addReplyLongLong (line 447) | void addReplyLongLong(client *c, long long ll) {
function addReplyMultiBulkLen (line 456) | void addReplyMultiBulkLen(client *c, long length) {
function addReplyBulkLen (line 464) | void addReplyBulkLen(client *c, robj *obj) {
function addReplyBulk (line 490) | void addReplyBulk(client *c, robj *obj) {
function addReplyBulkCBuffer (line 497) | void addReplyBulkCBuffer(client *c, const void *p, size_t len) {
function addReplyBulkSds (line 504) | void addReplyBulkSds(client *c, sds s) {
function addReplyBulkCString (line 512) | void addReplyBulkCString(client *c, const char *s) {
function addReplyBulkLongLong (line 521) | void addReplyBulkLongLong(client *c, long long ll) {
function copyClientOutputBuffer (line 532) | void copyClientOutputBuffer(client *dst, client *src) {
function clientHasPendingReplies (line 542) | int clientHasPendingReplies(client *c) {
function acceptCommonHandler (line 547) | static void acceptCommonHandler(int fd, int flags) {
function acceptTcpHandler (line 575) | void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
function acceptUnixHandler (line 595) | void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
function freeClientArgv (line 614) | static void freeClientArgv(client *c) {
function unlinkClient (line 625) | void unlinkClient(client *c) {
function freeClient (line 663) | void freeClient(client *c) {
function freeClientAsync (line 710) | void freeClientAsync(client *c) {
function freeClientsInAsyncFreeQueue (line 716) | void freeClientsInAsyncFreeQueue(void) {
function writeToClient (line 729) | int writeToClient(int fd, client *c, int handler_installed) {
function sendReplyToClient (line 806) | void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
function handleClientsWithPendingWrites (line 816) | int handleClientsWithPendingWrites(void) {
function resetClient (line 843) | void resetClient(client *c) {
function processInlineBuffer (line 859) | int processInlineBuffer(client *c) {
function setProtocolError (line 914) | static void setProtocolError(client *c, int pos) {
function processMultibulkBuffer (line 925) | int processMultibulkBuffer(client *c) {
function processInputBuffer (line 1063) | void processInputBuffer(client *c) {
function readQueryFromClient (line 1107) | void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int ma...
function getClientsMaxBuffers (line 1163) | void getClientsMaxBuffers(unsigned long *longest_output_list,
function formatPeerID (line 1185) | void formatPeerID(char *peerid, size_t peerid_len, char *ip, int port) {
function genClientPeerID (line 1205) | int genClientPeerID(client *client, char *peerid, size_t peerid_len) {
function sds (line 1237) | sds catClientInfoString(sds s, client *client) {
function sds (line 1274) | sds getAllClientsInfoString(void) {
function clientCommand (line 1290) | void clientCommand(client *c) {
function rewriteClientCommandVector (line 1449) | void rewriteClientCommandVector(client *c, int argc, ...) {
function rewriteClientCommandArgument (line 1478) | void rewriteClientCommandArgument(client *c, int i, robj *newval) {
function getClientOutputBufferMemoryUsage (line 1507) | unsigned long getClientOutputBufferMemoryUsage(client *c) {
function getClientType (line 1521) | int getClientType(client *c) {
function getClientTypeByName (line 1526) | int getClientTypeByName(char *name) {
function checkClientOutputBufferLimits (line 1544) | int checkClientOutputBufferLimits(client *c) {
function asyncCloseClientOnOutputBufferLimitReached (line 1585) | void asyncCloseClientOnOutputBufferLimitReached(client *c) {
function pauseClients (line 1614) | void pauseClients(mstime_t end) {
function clientsArePaused (line 1622) | int clientsArePaused(void) {
function processEventsWhileBlocked (line 1653) | int processEventsWhileBlocked(void) {
FILE: src/object.c
function robj (line 39) | robj *createObject(int type, void *ptr) {
function robj (line 51) | robj *createRawStringObject(const char *ptr, size_t len) {
function robj (line 58) | robj *createEmbeddedStringObject(const char *ptr, size_t len) {
function robj (line 87) | robj *createStringObject(const char *ptr, size_t len) {
function robj (line 94) | robj *createStringObjectFromLongLong(long long value) {
function robj (line 113) | robj *createStringObjectFromLongDouble(long double value) {
function robj (line 143) | robj *dupStringObject(robj *o) {
function freeStringObject (line 164) | void freeStringObject(robj *o) {
function incrRefCount (line 170) | void incrRefCount(robj *o) {
function decrRefCount (line 174) | void decrRefCount(robj *o) {
function decrRefCountVoid (line 190) | void decrRefCountVoid(void *o) {
function robj (line 206) | robj *resetRefCount(robj *obj) {
function checkType (line 211) | int checkType(client *c, robj *o, int type) {
function isObjectRepresentableAsLongLong (line 219) | int isObjectRepresentableAsLongLong(robj *o, long long *llval) {
function robj (line 230) | robj *tryObjectEncoding(robj *o) {
function robj (line 306) | robj *getDecodedObject(robj *o) {
function compareStringObjectsWithFlags (line 335) | int compareStringObjectsWithFlags(robj *a, robj *b, int flags) {
function compareStringObjects (line 368) | int compareStringObjects(robj *a, robj *b) {
function collateStringObjects (line 373) | int collateStringObjects(robj *a, robj *b) {
function equalStringObjects (line 381) | int equalStringObjects(robj *a, robj *b) {
function stringObjectLen (line 392) | size_t stringObjectLen(robj *o) {
function getDoubleFromObject (line 401) | int getDoubleFromObject(robj *o, double *target) {
function getDoubleFromObjectOrReply (line 429) | int getDoubleFromObjectOrReply(client *c, robj *o, double *target, const...
function getLongDoubleFromObject (line 443) | int getLongDoubleFromObject(robj *o, long double *target) {
function getLongDoubleFromObjectOrReply (line 467) | int getLongDoubleFromObjectOrReply(client *c, robj *o, long double *targ...
function getLongLongFromObject (line 481) | int getLongLongFromObject(robj *o, long long *target) {
function getLongLongFromObjectOrReply (line 505) | int getLongLongFromObjectOrReply(client *c, robj *o, long long *target, ...
function getLongFromObjectOrReply (line 519) | int getLongFromObjectOrReply(client *c, robj *o, long *target, const cha...
function parseScanCursorOrReply (line 541) | int parseScanCursorOrReply(client *c, robj *o, unsigned long *cursor) {
FILE: src/pqsort.c
function swapfunc (line 68) | static inline void
function _pqsort (line 98) | static void
function pqsort (line 179) | void
FILE: src/queue.c
function skiplistCompareJobsInQueue (line 50) | int skiplistCompareJobsInQueue(const void *a, const void *b) {
function queue (line 61) | queue *createQueue(robj *name) {
function queue (line 91) | queue *lookupQueue(robj *name) {
function destroyQueue (line 101) | int destroyQueue(robj *name) {
function addReplyJob (line 120) | void addReplyJob(client *c, job *j, int flags) {
function enqueueJob (line 148) | int enqueueJob(job *job, int nack) {
function dequeueJob (line 198) | int dequeueJob(job *job) {
function job (line 217) | job *queueFetchJob(queue *q, unsigned long *qlen) {
function job (line 229) | job *queueNameFetchJob(robj *qname, unsigned long *qlen) {
function queueLength (line 235) | unsigned long queueLength(queue *q) {
function queueNameLength (line 242) | unsigned long queueNameLength(robj *qname) {
function GCQueue (line 250) | int GCQueue(queue *q, time_t max_idle_time) {
function evictIdleQueues (line 262) | int evictIdleQueues(void) {
function blockForJobs (line 301) | void blockForJobs(client *c, robj **queues, int numqueues, mstime_t time...
function unblockClientBlockedForJobs (line 323) | void unblockClientBlockedForJobs(client *c) {
function signalQueueAsReady (line 346) | void signalQueueAsReady(queue *q) {
function handleClientsBlockedOnQueues (line 354) | void handleClientsBlockedOnQueues(void) {
function clientsCronSendNeedJobs (line 386) | int clientsCronSendNeedJobs(client *c) {
function getQueueImportRate (line 401) | uint32_t getQueueImportRate(queue *q) {
function updateQueueImportRate (line 419) | void updateQueueImportRate(queue *q) {
function getQueueValidResponders (line 436) | unsigned long getQueueValidResponders(queue *q) {
function needJobsForQueue (line 481) | void needJobsForQueue(queue *q, int type) {
function needJobsForQueueName (line 550) | void needJobsForQueueName(robj *qname, int type) {
function receiveYourJobs (line 560) | void receiveYourJobs(clusterNode *node, uint32_t numjobs, unsigned char ...
function receiveNeedJobs (line 622) | void receiveNeedJobs(clusterNode *node, robj *qname, uint32_t count) {
function queueChangePausedState (line 674) | void queueChangePausedState(queue *q, int flag, int set) {
function receivePauseQueue (line 688) | void receivePauseQueue(robj *qname, uint32_t flags) {
function qlenCommand (line 723) | void qlenCommand(client *c) {
function getjobCommand (line 738) | void getjobCommand(client *c) {
function enqueueGenericCommand (line 854) | void enqueueGenericCommand(client *c, int nack) {
function enqueueCommand (line 871) | void enqueueCommand(client *c) {
function nackCommand (line 876) | void nackCommand(client *c) {
function dequeueCommand (line 887) | void dequeueCommand(client *c) {
function qpeekCommand (line 914) | void qpeekCommand(client *c) {
type qscanFilter (line 975) | struct qscanFilter {
function qscanCallback (line 981) | void qscanCallback(void *privdata, const dictEntry *de) {
function qscanCommand (line 1002) | void qscanCommand(client *c) {
function workingCommand (line 1093) | void workingCommand(client *c) {
function qstatCommand (line 1128) | void qstatCommand(client *c) {
function pauseCommand (line 1183) | void pauseCommand(client *c) {
FILE: src/queue.h
type queue (line 40) | typedef struct queue {
type clusterNode (line 83) | struct clusterNode
type clusterNode (line 103) | struct clusterNode
type clusterNode (line 104) | struct clusterNode
FILE: src/release.c
function disqueBuildId (line 48) | uint64_t disqueBuildId(void) {
FILE: src/rio.c
function rioBufferWrite (line 61) | static size_t rioBufferWrite(rio *r, const void *buf, size_t len) {
function rioBufferRead (line 68) | static size_t rioBufferRead(rio *r, void *buf, size_t len) {
function off_t (line 77) | static off_t rioBufferTell(rio *r) {
function rioBufferFlush (line 83) | static int rioBufferFlush(rio *r) {
function rioInitWithBuffer (line 100) | void rioInitWithBuffer(rio *r, sds s) {
function rioFileWrite (line 109) | static size_t rioFileWrite(rio *r, const void *buf, size_t len) {
function rioFileRead (line 126) | static size_t rioFileRead(rio *r, void *buf, size_t len) {
function off_t (line 131) | static off_t rioFileTell(rio *r) {
function rioFileFlush (line 137) | static int rioFileFlush(rio *r) {
function rioInitWithFile (line 153) | void rioInitWithFile(rio *r, FILE *fp) {
function rioFdsetWrite (line 169) | static size_t rioFdsetWrite(rio *r, const void *buf, size_t len) {
function rioFdsetRead (line 234) | static size_t rioFdsetRead(rio *r, void *buf, size_t len) {
function off_t (line 242) | static off_t rioFdsetTell(rio *r) {
function rioFdsetFlush (line 248) | static int rioFdsetFlush(rio *r) {
function rioInitWithFdset (line 266) | void rioInitWithFdset(rio *r, int *fds, int numfds) {
function rioFreeFdset (line 279) | void rioFreeFdset(rio *r) {
function rioGenericUpdateChecksum (line 289) | void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len) {
function rioSetAutoSync (line 301) | void rioSetAutoSync(rio *r, off_t bytes) {
function rioWriteBulkCount (line 312) | size_t rioWriteBulkCount(rio *r, char prefix, int count) {
function rioWriteBulkString (line 325) | size_t rioWriteBulkString(rio *r, const char *buf, size_t len) {
function rioWriteBulkLongLong (line 335) | size_t rioWriteBulkLongLong(rio *r, long long l) {
function rioWriteBulkDouble (line 344) | size_t rioWriteBulkDouble(rio *r, double d) {
FILE: src/rio.h
type _rio (line 39) | struct _rio {
type rio (line 87) | typedef struct _rio rio;
function rioWrite (line 93) | static inline size_t rioWrite(rio *r, const void *buf, size_t len) {
function rioRead (line 106) | static inline size_t rioRead(rio *r, void *buf, size_t len) {
function off_t (line 119) | static inline off_t rioTell(rio *r) {
function rioFlush (line 123) | static inline int rioFlush(rio *r) {
FILE: src/sds.c
function sdsHdrSize (line 41) | static inline int sdsHdrSize(char type) {
function sdsReqType (line 57) | static inline char sdsReqType(size_t string_size) {
function sds (line 81) | sds sdsnewlen(const void *init, size_t initlen) {
function sds (line 139) | sds sdsempty(void) {
function sds (line 144) | sds sdsnew(const char *init) {
function sds (line 150) | sds sdsdup(const sds s) {
function sdsfree (line 155) | void sdsfree(sds s) {
function sdsupdatelen (line 174) | void sdsupdatelen(sds s) {
function sdsclear (line 183) | void sdsclear(sds s) {
function sds (line 194) | sds sdsMakeRoomFor(sds s, size_t addlen) {
function sds (line 245) | sds sdsRemoveFreeSpace(sds s) {
function sdsAllocSize (line 278) | size_t sdsAllocSize(sds s) {
function sdsIncrLen (line 312) | void sdsIncrLen(sds s, int incr) {
function sds (line 358) | sds sdsgrowzero(sds s, size_t len) {
function sds (line 376) | sds sdscatlen(sds s, const void *t, size_t len) {
function sds (line 391) | sds sdscat(sds s, const char *t) {
function sds (line 399) | sds sdscatsds(sds s, const sds t) {
function sds (line 405) | sds sdscpylen(sds s, const char *t, size_t len) {
function sds (line 418) | sds sdscpy(sds s, const char *t) {
function sdsll2str (line 429) | int sdsll2str(char *s, long long value) {
function sdsull2str (line 461) | int sdsull2str(char *s, unsigned long long v) {
function sds (line 493) | sds sdsfromlonglong(long long value) {
function sds (line 501) | sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
function sds (line 554) | sds sdscatprintf(sds s, const char *fmt, ...) {
function sds (line 579) | sds sdscatfmt(sds s, char const *fmt, ...) {
function sds (line 683) | sds sdstrim(sds s, const char *cset) {
function sdsrange (line 714) | void sdsrange(sds s, int start, int end) {
function sdstolower (line 743) | void sdstolower(sds s) {
function sdstoupper (line 750) | void sdstoupper(sds s) {
function sdscmp (line 767) | int sdscmp(const sds s1, const sds s2) {
function sds (line 795) | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, in...
function sdsfreesplitres (line 845) | void sdsfreesplitres(sds *tokens, int count) {
function sds (line 858) | sds sdscatrepr(sds s, const char *p, size_t len) {
function is_hex_digit (line 885) | int is_hex_digit(char c) {
function hex_digit_to_int (line 892) | int hex_digit_to_int(char c) {
function sds (line 933) | sds *sdssplitargs(const char *line, int *argc) {
function sds (line 1052) | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
function sds (line 1068) | sds sdsjoin(char **argv, int argc, char *sep) {
function sds (line 1080) | sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
function sdsTest (line 1097) | int sdsTest(void) {
function main (line 1262) | int main(void) {
FILE: src/sds.h
type sdshdr5 (line 46) | struct __attribute__ ((__packed__)) sdshdr5 {
type sdshdr8 (line 50) | struct __attribute__ ((__packed__)) sdshdr8 {
type sdshdr16 (line 56) | struct __attribute__ ((__packed__)) sdshdr16 {
type sdshdr32 (line 62) | struct __attribute__ ((__packed__)) sdshdr32 {
type sdshdr64 (line 68) | struct __attribute__ ((__packed__)) sdshdr64 {
function sdslen (line 86) | static inline size_t sdslen(const sds s) {
function sdsavail (line 103) | static inline size_t sdsavail(const sds s) {
function sdssetlen (line 129) | static inline void sdssetlen(sds s, size_t newlen) {
function sdsinclen (line 153) | static inline void sdsinclen(sds s, size_t inc) {
function sdsalloc (line 179) | static inline size_t sdsalloc(const sds s) {
function sdssetalloc (line 196) | static inline void sdssetalloc(sds s, size_t newlen) {
FILE: src/server.c
type sharedObjectsStruct (line 57) | struct sharedObjectsStruct
type disqueServer (line 68) | struct disqueServer
type serverCommand (line 109) | struct serverCommand
function serverLogRaw (line 155) | void serverLogRaw(int level, const char *msg) {
function serverLog (line 197) | void serverLog(int level, const char *fmt, ...) {
function serverDebug (line 211) | void serverDebug(const char *fmt, ...) {
function serverLogFromHandler (line 240) | void serverLogFromHandler(int level, const char *msg) {
function ustime (line 263) | long long ustime(void) {
function mstime_t (line 274) | mstime_t mstime(void) {
function mstime_t (line 281) | mstime_t randomTimeError(mstime_t milliseconds) {
function exitFromChild (line 289) | void exitFromChild(int retcode) {
function dictVanillaFree (line 303) | void dictVanillaFree(void *privdata, void *val)
function dictListDestructor (line 309) | void dictListDestructor(void *privdata, void *val)
function dictSdsKeyCompare (line 315) | int dictSdsKeyCompare(void *privdata, const void *key1,
function dictSdsKeyCaseCompare (line 329) | int dictSdsKeyCaseCompare(void *privdata, const void *key1,
function dictObjectDestructor (line 337) | void dictObjectDestructor(void *privdata, void *val)
function dictSdsDestructor (line 345) | void dictSdsDestructor(void *privdata, void *val)
function dictObjKeyCompare (line 352) | int dictObjKeyCompare(void *privdata, const void *key1,
function dictObjHash (line 359) | unsigned int dictObjHash(const void *key) {
function dictSdsHash (line 364) | unsigned int dictSdsHash(const void *key) {
function dictSdsCaseHash (line 368) | unsigned int dictSdsCaseHash(const void *key) {
function dictEncObjKeyCompare (line 372) | int dictEncObjKeyCompare(void *privdata, const void *key1,
function dictEncObjHash (line 390) | unsigned int dictEncObjHash(const void *key) {
function dictClusterNodeHash (line 435) | unsigned int dictClusterNodeHash(const void *key) {
function dictClusterNodeKeyCompare (line 439) | int dictClusterNodeKeyCompare(void *privdata, const void *key1,
function dictJobHash (line 470) | unsigned int dictJobHash(const void *key) {
function dictJobKeyCompare (line 474) | int dictJobKeyCompare(void *privdata, const void *key1,
function htNeedsResize (line 500) | int htNeedsResize(dict *dict) {
function tryResizeHashTables (line 509) | void tryResizeHashTables(void) {
function incrementallyRehash (line 521) | int incrementallyRehash(void) {
function updateDictResizePolicy (line 539) | void updateDictResizePolicy(void) {
function flushServerData (line 548) | void flushServerData(void) {
function trackInstantaneousMetric (line 581) | void trackInstantaneousMetric(int metric, long long current_reading) {
function getInstantaneousMetric (line 598) | long long getInstantaneousMetric(int metric) {
function clientsCronHandleTimeout (line 611) | int clientsCronHandleTimeout(client *c, mstime_t now_ms) {
function clientsCronResizeQueryBuffer (line 641) | int clientsCronResizeQueryBuffer(client *c) {
function clientsCron (line 668) | void clientsCron(void) {
function databasesCron (line 707) | void databasesCron(void) {
function updateCachedTime (line 725) | void updateCachedTime(void) {
function serverCron (line 749) | int serverCron(struct aeEventLoop *eventLoop, long long id, void *client...
function beforeSleep (line 869) | void beforeSleep(struct aeEventLoop *eventLoop) {
function createSharedObjects (line 895) | void createSharedObjects(void) {
function initServerConfig (line 970) | void initServerConfig(void) {
function restartServer (line 1086) | int restartServer(int flags, mstime_t delay) {
function adjustOpenFilesLimit (line 1124) | void adjustOpenFilesLimit(void) {
function checkTcpBacklogSettings (line 1198) | void checkTcpBacklogSettings(void) {
function listenToPort (line 1231) | int listenToPort(int port, int *fds, int *count) {
function resetServerStats (line 1282) | void resetServerStats(void) {
type aeEventLoop (line 1303) | struct aeEventLoop
function initServer (line 1305) | void initServer(void) {
function populateCommandTable (line 1423) | void populateCommandTable(void) {
function resetCommandTableStats (line 1454) | void resetCommandTableStats(void) {
type serverCommand (line 1468) | struct serverCommand
type serverCommand (line 1472) | struct serverCommand
type serverCommand (line 1473) | struct serverCommand
type serverCommand (line 1488) | struct serverCommand
type serverCommand (line 1489) | struct serverCommand
function replicationFeedMonitors (line 1496) | void replicationFeedMonitors(client *c, list *monitors, robj **argv, int...
function call (line 1534) | void call(client *c, int flags) {
function processCommand (line 1574) | int processCommand(client *c) {
function closeListeningSockets (line 1647) | void closeListeningSockets(int unlink_unix_socket) {
function prepareForShutdown (line 1661) | int prepareForShutdown(int flags) {
function time_independent_strcmp (line 1715) | int time_independent_strcmp(char *a, char *b) {
function authCommand (line 1748) | void authCommand(client *c) {
function pingCommand (line 1762) | void pingCommand(client *c) {
function timeCommand (line 1776) | void timeCommand(client *c) {
function shutdownCommand (line 1787) | void shutdownCommand(client *c) {
function addReplyCommandFlag (line 1812) | int addReplyCommandFlag(client *c, struct serverCommand *cmd, int f, cha...
function addReplyCommand (line 1821) | void addReplyCommand(client *c, struct serverCommand *cmd) {
function commandCommand (line 1849) | void commandCommand(client *c) {
function bytesToHuman (line 1876) | void bytesToHuman(char *s, unsigned long long n) {
function sds (line 1907) | sds genDisqueInfoString(char *section) {
function infoCommand (line 2178) | void infoCommand(client *c) {
function monitorCommand (line 2188) | void monitorCommand(client *c) {
function freeMemoryIfNeeded (line 2216) | int freeMemoryIfNeeded(void) {
function getMemoryWarningLevel (line 2301) | int getMemoryWarningLevel(void) {
function linuxOvercommitMemoryValue (line 2314) | int linuxOvercommitMemoryValue(void) {
function linuxOvercommitMemoryWarning (line 2328) | void linuxOvercommitMemoryWarning(void) {
function createPidFile (line 2335) | void createPidFile(void) {
function daemonize (line 2344) | void daemonize(void) {
function version (line 2361) | void version(void) {
function usage (line 2372) | void usage(void) {
function disqueAsciiArt (line 2387) | void disqueAsciiArt(void) {
function sigShutdownHandler (line 2415) | static void sigShutdownHandler(int sig) {
function setupSignalHandlers (line 2444) | void setupSignalHandlers(void) {
function loadDataFromDisk (line 2470) | void loadDataFromDisk(void) {
function serverOutOfMemoryHandler (line 2490) | void serverOutOfMemoryHandler(size_t allocation_size) {
function serverSetProcTitle (line 2496) | void serverSetProcTitle(char *title) {
function main (line 2507) | int main(int argc, char **argv) {
FILE: src/server.h
type mstime_t (line 53) | typedef long long mstime_t;
type robj (line 277) | typedef struct disqueObject {
type job (line 296) | struct job
type blockingState (line 300) | typedef struct blockingState {
type client (line 319) | typedef struct client {
type sharedObjectsStruct (line 349) | struct sharedObjectsStruct {
type zskiplistNode (line 364) | typedef struct zskiplistNode {
type zskiplist (line 374) | typedef struct zskiplist {
type zset (line 380) | typedef struct zset {
type clientBufferLimitsConfig (line 385) | typedef struct clientBufferLimitsConfig {
type clusterState (line 397) | struct clusterState
type disqueServer (line 405) | struct disqueServer {
type serverCommand (line 560) | struct serverCommand
type serverCommand (line 562) | struct serverCommand {
type redisFunctionSym (line 578) | struct redisFunctionSym {
type listTypeIterator (line 584) | typedef struct {
type listTypeEntry (line 593) | typedef struct {
type setTypeIterator (line 600) | typedef struct {
type hashTypeIterator (line 611) | typedef struct {
type disqueServer (line 628) | struct disqueServer
type sharedObjectsStruct (line 629) | struct sharedObjectsStruct
type serverCommand (line 782) | struct serverCommand
type serverCommand (line 783) | struct serverCommand
type serverCommand (line 784) | struct serverCommand
type serverCommand (line 786) | struct serverCommand
type rewriteConfigState (line 819) | struct rewriteConfigState
type rewriteConfigState (line 820) | struct rewriteConfigState
FILE: src/setproctitle.c
function spt_min (line 70) | static inline size_t spt_min(size_t a, size_t b) {
function spt_clearenv (line 79) | static int spt_clearenv(void) {
function spt_copyenv (line 99) | static int spt_copyenv(char *oldenv[]) {
function spt_copyargs (line 130) | static int spt_copyargs(int argc, char *argv[]) {
function spt_init (line 148) | void spt_init(int argc, char *argv[]) {
function setproctitle (line 216) | void setproctitle(const char *fmt, ...) {
FILE: src/sha1.c
function SHA1Transform (line 56) | void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
function SHA1Init (line 117) | void SHA1Init(SHA1_CTX* context)
function SHA1Update (line 131) | void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)
function SHA1Final (line 155) | void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
function main (line 203) | int
FILE: src/sha1.h
type SHA1_CTX (line 8) | typedef struct {
FILE: src/skiplist.c
function skiplistNode (line 59) | skiplistNode *skiplistCreateNode(int level, void *obj) {
function skiplist (line 67) | skiplist *skiplistCreate(int (*compare)(const void *, const void *)) {
function skiplistFreeNode (line 86) | void skiplistFreeNode(skiplistNode *node) {
function skiplistFree (line 91) | void skiplistFree(skiplist *sl) {
function skiplistRandomLevel (line 107) | int skiplistRandomLevel(void) {
function skiplistNode (line 116) | skiplistNode *skiplistInsert(skiplist *sl, void *obj) {
function skiplistDeleteNode (line 175) | void skiplistDeleteNode(skiplist *sl, skiplistNode *x, skiplistNode **up...
function skiplistDelete (line 197) | int skiplistDelete(skiplist *sl, void *obj) {
function skiplistLength (line 264) | unsigned long skiplistLength(skiplist *sl) {
function compare (line 272) | int compare(const void *a, const void *b) {
function main (line 276) | int main(void) {
FILE: src/skiplist.h
type skiplistNode (line 38) | typedef struct skiplistNode {
type skiplist (line 47) | typedef struct skiplist {
FILE: src/slowlog.c
function slowlogEntry (line 48) | slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long durati...
function slowlogFreeEntry (line 91) | void slowlogFreeEntry(void *septr) {
function slowlogInit (line 103) | void slowlogInit(void) {
function slowlogPushEntryIfNeeded (line 112) | void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) {
function slowlogReset (line 123) | void slowlogReset(void) {
function slowlogCommand (line 130) | void slowlogCommand(client *c) {
FILE: src/slowlog.h
type slowlogEntry (line 34) | typedef struct slowlogEntry {
FILE: src/sparkline.c
type sequence (line 57) | struct sequence
type sequence (line 58) | struct sequence
function sparklineSequenceAddSample (line 65) | void sparklineSequenceAddSample(struct sequence *seq, double value, char...
function freeSparklineSequence (line 80) | void freeSparklineSequence(struct sequence *seq) {
function sds (line 96) | sds sparklineRenderRange(sds output, struct sequence *seq, int rows, int...
function sds (line 164) | sds sparklineRender(sds output, struct sequence *seq, int columns, int r...
FILE: src/sparkline.h
type sample (line 34) | struct sample {
type sequence (line 39) | struct sequence {
type sequence (line 50) | struct sequence
type sequence (line 51) | struct sequence
type sequence (line 52) | struct sequence
type sequence (line 53) | struct sequence
type sequence (line 54) | struct sequence
FILE: src/syncio.c
function syncWrite (line 49) | ssize_t syncWrite(int fd, char *ptr, ssize_t size, long long timeout) {
function syncRead (line 85) | ssize_t syncRead(int fd, char *ptr, ssize_t size, long long timeout) {
function syncReadLine (line 125) | ssize_t syncReadLine(int fd, char *ptr, ssize_t size, long long timeout) {
FILE: src/util.c
function stringmatchlen (line 46) | int stringmatchlen(const char *pattern, int patternLen,
function stringmatch (line 168) | int stringmatch(const char *pattern, const char *string, int nocase) {
function memtoll (line 178) | long long memtoll(const char *p, int *err) {
function digits10 (line 221) | uint32_t digits10(uint64_t v) {
function sdigits10 (line 242) | uint32_t sdigits10(int64_t v) {
function ll2string (line 264) | int ll2string(char* dst, size_t dstlen, long long svalue) {
function string2ll (line 321) | int string2ll(const char *s, size_t slen, long long *value) {
function string2l (line 387) | int string2l(const char *s, size_t slen, long *lval) {
function d2string (line 402) | int d2string(char *buf, size_t len, double value) {
function getRandomHexChars (line 443) | void getRandomHexChars(char *p, unsigned int len) {
function sds (line 523) | sds getAbsolutePath(char *filename) {
function pathIsBaseName (line 572) | int pathIsBaseName(char *path) {
function test_string2ll (line 579) | static void test_string2ll(void) {
function test_string2l (line 634) | static void test_string2l(void) {
function test_ll2string (line 683) | static void test_ll2string(void) {
function utilTest (line 725) | int utilTest(int argc, char **argv) {
FILE: src/zmalloc.c
function zlibc_free (line 38) | void zlibc_free(void *ptr) {
function zmalloc_default_oom (line 95) | static void zmalloc_default_oom(size_t size) {
function zmalloc_size (line 165) | size_t zmalloc_size(void *ptr) {
function zfree (line 175) | void zfree(void *ptr) {
function zmalloc_used_memory (line 201) | size_t zmalloc_used_memory(void) {
function zmalloc_enable_thread_safeness (line 212) | void zmalloc_enable_thread_safeness(void) {
function zmalloc_set_oom_handler (line 216) | void zmalloc_set_oom_handler(void (*oom_handler)(size_t)) {
function zmalloc_get_rss (line 232) | size_t zmalloc_get_rss(void) {
function zmalloc_get_rss (line 272) | size_t zmalloc_get_rss(void) {
function zmalloc_get_rss (line 284) | size_t zmalloc_get_rss(void) {
function zmalloc_get_fragmentation_ratio (line 295) | float zmalloc_get_fragmentation_ratio(size_t rss) {
function zmalloc_get_private_dirty (line 300) | size_t zmalloc_get_private_dirty(void) {
function zmalloc_get_private_dirty (line 319) | size_t zmalloc_get_private_dirty(void) {
Condensed preview — 327 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,859K chars).
[
{
"path": ".gitignore",
"chars": 298,
"preview": ".*.swp\n*.o\n*.log\ndump.rdb\ndisque-server\ndisque-check-aof\ndisque\ndoc-tools\nrelease\nmisc/*\nsrc/release.h\nappendonly.aof\nSH"
},
{
"path": ".travis.yml",
"chars": 158,
"preview": "language: c\nsudo: false\naddons:\n apt:\n packages:\n - tcl8.5\ncache:\n directories:\n - $HOME/.ccache\ninstall: m"
},
{
"path": "COPYING",
"chars": 1488,
"preview": "Copyright (c) 2006-2014, Salvatore Sanfilippo\nAll rights reserved.\n\nRedistribution and use in source and binary forms, w"
},
{
"path": "Makefile",
"chars": 151,
"preview": "# Top level makefile, the real shit is at src/Makefile\n\ndefault: all\n\n.DEFAULT:\n\tcd src && $(MAKE) $@\n\ninstall:\n\tcd src "
},
{
"path": "README.md",
"chars": 72191,
"preview": "[](https://travis-ci.org/antirez/disque)\n\nDisque, an in-memory,"
},
{
"path": "deps/Makefile",
"chars": 1794,
"preview": "# Redis dependency Makefile\n\nuname_S:= $(shell sh -c 'uname -s 2>/dev/null || echo not')\n\nCCCOLOR=\"\\033[34m\"\nLINKCOLOR=\""
},
{
"path": "deps/README.md",
"chars": 3517,
"preview": "This directory contains all Redis dependencies, except for the libc that\nshould be provided by the operating system.\n\n* "
},
{
"path": "deps/hiredis/.gitignore",
"chars": 66,
"preview": "/hiredis-test\n/examples/hiredis-example*\n/*.o\n/*.so\n/*.dylib\n/*.a\n"
},
{
"path": "deps/hiredis/.travis.yml",
"chars": 68,
"preview": "language: c\ncompiler:\n - gcc\n - clang\n\nscript: make && make check\n"
},
{
"path": "deps/hiredis/CHANGELOG.md",
"chars": 701,
"preview": "### 0.11.0\n\n* Increase the maximum multi-bulk reply depth to 7.\n\n* Increase the read buffer size from 2k to 16k.\n\n* Use "
},
{
"path": "deps/hiredis/COPYING",
"chars": 1588,
"preview": "Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>\nCopyright (c) 2010-2011, Pieter Noordhuis <pcno"
},
{
"path": "deps/hiredis/Makefile",
"chars": 5166,
"preview": "# Hiredis Makefile\n# Copyright (C) 2010-2011 Salvatore Sanfilippo <antirez at gmail dot com>\n# Copyright (C) 2010-2011 P"
},
{
"path": "deps/hiredis/README.md",
"chars": 17437,
"preview": "[](https://travis-ci.org/redis/hiredis)\n\n# HIREDIS\n\nHiredis is a"
},
{
"path": "deps/hiredis/adapters/ae.h",
"chars": 4219,
"preview": "/*\n * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>\n *\n * All rights reserved.\n *\n * Redistri"
},
{
"path": "deps/hiredis/adapters/libev.h",
"chars": 4587,
"preview": "/*\n * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>\n *\n * All rights reserved.\n *\n * Redistri"
},
{
"path": "deps/hiredis/adapters/libevent.h",
"chars": 3980,
"preview": "/*\n * Copyright (c) 2010-2011, Pieter Noordhuis <pcnoordhuis at gmail dot com>\n *\n * All rights reserved.\n *\n * Redistri"
},
{
"path": "deps/hiredis/adapters/libuv.h",
"chars": 2487,
"preview": "#ifndef __HIREDIS_LIBUV_H__\n#define __HIREDIS_LIBUV_H__\n#include <uv.h>\n#include \"../hiredis.h\"\n#include \"../async.h\"\n#i"
},
{
"path": "deps/hiredis/async.c",
"chars": 22288,
"preview": "/*\n * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>\n * Copyright (c) 2010-2011, Pieter Noordh"
},
{
"path": "deps/hiredis/async.h",
"chars": 5021,
"preview": "/*\n * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>\n * Copyright (c) 2010-2011, Pieter Noordh"
},
{
"path": "deps/hiredis/dict.c",
"chars": 10549,
"preview": "/* Hash table implementation.\n *\n * This file implements in memory hash tables with insert/del/replace/find/\n * get-rand"
},
{
"path": "deps/hiredis/dict.h",
"chars": 4691,
"preview": "/* Hash table implementation.\n *\n * This file implements in memory hash tables with insert/del/replace/find/\n * get-rand"
},
{
"path": "deps/hiredis/examples/example-ae.c",
"chars": 1583,
"preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n\n#include <hiredis.h>\n#include <async.h>\n"
},
{
"path": "deps/hiredis/examples/example-libev.c",
"chars": 1405,
"preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n\n#include <hiredis.h>\n#include <async.h>\n"
},
{
"path": "deps/hiredis/examples/example-libevent.c",
"chars": 1455,
"preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n\n#include <hiredis.h>\n#include <async.h>\n"
},
{
"path": "deps/hiredis/examples/example-libuv.c",
"chars": 1445,
"preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n\n#include <hiredis.h>\n#include <async.h>\n"
},
{
"path": "deps/hiredis/examples/example.c",
"chars": 2236,
"preview": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <hiredis.h>\n\nint main(int argc, char **argv) {\n "
},
{
"path": "deps/hiredis/fmacros.h",
"chars": 420,
"preview": "#ifndef __HIREDIS_FMACRO_H\n#define __HIREDIS_FMACRO_H\n\n#if !defined(_BSD_SOURCE)\n#define _BSD_SOURCE\n#define _DEFAULT_SO"
},
{
"path": "deps/hiredis/hiredis.c",
"chars": 38056,
"preview": "/*\n * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>\n * Copyright (c) 2010-2011, Pieter Noordh"
},
{
"path": "deps/hiredis/hiredis.h",
"chars": 9403,
"preview": "/*\n * Copyright (c) 2009-2011, Salvatore Sanfilippo <antirez at gmail dot com>\n * Copyright (c) 2010-2011, Pieter Noordh"
},
{
"path": "deps/hiredis/net.c",
"chars": 12238,
"preview": "/* Extracted from anet.c to work properly with Hiredis error reporting.\n *\n * Copyright (c) 2006-2011, Salvatore Sanfili"
},
{
"path": "deps/hiredis/net.h",
"chars": 2453,
"preview": "/* Extracted from anet.c to work properly with Hiredis error reporting.\n *\n * Copyright (c) 2006-2011, Salvatore Sanfili"
},
{
"path": "deps/hiredis/sds.c",
"chars": 39396,
"preview": "/* SDSLib 2.0 -- A C dynamic strings library\n *\n * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot c"
},
{
"path": "deps/hiredis/sds.h",
"chars": 8595,
"preview": "/* SDSLib 2.0 -- A C dynamic strings library\n *\n * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot c"
},
{
"path": "deps/hiredis/sdsalloc.h",
"chars": 2083,
"preview": "/* SDSLib 2.0 -- A C dynamic strings library\n *\n * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot c"
},
{
"path": "deps/hiredis/test.c",
"chars": 25570,
"preview": "#include \"fmacros.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <strings.h>\n#include <sys/time."
},
{
"path": "deps/hiredis/zmalloc.h",
"chars": 267,
"preview": "/* Drop in replacement for zmalloc.h in order to just use libc malloc without\n * any wrappering. */\n\n#ifndef ZMALLOC_H\n#"
},
{
"path": "deps/jemalloc/.autom4te.cfg",
"chars": 107,
"preview": "begin-language: \"Autoconf-without-aclocal-m4\"\nargs: --no-cache\nend-language: \"Autoconf-without-aclocal-m4\"\n"
},
{
"path": "deps/jemalloc/.gitattributes",
"chars": 19,
"preview": "* text=auto eol=lf\n"
},
{
"path": "deps/jemalloc/.gitignore",
"chars": 1527,
"preview": "/*.gcov.*\n\n/bin/jemalloc-config\n/bin/jemalloc.sh\n/bin/jeprof\n\n/config.stamp\n/config.log\n/config.status\n/configure\n\n/doc/"
},
{
"path": "deps/jemalloc/COPYING",
"chars": 1703,
"preview": "Unless otherwise specified, files in the jemalloc source distribution are\nsubject to the following license:\n------------"
},
{
"path": "deps/jemalloc/ChangeLog",
"chars": 37758,
"preview": "Following are change highlights associated with official releases. Important\nbug fixes are all mentioned, but some inte"
},
{
"path": "deps/jemalloc/INSTALL",
"chars": 15708,
"preview": "Building and installing a packaged release of jemalloc can be as simple as\ntyping the following while in the root direct"
},
{
"path": "deps/jemalloc/Makefile.in",
"chars": 16794,
"preview": "# Clear out all vpaths, then set just one (default vpath) for the main build\n# directory.\nvpath\nvpath % .\n\n# Clear the d"
},
{
"path": "deps/jemalloc/README",
"chars": 1084,
"preview": "jemalloc is a general purpose malloc(3) implementation that emphasizes\nfragmentation avoidance and scalable concurrency "
},
{
"path": "deps/jemalloc/VERSION",
"chars": 50,
"preview": "4.0.3-0-ge9192eacf8935e29fc62fddc2701f7942b1cc02c\n"
},
{
"path": "deps/jemalloc/autogen.sh",
"chars": 266,
"preview": "#!/bin/sh\n\nfor i in autoconf; do\n echo \"$i\"\n $i\n if [ $? -ne 0 ]; then\n\techo \"Error $? in $i\"\n\texit 1\n fi\ndo"
},
{
"path": "deps/jemalloc/bin/jemalloc-config.in",
"chars": 1497,
"preview": "#!/bin/sh\n\nusage() {\n\tcat <<EOF\nUsage:\n @BINDIR@/jemalloc-config <option>\nOptions:\n --help | -h : Print usage.\n --ve"
},
{
"path": "deps/jemalloc/bin/jemalloc.sh.in",
"chars": 151,
"preview": "#!/bin/sh\n\nprefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\n\n@LD_PRELOAD_VAR@=${libdir}/libjemalloc.@SOREV@\nexp"
},
{
"path": "deps/jemalloc/bin/jeprof.in",
"chars": 175311,
"preview": "#! /usr/bin/env perl\n\n# Copyright (c) 1998-2007, Google Inc.\n# All rights reserved.\n#\n# Redistribution and use in source"
},
{
"path": "deps/jemalloc/config.guess",
"chars": 42856,
"preview": "#! /bin/sh\n# Attempt to guess a canonical system name.\n# Copyright 1992-2014 Free Software Foundation, Inc.\n\ntimestamp"
},
{
"path": "deps/jemalloc/config.stamp.in",
"chars": 0,
"preview": ""
},
{
"path": "deps/jemalloc/config.sub",
"chars": 35766,
"preview": "#! /bin/sh\n# Configuration validation subroutine script.\n# Copyright 1992-2014 Free Software Foundation, Inc.\n\ntimesta"
},
{
"path": "deps/jemalloc/configure",
"chars": 268023,
"preview": "#! /bin/sh\n# Guess values for system-dependent variables and create Makefiles.\n# Generated by GNU Autoconf 2.69.\n#\n#\n# C"
},
{
"path": "deps/jemalloc/configure.ac",
"chars": 56418,
"preview": "dnl Process this file with autoconf to produce a configure script.\nAC_INIT([Makefile.in])\n\ndnl ========================="
},
{
"path": "deps/jemalloc/coverage.sh",
"chars": 321,
"preview": "#!/bin/sh\n\nset -e\n\nobjdir=$1\nsuffix=$2\nshift 2\nobjs=$@\n\ngcov -b -p -f -o \"${objdir}\" ${objs}\n\n# Move gcov outputs so tha"
},
{
"path": "deps/jemalloc/doc/html.xsl.in",
"chars": 203,
"preview": "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">\n <xsl:import href=\"@XSLROOT@/html/docbo"
},
{
"path": "deps/jemalloc/doc/jemalloc.3",
"chars": 67936,
"preview": "'\\\" t\n.\\\" Title: JEMALLOC\n.\\\" Author: Jason Evans\n.\\\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook."
},
{
"path": "deps/jemalloc/doc/jemalloc.html",
"chars": 131730,
"preview": "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"><title>JEMALLOC</title><meta name=\"g"
},
{
"path": "deps/jemalloc/doc/jemalloc.xml.in",
"chars": 124140,
"preview": "<?xml version='1.0' encoding='UTF-8'?>\n<?xml-stylesheet type=\"text/xsl\"\n href=\"http://docbook.sourceforge.net/rel"
},
{
"path": "deps/jemalloc/doc/manpages.xsl.in",
"chars": 207,
"preview": "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">\n <xsl:import href=\"@XSLROOT@/manpages/d"
},
{
"path": "deps/jemalloc/doc/stylesheet.xsl",
"chars": 303,
"preview": "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">\n <xsl:param name=\"funcsynopsis.style\">a"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/arena.h",
"chars": 42181,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#define\tLARGE_"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/atomic.h",
"chars": 15439,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#endif /* JEMA"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/base.h",
"chars": 855,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#endif /* JEMA"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/bitmap.h",
"chars": 6977,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n/* Maximum bit"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/chunk.h",
"chars": 3299,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n/*\n * Size and"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/chunk_dss.h",
"chars": 1246,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef enum {"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/chunk_mmap.h",
"chars": 773,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#endif /* JEMA"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/ckh.h",
"chars": 2694,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/ctl.h",
"chars": 3189,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/extent.h",
"chars": 5899,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/hash.h",
"chars": 7940,
"preview": "/*\n * The following hash function is based on MurmurHash3, placed into the public\n * domain by Austin Appleby. See http"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/huge.h",
"chars": 1498,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#endif /* JEMA"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/jemalloc_internal.h.in",
"chars": 29462,
"preview": "#ifndef JEMALLOC_INTERNAL_H\n#define\tJEMALLOC_INTERNAL_H\n\n#include \"jemalloc_internal_defs.h\"\n#include \"jemalloc/internal"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/jemalloc_internal_decls.h",
"chars": 1346,
"preview": "#ifndef JEMALLOC_INTERNAL_DECLS_H\n#define\tJEMALLOC_INTERNAL_DECLS_H\n\n#include <math.h>\n#ifdef _WIN32\n# include <windows"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in",
"chars": 7691,
"preview": "#ifndef JEMALLOC_INTERNAL_DEFS_H_\n#define\tJEMALLOC_INTERNAL_DEFS_H_\n/*\n * If JEMALLOC_PREFIX is defined via --with-jemal"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/jemalloc_internal_macros.h",
"chars": 1669,
"preview": "/*\n * JEMALLOC_ALWAYS_INLINE and JEMALLOC_INLINE are used within header files for\n * functions that are static inline fu"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/mb.h",
"chars": 2687,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#endif /* JEMA"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/mutex.h",
"chars": 2926,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/pages.h",
"chars": 940,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#endif /* JEMA"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/private_namespace.sh",
"chars": 93,
"preview": "#!/bin/sh\n\nfor symbol in `cat $1` ; do\n echo \"#define\t${symbol} JEMALLOC_N(${symbol})\"\ndone\n"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/private_symbols.txt",
"chars": 8761,
"preview": "a0dalloc\na0get\na0malloc\narena_aalloc\narena_alloc_junk_small\narena_bin_index\narena_bin_info\narena_bitselm_get\narena_boot\n"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/private_unnamespace.sh",
"chars": 70,
"preview": "#!/bin/sh\n\nfor symbol in `cat $1` ; do\n echo \"#undef ${symbol}\"\ndone\n"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/prng.h",
"chars": 2025,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n/*\n * Simple l"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/prof.h",
"chars": 15423,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/public_namespace.sh",
"chars": 129,
"preview": "#!/bin/sh\n\nfor nm in `cat $1` ; do\n n=`echo ${nm} |tr ':' ' ' |awk '{print $1}'`\n echo \"#define\tje_${n} JEMALLOC_N(${n"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/public_unnamespace.sh",
"chars": 111,
"preview": "#!/bin/sh\n\nfor nm in `cat $1` ; do\n n=`echo ${nm} |tr ':' ' ' |awk '{print $1}'`\n echo \"#undef je_${n}\"\ndone\n"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/ql.h",
"chars": 2369,
"preview": "/* List definitions. */\n#define\tql_head(a_type)\t\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\ta_type *qlh_first;\t\t\t\t\t\t\\\n}\n\n#define\tql_head_"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/qr.h",
"chars": 2259,
"preview": "/* Ring definitions. */\n#define\tqr(a_type)\t\t\t\t\t\t\t\\\nstruct {\t\t\t\t\t\t\t\t\\\n\ta_type\t*qre_next;\t\t\t\t\t\t\\\n\ta_type\t*qre_prev;\t\t\t\t\t\t\\"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/quarantine.h",
"chars": 1593,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/rb.h",
"chars": 37346,
"preview": "/*-\n *******************************************************************************\n *\n * cpp macro implementation of l"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/rtree.h",
"chars": 8660,
"preview": "/*\n * This radix tree implementation is tailored to the singular purpose of\n * associating metadata with chunks that are"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/size_classes.sh",
"chars": 7998,
"preview": "#!/bin/sh\n#\n# Usage: size_classes.sh <lg_qarr> <lg_tmin> <lg_parr> <lg_g>\n\n# The following limits are chosen such that t"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/stats.h",
"chars": 4641,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/tcache.h",
"chars": 11875,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\ntypedef struct"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/tsd.h",
"chars": 19147,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n/* Maximum num"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/util.h",
"chars": 7346,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#ifdef _WIN32\n"
},
{
"path": "deps/jemalloc/include/jemalloc/internal/valgrind.h",
"chars": 4243,
"preview": "/******************************************************************************/\n#ifdef JEMALLOC_H_TYPES\n\n#ifdef JEMALLO"
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc.sh",
"chars": 499,
"preview": "#!/bin/sh\n\nobjroot=$1\n\ncat <<EOF\n#ifndef JEMALLOC_H_\n#define\tJEMALLOC_H_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nEOF\n\nfo"
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc_defs.h.in",
"chars": 1022,
"preview": "/* Defined if __attribute__((...)) syntax is supported. */\n#undef JEMALLOC_HAVE_ATTR\n\n/* Defined if alloc_size attribute"
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc_macros.h.in",
"chars": 3363,
"preview": "#include <stdlib.h>\n#include <stdbool.h>\n#include <stdint.h>\n#include <limits.h>\n#include <strings.h>\n\n#define\tJEMALLOC_"
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc_mangle.sh",
"chars": 1258,
"preview": "#!/bin/sh\n\npublic_symbols_txt=$1\nsymbol_prefix=$2\n\ncat <<EOF\n/*\n * By default application code must explicitly refer to "
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc_protos.h.in",
"chars": 3284,
"preview": "/*\n * The @je_@ prefix on the following public symbol declarations is an artifact\n * of namespace management, and should"
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc_rename.sh",
"chars": 460,
"preview": "#!/bin/sh\n\npublic_symbols_txt=$1\n\ncat <<EOF\n/*\n * Name mangling for public symbols is controlled by --with-mangling and\n"
},
{
"path": "deps/jemalloc/include/jemalloc/jemalloc_typedefs.h.in",
"chars": 1575,
"preview": "/*\n * void *\n * chunk_alloc(void *new_addr, size_t size, size_t alignment, bool *zero,\n * bool *commit, unsigned are"
},
{
"path": "deps/jemalloc/include/msvc_compat/C99/stdbool.h",
"chars": 449,
"preview": "#ifndef stdbool_h\n#define stdbool_h\n\n#include <wtypes.h>\n\n/* MSVC doesn't define _Bool or bool in C, but does have BOOL "
},
{
"path": "deps/jemalloc/include/msvc_compat/C99/stdint.h",
"chars": 7728,
"preview": "// ISO C9x compliant stdint.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG"
},
{
"path": "deps/jemalloc/include/msvc_compat/strings.h",
"chars": 490,
"preview": "#ifndef strings_h\n#define strings_h\n\n/* MSVC doesn't define ffs/ffsl. This dummy strings.h header is provided\n * for bot"
},
{
"path": "deps/jemalloc/include/msvc_compat/windows_extra.h",
"chars": 529,
"preview": "#ifndef MSVC_COMPAT_WINDOWS_EXTRA_H\n#define\tMSVC_COMPAT_WINDOWS_EXTRA_H\n\n#ifndef ENOENT\n# define ENOENT ERROR_PATH_NOT_"
},
{
"path": "deps/jemalloc/install-sh",
"chars": 5585,
"preview": "#! /bin/sh\n#\n# install - install a program, script, or datafile\n# This comes from X11R5 (mit/util/scripts/install.sh).\n#"
},
{
"path": "deps/jemalloc/jemalloc.pc.in",
"chars": 397,
"preview": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\ninstall_suffix=@install_suffix@\n\nName:"
},
{
"path": "deps/jemalloc/src/arena.c",
"chars": 94826,
"preview": "#define\tJEMALLOC_ARENA_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*******************************************"
},
{
"path": "deps/jemalloc/src/atomic.c",
"chars": 76,
"preview": "#define\tJEMALLOC_ATOMIC_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n"
},
{
"path": "deps/jemalloc/src/base.c",
"chars": 3984,
"preview": "#define\tJEMALLOC_BASE_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/********************************************"
},
{
"path": "deps/jemalloc/src/bitmap.c",
"chars": 2275,
"preview": "#define\tJEMALLOC_BITMAP_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/******************************************"
},
{
"path": "deps/jemalloc/src/chunk.c",
"chars": 21568,
"preview": "#define\tJEMALLOC_CHUNK_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*******************************************"
},
{
"path": "deps/jemalloc/src/chunk_dss.c",
"chars": 4697,
"preview": "#define\tJEMALLOC_CHUNK_DSS_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n/****************************************"
},
{
"path": "deps/jemalloc/src/chunk_mmap.c",
"chars": 2008,
"preview": "#define\tJEMALLOC_CHUNK_MMAP_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/**************************************"
},
{
"path": "deps/jemalloc/src/ckh.c",
"chars": 14240,
"preview": "/*\n *******************************************************************************\n * Implementation of (2^1+,2) cuckoo"
},
{
"path": "deps/jemalloc/src/ctl.c",
"chars": 57313,
"preview": "#define\tJEMALLOC_CTL_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*********************************************"
},
{
"path": "deps/jemalloc/src/extent.c",
"chars": 1461,
"preview": "#define\tJEMALLOC_EXTENT_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/******************************************"
},
{
"path": "deps/jemalloc/src/hash.c",
"chars": 74,
"preview": "#define\tJEMALLOC_HASH_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n"
},
{
"path": "deps/jemalloc/src/huge.c",
"chars": 11184,
"preview": "#define\tJEMALLOC_HUGE_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/********************************************"
},
{
"path": "deps/jemalloc/src/jemalloc.c",
"chars": 63053,
"preview": "#define\tJEMALLOC_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*************************************************"
},
{
"path": "deps/jemalloc/src/mb.c",
"chars": 72,
"preview": "#define\tJEMALLOC_MB_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n"
},
{
"path": "deps/jemalloc/src/mutex.c",
"chars": 3429,
"preview": "#define\tJEMALLOC_MUTEX_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n#if defined(JEMALLOC_LAZY_LOCK) && !defined("
},
{
"path": "deps/jemalloc/src/pages.c",
"chars": 3729,
"preview": "#define\tJEMALLOC_PAGES_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*******************************************"
},
{
"path": "deps/jemalloc/src/prof.c",
"chars": 50392,
"preview": "#define\tJEMALLOC_PROF_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n/*********************************************"
},
{
"path": "deps/jemalloc/src/quarantine.c",
"chars": 5398,
"preview": "#define\tJEMALLOC_QUARANTINE_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*\n * Quarantine pointers close to NULL"
},
{
"path": "deps/jemalloc/src/rtree.c",
"chars": 3180,
"preview": "#define\tJEMALLOC_RTREE_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\nstatic unsigned\nhmin(unsigned ha, unsigned h"
},
{
"path": "deps/jemalloc/src/stats.c",
"chars": 20238,
"preview": "#define\tJEMALLOC_STATS_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n#define\tCTL_GET(n, v, t) do {\t\t\t\t\t\t\\\n\tsize_t"
},
{
"path": "deps/jemalloc/src/tcache.c",
"chars": 13427,
"preview": "#define\tJEMALLOC_TCACHE_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/******************************************"
},
{
"path": "deps/jemalloc/src/tsd.c",
"chars": 3841,
"preview": "#define\tJEMALLOC_TSD_C_\n#include \"jemalloc/internal/jemalloc_internal.h\"\n\n/*********************************************"
},
{
"path": "deps/jemalloc/src/util.c",
"chars": 13941,
"preview": "#define\tassert(e) do {\t\t\t\t\t\t\t\\\n\tif (config_debug && !(e)) {\t\t\t\t\t\\\n\t\tmalloc_write(\"<jemalloc>: Failed assertion\\n\");\t\t\\\n\t"
},
{
"path": "deps/jemalloc/src/valgrind.c",
"chars": 581,
"preview": "#include \"jemalloc/internal/jemalloc_internal.h\"\n#ifndef JEMALLOC_VALGRIND\n# error \"This source file is for Valgrind in"
},
{
"path": "deps/jemalloc/src/zone.c",
"chars": 7681,
"preview": "#include \"jemalloc/internal/jemalloc_internal.h\"\n#ifndef JEMALLOC_ZONE\n# error \"This source file is for zones on Darwin"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-alti.h",
"chars": 5921,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params.h",
"chars": 4286,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params11213.h",
"chars": 3566,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params1279.h",
"chars": 3552,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params132049.h",
"chars": 3564,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params19937.h",
"chars": 3560,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params216091.h",
"chars": 3566,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params2281.h",
"chars": 3552,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params4253.h",
"chars": 3552,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params44497.h",
"chars": 3566,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params607.h",
"chars": 3558,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-params86243.h",
"chars": 3564,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT-sse2.h",
"chars": 5215,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/SFMT.h",
"chars": 5805,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/include/test/btalloc.h",
"chars": 825,
"preview": "/* btalloc() provides a mechanism for allocating via permuted backtraces. */\nvoid\t*btalloc(size_t size, unsigned bits);\n"
},
{
"path": "deps/jemalloc/test/include/test/jemalloc_test.h.in",
"chars": 4268,
"preview": "#include <limits.h>\n#ifndef SIZE_T_MAX\n# define SIZE_T_MAX\tSIZE_MAX\n#endif\n#include <stdlib.h>\n#include <stdarg.h>\n#inc"
},
{
"path": "deps/jemalloc/test/include/test/jemalloc_test_defs.h.in",
"chars": 290,
"preview": "#include \"jemalloc/internal/jemalloc_internal_defs.h\"\n#include \"jemalloc/internal/jemalloc_internal_decls.h\"\n\n/*\n * For "
},
{
"path": "deps/jemalloc/test/include/test/math.h",
"chars": 8172,
"preview": "#ifndef JEMALLOC_ENABLE_INLINE\ndouble\tln_gamma(double x);\ndouble\ti_gamma(double x, double p, double ln_gamma_p);\ndouble\t"
},
{
"path": "deps/jemalloc/test/include/test/mq.h",
"chars": 2902,
"preview": "void\tmq_nanosleep(unsigned ns);\n\n/*\n * Simple templated message queue implementation that relies on only mutexes for\n * "
},
{
"path": "deps/jemalloc/test/include/test/mtx.h",
"chars": 520,
"preview": "/*\n * mtx is a slightly simplified version of malloc_mutex. This code duplication\n * is unfortunate, but there are allo"
},
{
"path": "deps/jemalloc/test/include/test/test.h",
"chars": 13175,
"preview": "#define\tASSERT_BUFSIZE\t256\n\n#define\tassert_cmp(t, a, b, cmp, neg_cmp, pri, ...) do {\t\t\\\n\tt a_ = (a);\t\t\t\t\t\t\t\\\n\tt b_ = (b)"
},
{
"path": "deps/jemalloc/test/include/test/thd.h",
"chars": 224,
"preview": "/* Abstraction layer for threading in tests. */\n#ifdef _WIN32\ntypedef HANDLE thd_t;\n#else\ntypedef pthread_t thd_t;\n#endi"
},
{
"path": "deps/jemalloc/test/include/test/timer.h",
"chars": 615,
"preview": "/* Simple timer, for use in benchmark reporting. */\n\n#include <unistd.h>\n#include <sys/time.h>\n\n#define JEMALLOC_CLOCK_G"
},
{
"path": "deps/jemalloc/test/integration/MALLOCX_ARENA.c",
"chars": 1433,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tNTHREADS 10\n\nstatic bool have_dss =\n#ifdef JEMALLOC_DSS\n true\n#else\n fals"
},
{
"path": "deps/jemalloc/test/integration/aligned_alloc.c",
"chars": 2760,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tCHUNK 0x400000\n/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */\n#define"
},
{
"path": "deps/jemalloc/test/integration/allocated.c",
"chars": 2989,
"preview": "#include \"test/jemalloc_test.h\"\n\nstatic const bool config_stats =\n#ifdef JEMALLOC_STATS\n true\n#else\n false\n#endif\n"
},
{
"path": "deps/jemalloc/test/integration/chunk.c",
"chars": 8673,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifdef JEMALLOC_FILL\nconst char *malloc_conf = \"junk:false\";\n#endif\n\nstatic chunk_hooks"
},
{
"path": "deps/jemalloc/test/integration/mallocx.c",
"chars": 4116,
"preview": "#include \"test/jemalloc_test.h\"\n\nstatic unsigned\nget_nsizes_impl(const char *cmd)\n{\n\tunsigned ret;\n\tsize_t z;\n\n\tz = size"
},
{
"path": "deps/jemalloc/test/integration/overflow.c",
"chars": 1357,
"preview": "#include \"test/jemalloc_test.h\"\n\nTEST_BEGIN(test_overflow)\n{\n\tunsigned nhchunks;\n\tsize_t mib[4];\n\tsize_t sz, miblen, max"
},
{
"path": "deps/jemalloc/test/integration/posix_memalign.c",
"chars": 2603,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tCHUNK 0x400000\n/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */\n#define"
},
{
"path": "deps/jemalloc/test/integration/rallocx.c",
"chars": 4390,
"preview": "#include \"test/jemalloc_test.h\"\n\nTEST_BEGIN(test_grow_and_shrink)\n{\n\tvoid *p, *q;\n\tsize_t tsz;\n#define\tNCYCLES 3\n\tunsign"
},
{
"path": "deps/jemalloc/test/integration/sdallocx.c",
"chars": 1025,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tMAXALIGN (((size_t)1) << 25)\n#define\tNITER 4\n\nTEST_BEGIN(test_basic)\n{\n\tvoid *p"
},
{
"path": "deps/jemalloc/test/integration/thread_arena.c",
"chars": 1542,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tNTHREADS 10\n\nvoid *\nthd_start(void *arg)\n{\n\tunsigned main_arena_ind = *(unsigne"
},
{
"path": "deps/jemalloc/test/integration/thread_tcache_enabled.c",
"chars": 2535,
"preview": "#include \"test/jemalloc_test.h\"\n\nstatic const bool config_tcache =\n#ifdef JEMALLOC_TCACHE\n true\n#else\n false\n#endi"
},
{
"path": "deps/jemalloc/test/integration/xallocx.c",
"chars": 11797,
"preview": "#include \"test/jemalloc_test.h\"\n\nTEST_BEGIN(test_same_size)\n{\n\tvoid *p;\n\tsize_t sz, tsz;\n\n\tp = mallocx(42, 0);\n\tassert_p"
},
{
"path": "deps/jemalloc/test/src/SFMT.c",
"chars": 20695,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/src/btalloc.c",
"chars": 114,
"preview": "#include \"test/jemalloc_test.h\"\n\nvoid *\nbtalloc(size_t size, unsigned bits)\n{\n\n\treturn (btalloc_0(size, bits));\n}\n"
},
{
"path": "deps/jemalloc/test/src/btalloc_0.c",
"chars": 50,
"preview": "#include \"test/jemalloc_test.h\"\n\nbtalloc_n_gen(0)\n"
},
{
"path": "deps/jemalloc/test/src/btalloc_1.c",
"chars": 50,
"preview": "#include \"test/jemalloc_test.h\"\n\nbtalloc_n_gen(1)\n"
},
{
"path": "deps/jemalloc/test/src/math.c",
"chars": 48,
"preview": "#define\tMATH_C_\n#include \"test/jemalloc_test.h\"\n"
},
{
"path": "deps/jemalloc/test/src/mq.c",
"chars": 459,
"preview": "#include \"test/jemalloc_test.h\"\n\n/*\n * Sleep for approximately ns nanoseconds. No lower *nor* upper bound on sleep\n * t"
},
{
"path": "deps/jemalloc/test/src/mtx.c",
"chars": 1104,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifndef _CRT_SPINCOUNT\n#define\t_CRT_SPINCOUNT 4000\n#endif\n\nbool\nmtx_init(mtx_t *mtx)\n{\n"
},
{
"path": "deps/jemalloc/test/src/test.c",
"chars": 2310,
"preview": "#include \"test/jemalloc_test.h\"\n\nstatic unsigned\t\ttest_count = 0;\nstatic test_status_t\ttest_counts[test_status_count] = "
},
{
"path": "deps/jemalloc/test/src/thd.c",
"chars": 752,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifdef _WIN32\nvoid\nthd_create(thd_t *thd, void *(*proc)(void *), void *arg)\n{\n\tLPTHREAD"
},
{
"path": "deps/jemalloc/test/src/timer.c",
"chars": 1814,
"preview": "#include \"test/jemalloc_test.h\"\n\nvoid\ntimer_start(timedelta_t *timer)\n{\n\n#ifdef _WIN32\n\tGetSystemTimeAsFileTime(&timer->"
},
{
"path": "deps/jemalloc/test/stress/microbench.c",
"chars": 3169,
"preview": "#include \"test/jemalloc_test.h\"\n\nJEMALLOC_INLINE_C void\ntime_func(timedelta_t *timer, uint64_t nwarmup, uint64_t niter, "
},
{
"path": "deps/jemalloc/test/test.sh.in",
"chars": 1006,
"preview": "#!/bin/sh\n\ncase @abi@ in\n macho)\n export DYLD_FALLBACK_LIBRARY_PATH=\"@objroot@lib\"\n ;;\n pecoff)\n export PATH="
},
{
"path": "deps/jemalloc/test/unit/SFMT.c",
"chars": 87611,
"preview": "/*\n * This file derives from SFMT 1.3.3\n * (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html), which was\n"
},
{
"path": "deps/jemalloc/test/unit/atomic.c",
"chars": 2991,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tTEST_STRUCT(p, t)\t\t\t\t\t\t\\\nstruct p##_test_s {\t\t\t\t\t\t\t\\\n\tt\taccum0;\t\t\t\t\t\t\t\\\n\tt\tx;\t\t"
},
{
"path": "deps/jemalloc/test/unit/bitmap.c",
"chars": 3587,
"preview": "#include \"test/jemalloc_test.h\"\n\nTEST_BEGIN(test_bitmap_size)\n{\n\tsize_t i, prev_size;\n\n\tprev_size = 0;\n\tfor (i = 1; i <="
},
{
"path": "deps/jemalloc/test/unit/ckh.c",
"chars": 5467,
"preview": "#include \"test/jemalloc_test.h\"\n\nTEST_BEGIN(test_new_delete)\n{\n\ttsd_t *tsd;\n\tckh_t ckh;\n\n\ttsd = tsd_fetch();\n\n\tassert_fa"
},
{
"path": "deps/jemalloc/test/unit/hash.c",
"chars": 4746,
"preview": "/*\n * This file is based on code that is part of SMHasher\n * (https://code.google.com/p/smhasher/), and is subject to th"
},
{
"path": "deps/jemalloc/test/unit/junk.c",
"chars": 6244,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifdef JEMALLOC_FILL\n# ifndef JEMALLOC_TEST_JUNK_OPT\n# define JEMALLOC_TEST_JUNK_OP"
},
{
"path": "deps/jemalloc/test/unit/junk_alloc.c",
"chars": 92,
"preview": "#define JEMALLOC_TEST_JUNK_OPT \"junk:alloc\"\n#include \"junk.c\"\n#undef JEMALLOC_TEST_JUNK_OPT\n"
},
{
"path": "deps/jemalloc/test/unit/junk_free.c",
"chars": 91,
"preview": "#define JEMALLOC_TEST_JUNK_OPT \"junk:free\"\n#include \"junk.c\"\n#undef JEMALLOC_TEST_JUNK_OPT\n"
},
{
"path": "deps/jemalloc/test/unit/lg_chunk.c",
"chars": 512,
"preview": "#include \"test/jemalloc_test.h\"\n\n/*\n * Make sure that opt.lg_chunk clamping is sufficient. In practice, this test\n * pr"
},
{
"path": "deps/jemalloc/test/unit/mallctl.c",
"chars": 19064,
"preview": "#include \"test/jemalloc_test.h\"\n\nTEST_BEGIN(test_mallctl_errors)\n{\n\tuint64_t epoch;\n\tsize_t sz;\n\n\tassert_d_eq(mallctl(\"n"
},
{
"path": "deps/jemalloc/test/unit/math.c",
"chars": 18448,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tMAX_REL_ERR 1.0e-9\n#define\tMAX_ABS_ERR 1.0e-9\n\n#include <float.h>\n\n#ifndef INFI"
},
{
"path": "deps/jemalloc/test/unit/mq.c",
"chars": 1798,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tNSENDERS\t3\n#define\tNMSGS\t\t100000\n\ntypedef struct mq_msg_s mq_msg_t;\nstruct mq_m"
},
{
"path": "deps/jemalloc/test/unit/mtx.c",
"chars": 1003,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tNTHREADS\t2\n#define\tNINCRS\t\t2000000\n\nTEST_BEGIN(test_mtx_basic)\n{\n\tmtx_t mtx;\n\n\t"
},
{
"path": "deps/jemalloc/test/unit/prof_accum.c",
"chars": 1903,
"preview": "#include \"test/jemalloc_test.h\"\n\n#define\tNTHREADS\t\t4\n#define\tNALLOCS_PER_THREAD\t50\n#define\tDUMP_INTERVAL\t\t1\n#define\tBT_C"
},
{
"path": "deps/jemalloc/test/unit/prof_active.c",
"chars": 3677,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifdef JEMALLOC_PROF\nconst char *malloc_conf =\n \"prof:true,prof_thread_active_init:f"
},
{
"path": "deps/jemalloc/test/unit/prof_gdump.c",
"chars": 1965,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifdef JEMALLOC_PROF\nconst char *malloc_conf = \"prof:true,prof_active:false,prof_gdump:"
},
{
"path": "deps/jemalloc/test/unit/prof_idump.c",
"chars": 969,
"preview": "#include \"test/jemalloc_test.h\"\n\n#ifdef JEMALLOC_PROF\nconst char *malloc_conf =\n \"prof:true,prof_accum:true,prof_acti"
}
]
// ... and 127 more files (download for full content)
About this extraction
This page contains the full source code of the antirez/disque GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 327 files (3.5 MB), approximately 925.9k tokens, and a symbol index with 2281 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.