redis-server 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +38 -0
- data/README.md +33 -0
- data/bin/redis +114 -0
- data/redis/Makefile +5 -0
- data/redis/extconf.rb +3 -0
- data/redis/redis-2.2.11/00-RELEASENOTES +199 -0
- data/redis/redis-2.2.11/BUGS +1 -0
- data/redis/redis-2.2.11/CONTRIBUTING +13 -0
- data/redis/redis-2.2.11/COPYING +10 -0
- data/redis/redis-2.2.11/Changelog +1032 -0
- data/redis/redis-2.2.11/INSTALL +30 -0
- data/redis/redis-2.2.11/Makefile +22 -0
- data/redis/redis-2.2.11/README +83 -0
- data/redis/redis-2.2.11/TODO +4 -0
- data/redis/redis-2.2.11/client-libraries/README +11 -0
- data/redis/redis-2.2.11/deps/hiredis/COPYING +10 -0
- data/redis/redis-2.2.11/deps/hiredis/Makefile +115 -0
- data/redis/redis-2.2.11/deps/hiredis/README.md +311 -0
- data/redis/redis-2.2.11/deps/hiredis/TODO +2 -0
- data/redis/redis-2.2.11/deps/hiredis/adapters/ae.h +95 -0
- data/redis/redis-2.2.11/deps/hiredis/adapters/libev.h +113 -0
- data/redis/redis-2.2.11/deps/hiredis/adapters/libevent.h +76 -0
- data/redis/redis-2.2.11/deps/hiredis/async.c +321 -0
- data/redis/redis-2.2.11/deps/hiredis/async.h +112 -0
- data/redis/redis-2.2.11/deps/hiredis/example-ae.c +53 -0
- data/redis/redis-2.2.11/deps/hiredis/example-libev.c +47 -0
- data/redis/redis-2.2.11/deps/hiredis/example-libevent.c +48 -0
- data/redis/redis-2.2.11/deps/hiredis/example.c +67 -0
- data/redis/redis-2.2.11/deps/hiredis/fmacros.h +15 -0
- data/redis/redis-2.2.11/deps/hiredis/hiredis.c +1058 -0
- data/redis/redis-2.2.11/deps/hiredis/hiredis.h +170 -0
- data/redis/redis-2.2.11/deps/hiredis/net.c +170 -0
- data/redis/redis-2.2.11/deps/hiredis/net.h +43 -0
- data/redis/redis-2.2.11/deps/hiredis/sds.c +479 -0
- data/redis/redis-2.2.11/deps/hiredis/sds.h +77 -0
- data/redis/redis-2.2.11/deps/hiredis/test.c +479 -0
- data/redis/redis-2.2.11/deps/hiredis/util.h +40 -0
- data/redis/redis-2.2.11/deps/linenoise/Makefile +10 -0
- data/redis/redis-2.2.11/deps/linenoise/README.markdown +45 -0
- data/redis/redis-2.2.11/deps/linenoise/example.c +27 -0
- data/redis/redis-2.2.11/deps/linenoise/linenoise.c +609 -0
- data/redis/redis-2.2.11/deps/linenoise/linenoise.h +55 -0
- data/redis/redis-2.2.11/design-documents/REDIS-CLUSTER +214 -0
- data/redis/redis-2.2.11/design-documents/REDIS-CLUSTER-2 +343 -0
- data/redis/redis-2.2.11/doc/AppendCommand.html +48 -0
- data/redis/redis-2.2.11/doc/AppendOnlyFileHowto.html +41 -0
- data/redis/redis-2.2.11/doc/AuthCommand.html +39 -0
- data/redis/redis-2.2.11/doc/Benchmarks.html +129 -0
- data/redis/redis-2.2.11/doc/BgrewriteaofCommand.html +41 -0
- data/redis/redis-2.2.11/doc/BgsaveCommand.html +39 -0
- data/redis/redis-2.2.11/doc/BlpopCommand.html +51 -0
- data/redis/redis-2.2.11/doc/BrpoplpushCommand.html +39 -0
- data/redis/redis-2.2.11/doc/CommandReference.html +47 -0
- data/redis/redis-2.2.11/doc/Comparisons.html +42 -0
- data/redis/redis-2.2.11/doc/ConfigCommand.html +76 -0
- data/redis/redis-2.2.11/doc/Configuration.html +38 -0
- data/redis/redis-2.2.11/doc/ConnectionHandlingSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/ControlCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Credits.html +38 -0
- data/redis/redis-2.2.11/doc/DbsizeCommand.html +38 -0
- data/redis/redis-2.2.11/doc/DelCommand.html +41 -0
- data/redis/redis-2.2.11/doc/DesignPatterns.html +37 -0
- data/redis/redis-2.2.11/doc/EventLibray.html +44 -0
- data/redis/redis-2.2.11/doc/ExistsCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ExpireCommand.html +96 -0
- data/redis/redis-2.2.11/doc/FAQ.html +70 -0
- data/redis/redis-2.2.11/doc/Features.html +38 -0
- data/redis/redis-2.2.11/doc/FlushallCommand.html +39 -0
- data/redis/redis-2.2.11/doc/FlushdbCommand.html +39 -0
- data/redis/redis-2.2.11/doc/FromSqlToDataStructures.html +37 -0
- data/redis/redis-2.2.11/doc/GenericCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/GetCommand.html +39 -0
- data/redis/redis-2.2.11/doc/GetbitCommand.html +39 -0
- data/redis/redis-2.2.11/doc/GetsetCommand.html +38 -0
- data/redis/redis-2.2.11/doc/HackingStrings.html +83 -0
- data/redis/redis-2.2.11/doc/HashCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Hashes.html +37 -0
- data/redis/redis-2.2.11/doc/HdelCommand.html +39 -0
- data/redis/redis-2.2.11/doc/HexistsCommand.html +39 -0
- data/redis/redis-2.2.11/doc/HgetCommand.html +39 -0
- data/redis/redis-2.2.11/doc/HgetallCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HincrbyCommand.html +45 -0
- data/redis/redis-2.2.11/doc/HlenCommand.html +38 -0
- data/redis/redis-2.2.11/doc/HmgetCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HmsetCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HsetCommand.html +40 -0
- data/redis/redis-2.2.11/doc/HsetnxCommand.html +41 -0
- data/redis/redis-2.2.11/doc/IncrCommand.html +43 -0
- data/redis/redis-2.2.11/doc/InfoCommand.html +48 -0
- data/redis/redis-2.2.11/doc/IntroductionToRedisDataTypes.html +152 -0
- data/redis/redis-2.2.11/doc/KeysCommand.html +43 -0
- data/redis/redis-2.2.11/doc/LastsaveCommand.html +39 -0
- data/redis/redis-2.2.11/doc/LindexCommand.html +40 -0
- data/redis/redis-2.2.11/doc/ListCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Lists.html +42 -0
- data/redis/redis-2.2.11/doc/LlenCommand.html +41 -0
- data/redis/redis-2.2.11/doc/LpopCommand.html +41 -0
- data/redis/redis-2.2.11/doc/LrangeCommand.html +47 -0
- data/redis/redis-2.2.11/doc/LremCommand.html +41 -0
- data/redis/redis-2.2.11/doc/LsetCommand.html +38 -0
- data/redis/redis-2.2.11/doc/LtrimCommand.html +47 -0
- data/redis/redis-2.2.11/doc/MgetCommand.html +52 -0
- data/redis/redis-2.2.11/doc/MonitorCommand.html +63 -0
- data/redis/redis-2.2.11/doc/MoveCommand.html +42 -0
- data/redis/redis-2.2.11/doc/MsetCommand.html +44 -0
- data/redis/redis-2.2.11/doc/MultiExecCommand.html +166 -0
- data/redis/redis-2.2.11/doc/NonexistentCommands.html +51 -0
- data/redis/redis-2.2.11/doc/ObjectHashMappers.html +39 -0
- data/redis/redis-2.2.11/doc/Pipelining.html +36 -0
- data/redis/redis-2.2.11/doc/ProgrammingExamples.html +38 -0
- data/redis/redis-2.2.11/doc/ProtocolSpecification.html +137 -0
- data/redis/redis-2.2.11/doc/PublishSubscribe.html +115 -0
- data/redis/redis-2.2.11/doc/QuickStart.html +68 -0
- data/redis/redis-2.2.11/doc/QuitCommand.html +38 -0
- data/redis/redis-2.2.11/doc/README.html +119 -0
- data/redis/redis-2.2.11/doc/RandomkeyCommand.html +39 -0
- data/redis/redis-2.2.11/doc/Redis0100ChangeLog.html +67 -0
- data/redis/redis-2.2.11/doc/Redis0900ChangeLog.html +56 -0
- data/redis/redis-2.2.11/doc/RedisBigData.html +61 -0
- data/redis/redis-2.2.11/doc/RedisCLI.html +37 -0
- data/redis/redis-2.2.11/doc/RedisEventLibrary.html +70 -0
- data/redis/redis-2.2.11/doc/RedisGuides.html +37 -0
- data/redis/redis-2.2.11/doc/RedisInternals.html +38 -0
- data/redis/redis-2.2.11/doc/RedisPipelining.html +93 -0
- data/redis/redis-2.2.11/doc/RedisStatus.html +56 -0
- data/redis/redis-2.2.11/doc/Redis_1_2_0_Changelog.html +40 -0
- data/redis/redis-2.2.11/doc/Redis_2_0_0_Changelog.html +62 -0
- data/redis/redis-2.2.11/doc/Redis_2_0_Whats_new.html +59 -0
- data/redis/redis-2.2.11/doc/RenameCommand.html +39 -0
- data/redis/redis-2.2.11/doc/RenamenxCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ReplicationHowto.html +43 -0
- data/redis/redis-2.2.11/doc/ReplyTypes.html +42 -0
- data/redis/redis-2.2.11/doc/RoadMap.html +38 -0
- data/redis/redis-2.2.11/doc/RpoplpushCommand.html +44 -0
- data/redis/redis-2.2.11/doc/RpushCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SaddCommand.html +41 -0
- data/redis/redis-2.2.11/doc/SaveCommand.html +39 -0
- data/redis/redis-2.2.11/doc/ScardCommand.html +41 -0
- data/redis/redis-2.2.11/doc/SdiffCommand.html +45 -0
- data/redis/redis-2.2.11/doc/SdiffstoreCommand.html +38 -0
- data/redis/redis-2.2.11/doc/SelectCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SetCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SetCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/SetbitCommand.html +45 -0
- data/redis/redis-2.2.11/doc/SetexCommand.html +42 -0
- data/redis/redis-2.2.11/doc/SetnxCommand.html +51 -0
- data/redis/redis-2.2.11/doc/SetrangeCommand.html +58 -0
- data/redis/redis-2.2.11/doc/Sets.html +36 -0
- data/redis/redis-2.2.11/doc/ShutdownCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SideBar.html +36 -0
- data/redis/redis-2.2.11/doc/SinterCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SinterstoreCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SismemberCommand.html +42 -0
- data/redis/redis-2.2.11/doc/SlaveofCommand.html +41 -0
- data/redis/redis-2.2.11/doc/SmembersCommand.html +38 -0
- data/redis/redis-2.2.11/doc/SmoveCommand.html +44 -0
- data/redis/redis-2.2.11/doc/SortCommand.html +75 -0
- data/redis/redis-2.2.11/doc/SortedSetCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/SortedSets.html +36 -0
- data/redis/redis-2.2.11/doc/Speed.html +38 -0
- data/redis/redis-2.2.11/doc/SponsorshipHistory.html +38 -0
- data/redis/redis-2.2.11/doc/SpopCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SrandmemberCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SremCommand.html +42 -0
- data/redis/redis-2.2.11/doc/StringCommandsSidebar.html +36 -0
- data/redis/redis-2.2.11/doc/Strings.html +37 -0
- data/redis/redis-2.2.11/doc/StrlenCommand.html +39 -0
- data/redis/redis-2.2.11/doc/SubstrCommand.html +52 -0
- data/redis/redis-2.2.11/doc/SunionCommand.html +40 -0
- data/redis/redis-2.2.11/doc/SunionstoreCommand.html +38 -0
- data/redis/redis-2.2.11/doc/SupportedLanguages.html +60 -0
- data/redis/redis-2.2.11/doc/SupportedPlatforms.html +37 -0
- data/redis/redis-2.2.11/doc/TemplateCommand.html +38 -0
- data/redis/redis-2.2.11/doc/TtlCommand.html +38 -0
- data/redis/redis-2.2.11/doc/TwitterAlikeExample.html +250 -0
- data/redis/redis-2.2.11/doc/TypeCommand.html +46 -0
- data/redis/redis-2.2.11/doc/UnstableSource.html +39 -0
- data/redis/redis-2.2.11/doc/VirtualMemorySpecification.html +156 -0
- data/redis/redis-2.2.11/doc/VirtualMemoryUserGuide.html +66 -0
- data/redis/redis-2.2.11/doc/ZaddCommand.html +43 -0
- data/redis/redis-2.2.11/doc/ZcardCommand.html +41 -0
- data/redis/redis-2.2.11/doc/ZincrbyCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZrangeCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZrangebyscoreCommand.html +77 -0
- data/redis/redis-2.2.11/doc/ZrankCommand.html +43 -0
- data/redis/redis-2.2.11/doc/ZremCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZremrangebyrankCommand.html +39 -0
- data/redis/redis-2.2.11/doc/ZremrangebyscoreCommand.html +39 -0
- data/redis/redis-2.2.11/doc/ZscoreCommand.html +41 -0
- data/redis/redis-2.2.11/doc/ZunionCommand.html +42 -0
- data/redis/redis-2.2.11/doc/ZunionstoreCommand.html +43 -0
- data/redis/redis-2.2.11/doc/index.html +43 -0
- data/redis/redis-2.2.11/doc/redis.png +0 -0
- data/redis/redis-2.2.11/doc/style.css +25 -0
- data/redis/redis-2.2.11/redis.conf +417 -0
- data/redis/redis-2.2.11/src/Makefile +177 -0
- data/redis/redis-2.2.11/src/adlist.c +325 -0
- data/redis/redis-2.2.11/src/adlist.h +92 -0
- data/redis/redis-2.2.11/src/ae.c +390 -0
- data/redis/redis-2.2.11/src/ae.h +117 -0
- data/redis/redis-2.2.11/src/ae_epoll.c +91 -0
- data/redis/redis-2.2.11/src/ae_kqueue.c +93 -0
- data/redis/redis-2.2.11/src/ae_select.c +72 -0
- data/redis/redis-2.2.11/src/anet.c +347 -0
- data/redis/redis-2.2.11/src/anet.h +57 -0
- data/redis/redis-2.2.11/src/aof.c +675 -0
- data/redis/redis-2.2.11/src/config.c +627 -0
- data/redis/redis-2.2.11/src/config.h +64 -0
- data/redis/redis-2.2.11/src/db.c +543 -0
- data/redis/redis-2.2.11/src/debug.c +314 -0
- data/redis/redis-2.2.11/src/dict.c +721 -0
- data/redis/redis-2.2.11/src/dict.h +156 -0
- data/redis/redis-2.2.11/src/fmacros.h +15 -0
- data/redis/redis-2.2.11/src/help.h +638 -0
- data/redis/redis-2.2.11/src/intset.c +422 -0
- data/redis/redis-2.2.11/src/intset.h +19 -0
- data/redis/redis-2.2.11/src/lzf.h +100 -0
- data/redis/redis-2.2.11/src/lzfP.h +159 -0
- data/redis/redis-2.2.11/src/lzf_c.c +295 -0
- data/redis/redis-2.2.11/src/lzf_d.c +150 -0
- data/redis/redis-2.2.11/src/mkreleasehdr.sh +9 -0
- data/redis/redis-2.2.11/src/multi.c +268 -0
- data/redis/redis-2.2.11/src/networking.c +899 -0
- data/redis/redis-2.2.11/src/object.c +484 -0
- data/redis/redis-2.2.11/src/pqsort.c +197 -0
- data/redis/redis-2.2.11/src/pqsort.h +15 -0
- data/redis/redis-2.2.11/src/pubsub.c +267 -0
- data/redis/redis-2.2.11/src/rdb.c +1020 -0
- data/redis/redis-2.2.11/src/redis-benchmark.c +530 -0
- data/redis/redis-2.2.11/src/redis-check-aof.c +185 -0
- data/redis/redis-2.2.11/src/redis-check-dump.c +681 -0
- data/redis/redis-2.2.11/src/redis-cli.c +773 -0
- data/redis/redis-2.2.11/src/redis.c +1677 -0
- data/redis/redis-2.2.11/src/redis.h +1022 -0
- data/redis/redis-2.2.11/src/release.c +13 -0
- data/redis/redis-2.2.11/src/replication.c +557 -0
- data/redis/redis-2.2.11/src/sds.c +639 -0
- data/redis/redis-2.2.11/src/sds.h +78 -0
- data/redis/redis-2.2.11/src/sha1.c +276 -0
- data/redis/redis-2.2.11/src/sha1.h +17 -0
- data/redis/redis-2.2.11/src/solarisfixes.h +22 -0
- data/redis/redis-2.2.11/src/sort.c +389 -0
- data/redis/redis-2.2.11/src/syncio.c +154 -0
- data/redis/redis-2.2.11/src/t_hash.c +476 -0
- data/redis/redis-2.2.11/src/t_list.c +986 -0
- data/redis/redis-2.2.11/src/t_set.c +610 -0
- data/redis/redis-2.2.11/src/t_string.c +438 -0
- data/redis/redis-2.2.11/src/t_zset.c +1084 -0
- data/redis/redis-2.2.11/src/testhelp.h +54 -0
- data/redis/redis-2.2.11/src/util.c +243 -0
- data/redis/redis-2.2.11/src/valgrind.sup +5 -0
- data/redis/redis-2.2.11/src/version.h +1 -0
- data/redis/redis-2.2.11/src/vm.c +1149 -0
- data/redis/redis-2.2.11/src/ziplist.c +1323 -0
- data/redis/redis-2.2.11/src/ziplist.h +15 -0
- data/redis/redis-2.2.11/src/zipmap.c +455 -0
- data/redis/redis-2.2.11/src/zipmap.h +48 -0
- data/redis/redis-2.2.11/src/zmalloc.c +278 -0
- data/redis/redis-2.2.11/src/zmalloc.h +47 -0
- data/redis/redis-2.2.11/tests/assets/default.conf +308 -0
- data/redis/redis-2.2.11/tests/integration/aof.tcl +104 -0
- data/redis/redis-2.2.11/tests/integration/redis-cli.tcl +208 -0
- data/redis/redis-2.2.11/tests/integration/replication.tcl +98 -0
- data/redis/redis-2.2.11/tests/support/redis.tcl +241 -0
- data/redis/redis-2.2.11/tests/support/server.tcl +294 -0
- data/redis/redis-2.2.11/tests/support/test.tcl +190 -0
- data/redis/redis-2.2.11/tests/support/tmpfile.tcl +15 -0
- data/redis/redis-2.2.11/tests/support/util.tcl +296 -0
- data/redis/redis-2.2.11/tests/test_helper.tcl +221 -0
- data/redis/redis-2.2.11/tests/unit/auth.tcl +15 -0
- data/redis/redis-2.2.11/tests/unit/basic.tcl +616 -0
- data/redis/redis-2.2.11/tests/unit/cas.tcl +135 -0
- data/redis/redis-2.2.11/tests/unit/expire.tcl +74 -0
- data/redis/redis-2.2.11/tests/unit/other.tcl +240 -0
- data/redis/redis-2.2.11/tests/unit/printver.tcl +6 -0
- data/redis/redis-2.2.11/tests/unit/protocol.tcl +62 -0
- data/redis/redis-2.2.11/tests/unit/pubsub.tcl +195 -0
- data/redis/redis-2.2.11/tests/unit/quit.tcl +40 -0
- data/redis/redis-2.2.11/tests/unit/sort.tcl +189 -0
- data/redis/redis-2.2.11/tests/unit/type/hash.tcl +300 -0
- data/redis/redis-2.2.11/tests/unit/type/list.tcl +819 -0
- data/redis/redis-2.2.11/tests/unit/type/set.tcl +334 -0
- data/redis/redis-2.2.11/tests/unit/type/zset.tcl +587 -0
- data/redis/redis-2.2.11/utils/build-static-symbols.tcl +22 -0
- data/redis/redis-2.2.11/utils/generate-command-help.rb +112 -0
- data/redis/redis-2.2.11/utils/mktarball.sh +13 -0
- data/redis/redis-2.2.11/utils/redis-copy.rb +78 -0
- data/redis/redis-2.2.11/utils/redis-sha1.rb +52 -0
- data/redis/redis-2.2.11/utils/redis_init_script +42 -0
- metadata +362 -0
@@ -0,0 +1,154 @@
|
|
1
|
+
/* Synchronous socket and file I/O operations useful across the core.
|
2
|
+
*
|
3
|
+
* Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions are met:
|
8
|
+
*
|
9
|
+
* * Redistributions of source code must retain the above copyright notice,
|
10
|
+
* this list of conditions and the following disclaimer.
|
11
|
+
* * Redistributions in binary form must reproduce the above copyright
|
12
|
+
* notice, this list of conditions and the following disclaimer in the
|
13
|
+
* documentation and/or other materials provided with the distribution.
|
14
|
+
* * Neither the name of Redis nor the names of its contributors may be used
|
15
|
+
* to endorse or promote products derived from this software without
|
16
|
+
* specific prior written permission.
|
17
|
+
*
|
18
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
22
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
23
|
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
* POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include "redis.h"
|
32
|
+
|
33
|
+
/* ----------------- Blocking sockets I/O with timeouts --------------------- */
|
34
|
+
|
35
|
+
/* Redis performs most of the I/O in a nonblocking way, with the exception
|
36
|
+
* of the SYNC command where the slave does it in a blocking way, and
|
37
|
+
* the MIGRATE command that must be blocking in order to be atomic from the
|
38
|
+
* point of view of the two instances (one migrating the key and one receiving
|
39
|
+
* the key). This is why need the following blocking I/O functions. */
|
40
|
+
|
41
|
+
int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
|
42
|
+
ssize_t nwritten, ret = size;
|
43
|
+
time_t start = time(NULL);
|
44
|
+
|
45
|
+
timeout++;
|
46
|
+
while(size) {
|
47
|
+
if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
|
48
|
+
nwritten = write(fd,ptr,size);
|
49
|
+
if (nwritten == -1) return -1;
|
50
|
+
ptr += nwritten;
|
51
|
+
size -= nwritten;
|
52
|
+
}
|
53
|
+
if ((time(NULL)-start) > timeout) {
|
54
|
+
errno = ETIMEDOUT;
|
55
|
+
return -1;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return ret;
|
59
|
+
}
|
60
|
+
|
61
|
+
int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
|
62
|
+
ssize_t nread, totread = 0;
|
63
|
+
time_t start = time(NULL);
|
64
|
+
|
65
|
+
timeout++;
|
66
|
+
while(size) {
|
67
|
+
if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
|
68
|
+
nread = read(fd,ptr,size);
|
69
|
+
if (nread <= 0) return -1;
|
70
|
+
ptr += nread;
|
71
|
+
size -= nread;
|
72
|
+
totread += nread;
|
73
|
+
}
|
74
|
+
if ((time(NULL)-start) > timeout) {
|
75
|
+
errno = ETIMEDOUT;
|
76
|
+
return -1;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
return totread;
|
80
|
+
}
|
81
|
+
|
82
|
+
int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
|
83
|
+
ssize_t nread = 0;
|
84
|
+
|
85
|
+
size--;
|
86
|
+
while(size) {
|
87
|
+
char c;
|
88
|
+
|
89
|
+
if (syncRead(fd,&c,1,timeout) == -1) return -1;
|
90
|
+
if (c == '\n') {
|
91
|
+
*ptr = '\0';
|
92
|
+
if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
|
93
|
+
return nread;
|
94
|
+
} else {
|
95
|
+
*ptr++ = c;
|
96
|
+
*ptr = '\0';
|
97
|
+
nread++;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
return nread;
|
101
|
+
}
|
102
|
+
|
103
|
+
/* ----------------- Blocking sockets I/O with timeouts --------------------- */
|
104
|
+
|
105
|
+
/* Write binary-safe string into a file in the bulkformat
|
106
|
+
* $<count>\r\n<payload>\r\n */
|
107
|
+
int fwriteBulkString(FILE *fp, char *s, unsigned long len) {
|
108
|
+
char cbuf[128];
|
109
|
+
int clen;
|
110
|
+
cbuf[0] = '$';
|
111
|
+
clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,len);
|
112
|
+
cbuf[clen++] = '\r';
|
113
|
+
cbuf[clen++] = '\n';
|
114
|
+
if (fwrite(cbuf,clen,1,fp) == 0) return 0;
|
115
|
+
if (len > 0 && fwrite(s,len,1,fp) == 0) return 0;
|
116
|
+
if (fwrite("\r\n",2,1,fp) == 0) return 0;
|
117
|
+
return 1;
|
118
|
+
}
|
119
|
+
|
120
|
+
/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
|
121
|
+
int fwriteBulkDouble(FILE *fp, double d) {
|
122
|
+
char buf[128], dbuf[128];
|
123
|
+
|
124
|
+
snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
|
125
|
+
snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
|
126
|
+
if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
|
127
|
+
if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
|
128
|
+
return 1;
|
129
|
+
}
|
130
|
+
|
131
|
+
/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
|
132
|
+
int fwriteBulkLongLong(FILE *fp, long long l) {
|
133
|
+
char bbuf[128], lbuf[128];
|
134
|
+
unsigned int blen, llen;
|
135
|
+
llen = ll2string(lbuf,32,l);
|
136
|
+
blen = snprintf(bbuf,sizeof(bbuf),"$%u\r\n%s\r\n",llen,lbuf);
|
137
|
+
if (fwrite(bbuf,blen,1,fp) == 0) return 0;
|
138
|
+
return 1;
|
139
|
+
}
|
140
|
+
|
141
|
+
/* Delegate writing an object to writing a bulk string or bulk long long. */
|
142
|
+
int fwriteBulkObject(FILE *fp, robj *obj) {
|
143
|
+
/* Avoid using getDecodedObject to help copy-on-write (we are often
|
144
|
+
* in a child process when this function is called). */
|
145
|
+
if (obj->encoding == REDIS_ENCODING_INT) {
|
146
|
+
return fwriteBulkLongLong(fp,(long)obj->ptr);
|
147
|
+
} else if (obj->encoding == REDIS_ENCODING_RAW) {
|
148
|
+
return fwriteBulkString(fp,obj->ptr,sdslen(obj->ptr));
|
149
|
+
} else {
|
150
|
+
redisPanic("Unknown string encoding");
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
|
@@ -0,0 +1,476 @@
|
|
1
|
+
#include "redis.h"
|
2
|
+
|
3
|
+
#include <math.h>
|
4
|
+
|
5
|
+
/*-----------------------------------------------------------------------------
|
6
|
+
* Hash type API
|
7
|
+
*----------------------------------------------------------------------------*/
|
8
|
+
|
9
|
+
/* Check the length of a number of objects to see if we need to convert a
|
10
|
+
* zipmap to a real hash. Note that we only check string encoded objects
|
11
|
+
* as their string length can be queried in constant time. */
|
12
|
+
void hashTypeTryConversion(robj *subject, robj **argv, int start, int end) {
|
13
|
+
int i;
|
14
|
+
if (subject->encoding != REDIS_ENCODING_ZIPMAP) return;
|
15
|
+
|
16
|
+
for (i = start; i <= end; i++) {
|
17
|
+
if (argv[i]->encoding == REDIS_ENCODING_RAW &&
|
18
|
+
sdslen(argv[i]->ptr) > server.hash_max_zipmap_value)
|
19
|
+
{
|
20
|
+
convertToRealHash(subject);
|
21
|
+
return;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
/* Encode given objects in-place when the hash uses a dict. */
|
27
|
+
void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) {
|
28
|
+
if (subject->encoding == REDIS_ENCODING_HT) {
|
29
|
+
if (o1) *o1 = tryObjectEncoding(*o1);
|
30
|
+
if (o2) *o2 = tryObjectEncoding(*o2);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
/* Get the value from a hash identified by key.
|
35
|
+
*
|
36
|
+
* If the string is found either REDIS_ENCODING_HT or REDIS_ENCODING_ZIPMAP
|
37
|
+
* is returned, and either **objval or **v and *vlen are set accordingly,
|
38
|
+
* so that objects in hash tables are returend as objects and pointers
|
39
|
+
* inside a zipmap are returned as such.
|
40
|
+
*
|
41
|
+
* If the object was not found -1 is returned.
|
42
|
+
*
|
43
|
+
* This function is copy on write friendly as there is no incr/decr
|
44
|
+
* of refcount needed if objects are accessed just for reading operations. */
|
45
|
+
int hashTypeGet(robj *o, robj *key, robj **objval, unsigned char **v,
|
46
|
+
unsigned int *vlen)
|
47
|
+
{
|
48
|
+
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
|
49
|
+
int found;
|
50
|
+
|
51
|
+
key = getDecodedObject(key);
|
52
|
+
found = zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),v,vlen);
|
53
|
+
decrRefCount(key);
|
54
|
+
if (!found) return -1;
|
55
|
+
} else {
|
56
|
+
dictEntry *de = dictFind(o->ptr,key);
|
57
|
+
if (de == NULL) return -1;
|
58
|
+
*objval = dictGetEntryVal(de);
|
59
|
+
}
|
60
|
+
return o->encoding;
|
61
|
+
}
|
62
|
+
|
63
|
+
/* Higher level function of hashTypeGet() that always returns a Redis
|
64
|
+
* object (either new or with refcount incremented), so that the caller
|
65
|
+
* can retain a reference or call decrRefCount after the usage.
|
66
|
+
*
|
67
|
+
* The lower level function can prevent copy on write so it is
|
68
|
+
* the preferred way of doing read operations. */
|
69
|
+
robj *hashTypeGetObject(robj *o, robj *key) {
|
70
|
+
robj *objval;
|
71
|
+
unsigned char *v;
|
72
|
+
unsigned int vlen;
|
73
|
+
|
74
|
+
int encoding = hashTypeGet(o,key,&objval,&v,&vlen);
|
75
|
+
switch(encoding) {
|
76
|
+
case REDIS_ENCODING_HT:
|
77
|
+
incrRefCount(objval);
|
78
|
+
return objval;
|
79
|
+
case REDIS_ENCODING_ZIPMAP:
|
80
|
+
objval = createStringObject((char*)v,vlen);
|
81
|
+
return objval;
|
82
|
+
default: return NULL;
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
/* Test if the key exists in the given hash. Returns 1 if the key
|
87
|
+
* exists and 0 when it doesn't. */
|
88
|
+
int hashTypeExists(robj *o, robj *key) {
|
89
|
+
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
|
90
|
+
key = getDecodedObject(key);
|
91
|
+
if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
|
92
|
+
decrRefCount(key);
|
93
|
+
return 1;
|
94
|
+
}
|
95
|
+
decrRefCount(key);
|
96
|
+
} else {
|
97
|
+
if (dictFind(o->ptr,key) != NULL) {
|
98
|
+
return 1;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
return 0;
|
102
|
+
}
|
103
|
+
|
104
|
+
/* Add an element, discard the old if the key already exists.
|
105
|
+
* Return 0 on insert and 1 on update. */
|
106
|
+
int hashTypeSet(robj *o, robj *key, robj *value) {
|
107
|
+
int update = 0;
|
108
|
+
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
|
109
|
+
key = getDecodedObject(key);
|
110
|
+
value = getDecodedObject(value);
|
111
|
+
o->ptr = zipmapSet(o->ptr,
|
112
|
+
key->ptr,sdslen(key->ptr),
|
113
|
+
value->ptr,sdslen(value->ptr), &update);
|
114
|
+
decrRefCount(key);
|
115
|
+
decrRefCount(value);
|
116
|
+
|
117
|
+
/* Check if the zipmap needs to be upgraded to a real hash table */
|
118
|
+
if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
|
119
|
+
convertToRealHash(o);
|
120
|
+
} else {
|
121
|
+
if (dictReplace(o->ptr,key,value)) {
|
122
|
+
/* Insert */
|
123
|
+
incrRefCount(key);
|
124
|
+
} else {
|
125
|
+
/* Update */
|
126
|
+
update = 1;
|
127
|
+
}
|
128
|
+
incrRefCount(value);
|
129
|
+
}
|
130
|
+
return update;
|
131
|
+
}
|
132
|
+
|
133
|
+
/* Delete an element from a hash.
|
134
|
+
* Return 1 on deleted and 0 on not found. */
|
135
|
+
int hashTypeDelete(robj *o, robj *key) {
|
136
|
+
int deleted = 0;
|
137
|
+
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
|
138
|
+
key = getDecodedObject(key);
|
139
|
+
o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
|
140
|
+
decrRefCount(key);
|
141
|
+
} else {
|
142
|
+
deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
|
143
|
+
/* Always check if the dictionary needs a resize after a delete. */
|
144
|
+
if (deleted && htNeedsResize(o->ptr)) dictResize(o->ptr);
|
145
|
+
}
|
146
|
+
return deleted;
|
147
|
+
}
|
148
|
+
|
149
|
+
/* Return the number of elements in a hash. */
|
150
|
+
unsigned long hashTypeLength(robj *o) {
|
151
|
+
return (o->encoding == REDIS_ENCODING_ZIPMAP) ?
|
152
|
+
zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
|
153
|
+
}
|
154
|
+
|
155
|
+
hashTypeIterator *hashTypeInitIterator(robj *subject) {
|
156
|
+
hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator));
|
157
|
+
hi->encoding = subject->encoding;
|
158
|
+
if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
|
159
|
+
hi->zi = zipmapRewind(subject->ptr);
|
160
|
+
} else if (hi->encoding == REDIS_ENCODING_HT) {
|
161
|
+
hi->di = dictGetIterator(subject->ptr);
|
162
|
+
} else {
|
163
|
+
redisAssert(NULL);
|
164
|
+
}
|
165
|
+
return hi;
|
166
|
+
}
|
167
|
+
|
168
|
+
void hashTypeReleaseIterator(hashTypeIterator *hi) {
|
169
|
+
if (hi->encoding == REDIS_ENCODING_HT) {
|
170
|
+
dictReleaseIterator(hi->di);
|
171
|
+
}
|
172
|
+
zfree(hi);
|
173
|
+
}
|
174
|
+
|
175
|
+
/* Move to the next entry in the hash. Return REDIS_OK when the next entry
|
176
|
+
* could be found and REDIS_ERR when the iterator reaches the end. */
|
177
|
+
int hashTypeNext(hashTypeIterator *hi) {
|
178
|
+
if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
|
179
|
+
if ((hi->zi = zipmapNext(hi->zi, &hi->zk, &hi->zklen,
|
180
|
+
&hi->zv, &hi->zvlen)) == NULL) return REDIS_ERR;
|
181
|
+
} else {
|
182
|
+
if ((hi->de = dictNext(hi->di)) == NULL) return REDIS_ERR;
|
183
|
+
}
|
184
|
+
return REDIS_OK;
|
185
|
+
}
|
186
|
+
|
187
|
+
/* Get key or value object at current iteration position.
|
188
|
+
* The returned item differs with the hash object encoding:
|
189
|
+
* - When encoding is REDIS_ENCODING_HT, the objval pointer is populated
|
190
|
+
* with the original object.
|
191
|
+
* - When encoding is REDIS_ENCODING_ZIPMAP, a pointer to the string and
|
192
|
+
* its length is retunred populating the v and vlen pointers.
|
193
|
+
* This function is copy on write friendly as accessing objects in read only
|
194
|
+
* does not require writing to any memory page.
|
195
|
+
*
|
196
|
+
* The function returns the encoding of the object, so that the caller
|
197
|
+
* can underestand if the key or value was returned as object or C string. */
|
198
|
+
int hashTypeCurrent(hashTypeIterator *hi, int what, robj **objval, unsigned char **v, unsigned int *vlen) {
|
199
|
+
if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
|
200
|
+
if (what & REDIS_HASH_KEY) {
|
201
|
+
*v = hi->zk;
|
202
|
+
*vlen = hi->zklen;
|
203
|
+
} else {
|
204
|
+
*v = hi->zv;
|
205
|
+
*vlen = hi->zvlen;
|
206
|
+
}
|
207
|
+
} else {
|
208
|
+
if (what & REDIS_HASH_KEY)
|
209
|
+
*objval = dictGetEntryKey(hi->de);
|
210
|
+
else
|
211
|
+
*objval = dictGetEntryVal(hi->de);
|
212
|
+
}
|
213
|
+
return hi->encoding;
|
214
|
+
}
|
215
|
+
|
216
|
+
/* A non copy-on-write friendly but higher level version of hashTypeCurrent()
|
217
|
+
* that always returns an object with refcount incremented by one (or a new
|
218
|
+
* object), so it's up to the caller to decrRefCount() the object if no
|
219
|
+
* reference is retained. */
|
220
|
+
robj *hashTypeCurrentObject(hashTypeIterator *hi, int what) {
|
221
|
+
robj *obj;
|
222
|
+
unsigned char *v = NULL;
|
223
|
+
unsigned int vlen = 0;
|
224
|
+
int encoding = hashTypeCurrent(hi,what,&obj,&v,&vlen);
|
225
|
+
|
226
|
+
if (encoding == REDIS_ENCODING_HT) {
|
227
|
+
incrRefCount(obj);
|
228
|
+
return obj;
|
229
|
+
} else {
|
230
|
+
return createStringObject((char*)v,vlen);
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
234
|
+
robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key) {
|
235
|
+
robj *o = lookupKeyWrite(c->db,key);
|
236
|
+
if (o == NULL) {
|
237
|
+
o = createHashObject();
|
238
|
+
dbAdd(c->db,key,o);
|
239
|
+
} else {
|
240
|
+
if (o->type != REDIS_HASH) {
|
241
|
+
addReply(c,shared.wrongtypeerr);
|
242
|
+
return NULL;
|
243
|
+
}
|
244
|
+
}
|
245
|
+
return o;
|
246
|
+
}
|
247
|
+
|
248
|
+
void convertToRealHash(robj *o) {
|
249
|
+
unsigned char *key, *val, *p, *zm = o->ptr;
|
250
|
+
unsigned int klen, vlen;
|
251
|
+
dict *dict = dictCreate(&hashDictType,NULL);
|
252
|
+
|
253
|
+
redisAssert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
|
254
|
+
p = zipmapRewind(zm);
|
255
|
+
while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
|
256
|
+
robj *keyobj, *valobj;
|
257
|
+
|
258
|
+
keyobj = createStringObject((char*)key,klen);
|
259
|
+
valobj = createStringObject((char*)val,vlen);
|
260
|
+
keyobj = tryObjectEncoding(keyobj);
|
261
|
+
valobj = tryObjectEncoding(valobj);
|
262
|
+
dictAdd(dict,keyobj,valobj);
|
263
|
+
}
|
264
|
+
o->encoding = REDIS_ENCODING_HT;
|
265
|
+
o->ptr = dict;
|
266
|
+
zfree(zm);
|
267
|
+
}
|
268
|
+
|
269
|
+
/*-----------------------------------------------------------------------------
|
270
|
+
* Hash type commands
|
271
|
+
*----------------------------------------------------------------------------*/
|
272
|
+
|
273
|
+
void hsetCommand(redisClient *c) {
|
274
|
+
int update;
|
275
|
+
robj *o;
|
276
|
+
|
277
|
+
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
278
|
+
hashTypeTryConversion(o,c->argv,2,3);
|
279
|
+
hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
|
280
|
+
update = hashTypeSet(o,c->argv[2],c->argv[3]);
|
281
|
+
addReply(c, update ? shared.czero : shared.cone);
|
282
|
+
touchWatchedKey(c->db,c->argv[1]);
|
283
|
+
server.dirty++;
|
284
|
+
}
|
285
|
+
|
286
|
+
void hsetnxCommand(redisClient *c) {
|
287
|
+
robj *o;
|
288
|
+
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
289
|
+
hashTypeTryConversion(o,c->argv,2,3);
|
290
|
+
|
291
|
+
if (hashTypeExists(o, c->argv[2])) {
|
292
|
+
addReply(c, shared.czero);
|
293
|
+
} else {
|
294
|
+
hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
|
295
|
+
hashTypeSet(o,c->argv[2],c->argv[3]);
|
296
|
+
addReply(c, shared.cone);
|
297
|
+
touchWatchedKey(c->db,c->argv[1]);
|
298
|
+
server.dirty++;
|
299
|
+
}
|
300
|
+
}
|
301
|
+
|
302
|
+
void hmsetCommand(redisClient *c) {
|
303
|
+
int i;
|
304
|
+
robj *o;
|
305
|
+
|
306
|
+
if ((c->argc % 2) == 1) {
|
307
|
+
addReplyError(c,"wrong number of arguments for HMSET");
|
308
|
+
return;
|
309
|
+
}
|
310
|
+
|
311
|
+
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
312
|
+
hashTypeTryConversion(o,c->argv,2,c->argc-1);
|
313
|
+
for (i = 2; i < c->argc; i += 2) {
|
314
|
+
hashTypeTryObjectEncoding(o,&c->argv[i], &c->argv[i+1]);
|
315
|
+
hashTypeSet(o,c->argv[i],c->argv[i+1]);
|
316
|
+
}
|
317
|
+
addReply(c, shared.ok);
|
318
|
+
touchWatchedKey(c->db,c->argv[1]);
|
319
|
+
server.dirty++;
|
320
|
+
}
|
321
|
+
|
322
|
+
void hincrbyCommand(redisClient *c) {
|
323
|
+
long long value, incr;
|
324
|
+
robj *o, *current, *new;
|
325
|
+
|
326
|
+
if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return;
|
327
|
+
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
328
|
+
if ((current = hashTypeGetObject(o,c->argv[2])) != NULL) {
|
329
|
+
if (getLongLongFromObjectOrReply(c,current,&value,
|
330
|
+
"hash value is not an integer") != REDIS_OK) {
|
331
|
+
decrRefCount(current);
|
332
|
+
return;
|
333
|
+
}
|
334
|
+
decrRefCount(current);
|
335
|
+
} else {
|
336
|
+
value = 0;
|
337
|
+
}
|
338
|
+
|
339
|
+
value += incr;
|
340
|
+
new = createStringObjectFromLongLong(value);
|
341
|
+
hashTypeTryObjectEncoding(o,&c->argv[2],NULL);
|
342
|
+
hashTypeSet(o,c->argv[2],new);
|
343
|
+
decrRefCount(new);
|
344
|
+
addReplyLongLong(c,value);
|
345
|
+
touchWatchedKey(c->db,c->argv[1]);
|
346
|
+
server.dirty++;
|
347
|
+
}
|
348
|
+
|
349
|
+
void hgetCommand(redisClient *c) {
|
350
|
+
robj *o, *value;
|
351
|
+
unsigned char *v;
|
352
|
+
unsigned int vlen;
|
353
|
+
int encoding;
|
354
|
+
|
355
|
+
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
|
356
|
+
checkType(c,o,REDIS_HASH)) return;
|
357
|
+
|
358
|
+
if ((encoding = hashTypeGet(o,c->argv[2],&value,&v,&vlen)) != -1) {
|
359
|
+
if (encoding == REDIS_ENCODING_HT)
|
360
|
+
addReplyBulk(c,value);
|
361
|
+
else
|
362
|
+
addReplyBulkCBuffer(c,v,vlen);
|
363
|
+
} else {
|
364
|
+
addReply(c,shared.nullbulk);
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
void hmgetCommand(redisClient *c) {
|
369
|
+
int i, encoding;
|
370
|
+
robj *o, *value;
|
371
|
+
unsigned char *v;
|
372
|
+
unsigned int vlen;
|
373
|
+
|
374
|
+
o = lookupKeyRead(c->db,c->argv[1]);
|
375
|
+
if (o != NULL && o->type != REDIS_HASH) {
|
376
|
+
addReply(c,shared.wrongtypeerr);
|
377
|
+
return;
|
378
|
+
}
|
379
|
+
|
380
|
+
/* Note the check for o != NULL happens inside the loop. This is
|
381
|
+
* done because objects that cannot be found are considered to be
|
382
|
+
* an empty hash. The reply should then be a series of NULLs. */
|
383
|
+
addReplyMultiBulkLen(c,c->argc-2);
|
384
|
+
for (i = 2; i < c->argc; i++) {
|
385
|
+
if (o != NULL &&
|
386
|
+
(encoding = hashTypeGet(o,c->argv[i],&value,&v,&vlen)) != -1) {
|
387
|
+
if (encoding == REDIS_ENCODING_HT)
|
388
|
+
addReplyBulk(c,value);
|
389
|
+
else
|
390
|
+
addReplyBulkCBuffer(c,v,vlen);
|
391
|
+
} else {
|
392
|
+
addReply(c,shared.nullbulk);
|
393
|
+
}
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
void hdelCommand(redisClient *c) {
|
398
|
+
robj *o;
|
399
|
+
if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
|
400
|
+
checkType(c,o,REDIS_HASH)) return;
|
401
|
+
|
402
|
+
if (hashTypeDelete(o,c->argv[2])) {
|
403
|
+
if (hashTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
|
404
|
+
addReply(c,shared.cone);
|
405
|
+
touchWatchedKey(c->db,c->argv[1]);
|
406
|
+
server.dirty++;
|
407
|
+
} else {
|
408
|
+
addReply(c,shared.czero);
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
void hlenCommand(redisClient *c) {
|
413
|
+
robj *o;
|
414
|
+
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
|
415
|
+
checkType(c,o,REDIS_HASH)) return;
|
416
|
+
|
417
|
+
addReplyLongLong(c,hashTypeLength(o));
|
418
|
+
}
|
419
|
+
|
420
|
+
void genericHgetallCommand(redisClient *c, int flags) {
|
421
|
+
robj *o;
|
422
|
+
unsigned long count = 0;
|
423
|
+
hashTypeIterator *hi;
|
424
|
+
void *replylen = NULL;
|
425
|
+
|
426
|
+
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
|
427
|
+
|| checkType(c,o,REDIS_HASH)) return;
|
428
|
+
|
429
|
+
replylen = addDeferredMultiBulkLength(c);
|
430
|
+
hi = hashTypeInitIterator(o);
|
431
|
+
while (hashTypeNext(hi) != REDIS_ERR) {
|
432
|
+
robj *obj;
|
433
|
+
unsigned char *v = NULL;
|
434
|
+
unsigned int vlen = 0;
|
435
|
+
int encoding;
|
436
|
+
|
437
|
+
if (flags & REDIS_HASH_KEY) {
|
438
|
+
encoding = hashTypeCurrent(hi,REDIS_HASH_KEY,&obj,&v,&vlen);
|
439
|
+
if (encoding == REDIS_ENCODING_HT)
|
440
|
+
addReplyBulk(c,obj);
|
441
|
+
else
|
442
|
+
addReplyBulkCBuffer(c,v,vlen);
|
443
|
+
count++;
|
444
|
+
}
|
445
|
+
if (flags & REDIS_HASH_VALUE) {
|
446
|
+
encoding = hashTypeCurrent(hi,REDIS_HASH_VALUE,&obj,&v,&vlen);
|
447
|
+
if (encoding == REDIS_ENCODING_HT)
|
448
|
+
addReplyBulk(c,obj);
|
449
|
+
else
|
450
|
+
addReplyBulkCBuffer(c,v,vlen);
|
451
|
+
count++;
|
452
|
+
}
|
453
|
+
}
|
454
|
+
hashTypeReleaseIterator(hi);
|
455
|
+
setDeferredMultiBulkLength(c,replylen,count);
|
456
|
+
}
|
457
|
+
|
458
|
+
void hkeysCommand(redisClient *c) {
|
459
|
+
genericHgetallCommand(c,REDIS_HASH_KEY);
|
460
|
+
}
|
461
|
+
|
462
|
+
void hvalsCommand(redisClient *c) {
|
463
|
+
genericHgetallCommand(c,REDIS_HASH_VALUE);
|
464
|
+
}
|
465
|
+
|
466
|
+
void hgetallCommand(redisClient *c) {
|
467
|
+
genericHgetallCommand(c,REDIS_HASH_KEY|REDIS_HASH_VALUE);
|
468
|
+
}
|
469
|
+
|
470
|
+
void hexistsCommand(redisClient *c) {
|
471
|
+
robj *o;
|
472
|
+
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
|
473
|
+
checkType(c,o,REDIS_HASH)) return;
|
474
|
+
|
475
|
+
addReply(c, hashTypeExists(o,c->argv[2]) ? shared.cone : shared.czero);
|
476
|
+
}
|