]>
Commit | Line | Data |
---|---|---|
52970711 | 1 | /* diskstore.c implements a very simple disk backed key-value store used |
2 | * by Redis for the "disk" backend. This implementation uses the filesystem | |
3 | * to store key/value pairs. Every file represents a given key. | |
4 | * | |
5 | * The key path is calculated using the SHA1 of the key name. For instance | |
6 | * the key "foo" is stored as a file name called: | |
7 | * | |
8 | * /0b/ee/0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 | |
9 | * | |
10 | * The couples of characters from the hex output of SHA1 are also used | |
11 | * to locate two two levels of directories to store the file (as most | |
12 | * filesystems are not able to handle too many files in a single dir). | |
13 | * | |
14 | * In the end there are 65536 final directories (256 directories inside | |
15 | * every 256 top level directories), so that with 1 billion of files every | |
16 | * directory will contain in the average 15258 entires, that is ok with | |
17 | * most filesystems implementation. | |
18 | * | |
697af434 | 19 | * Note that since Redis supports multiple databases, the actual key name |
20 | * is: | |
21 | * | |
22 | * /0b/ee/<dbid>_0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 | |
23 | * | |
24 | * so for instance if the key is inside DB 0: | |
25 | * | |
26 | * /0b/ee/0_0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 | |
27 | * | |
28 | * The actaul implementation of this disk store is highly dependant to the | |
29 | * filesystem implementation itself. This implementation may be replaced by | |
52970711 | 30 | * a B+TREE implementation in future implementations. |
31 | * | |
32 | * Data ok every key is serialized using the same format used for .rdb | |
33 | * serialization. Everything is serialized on every entry: key name, | |
34 | * ttl information in case of keys with an associated expire time, and the | |
35 | * serialized value itself. | |
36 | * | |
37 | * Because the format is the same of the .rdb files it is trivial to create | |
38 | * an .rdb file starting from this format just by mean of scanning the | |
39 | * directories and concatenating entries, with the sole addition of an | |
40 | * .rdb header at the start and the end-of-db opcode at the end. | |
41 | * | |
42 | * ------------------------------------------------------------------------- | |
43 | * | |
44 | * Copyright (c) 2010-2011, Salvatore Sanfilippo <antirez at gmail dot com> | |
45 | * All rights reserved. | |
46 | * | |
47 | * Redistribution and use in source and binary forms, with or without | |
48 | * modification, are permitted provided that the following conditions are met: | |
49 | * | |
50 | * * Redistributions of source code must retain the above copyright notice, | |
51 | * this list of conditions and the following disclaimer. | |
52 | * * Redistributions in binary form must reproduce the above copyright | |
53 | * notice, this list of conditions and the following disclaimer in the | |
54 | * documentation and/or other materials provided with the distribution. | |
55 | * * Neither the name of Redis nor the names of its contributors may be used | |
56 | * to endorse or promote products derived from this software without | |
57 | * specific prior written permission. | |
58 | * | |
59 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
60 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
63 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
64 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
65 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
66 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
67 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
68 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
69 | * POSSIBILITY OF SUCH DAMAGE. | |
70 | */ | |
71 | ||
72 | #include "redis.h" | |
73 | ||
74 | #include <fcntl.h> | |
75 | #include <sys/stat.h> | |
76 | ||
ddbc81af | 77 | int create256dir(char *prefix) { |
78 | char buf[1024]; | |
79 | int j; | |
80 | ||
81 | for (j = 0; j < 256; j++) { | |
82 | snprintf(buf,sizeof(buf),"%s%02x",prefix,j); | |
83 | if (mkdir(buf,0755) == -1) { | |
84 | redisLog(REDIS_WARNING,"Error creating dir %s for diskstore: %s", | |
85 | buf,strerror(errno)); | |
86 | return REDIS_ERR; | |
87 | } | |
88 | } | |
89 | return REDIS_OK; | |
90 | } | |
91 | ||
52970711 | 92 | int dsOpen(void) { |
93 | struct stat sb; | |
ddbc81af | 94 | int retval, j; |
697af434 | 95 | char *path = server.ds_path; |
ddbc81af | 96 | char buf[1024]; |
52970711 | 97 | |
98 | if ((retval = stat(path,&sb) == -1) && errno != ENOENT) { | |
99 | redisLog(REDIS_WARNING, "Error opening disk store at %s: %s", | |
100 | path, strerror(errno)); | |
101 | return REDIS_ERR; | |
102 | } | |
103 | ||
104 | /* Directory already in place. Assume everything is ok. */ | |
67b0b41c | 105 | if (retval == 0 && S_ISDIR(sb.st_mode)) { |
106 | redisLog(REDIS_NOTICE,"Disk store %s exists", path); | |
107 | return REDIS_OK; | |
108 | } | |
52970711 | 109 | |
110 | /* File exists but it's not a directory */ | |
111 | if (retval == 0 && !S_ISDIR(sb.st_mode)) { | |
112 | redisLog(REDIS_WARNING,"Disk store at %s is not a directory", path); | |
113 | return REDIS_ERR; | |
114 | } | |
115 | ||
116 | /* New disk store, create the directory structure now, as creating | |
117 | * them in a lazy way is not a good idea, after very few insertions | |
118 | * we'll need most of the 65536 directories anyway. */ | |
67b0b41c | 119 | redisLog(REDIS_NOTICE,"Disk store %s does not exist: creating", path); |
ddbc81af | 120 | if (mkdir(path,0755) == -1) { |
52970711 | 121 | redisLog(REDIS_WARNING,"Disk store init failed creating dir %s: %s", |
122 | path, strerror(errno)); | |
123 | return REDIS_ERR; | |
124 | } | |
ddbc81af | 125 | /* Create the top level 256 directories */ |
126 | snprintf(buf,sizeof(buf),"%s/",path); | |
127 | if (create256dir(buf) == REDIS_ERR) return REDIS_ERR; | |
128 | ||
129 | /* For every 256 top level dir, create 256 nested dirs */ | |
130 | for (j = 0; j < 256; j++) { | |
131 | snprintf(buf,sizeof(buf),"%s/%02x/",path,j); | |
132 | if (create256dir(buf) == REDIS_ERR) return REDIS_ERR; | |
133 | } | |
52970711 | 134 | return REDIS_OK; |
135 | } | |
136 | ||
137 | int dsClose(void) { | |
138 | return REDIS_OK; | |
139 | } | |
140 | ||
141 | int dsSet(redisDb *db, robj *key, robj *val) { | |
142 | } | |
143 | ||
144 | robj *dsGet(redisDb *db, robj *key) { | |
145 | } | |
146 | ||
5ef64098 | 147 | int dsDel(redisDb *db, robj *key) { |
148 | } | |
149 | ||
52970711 | 150 | int dsExists(redisDb *db, robj *key) { |
151 | } | |
cea8c5cd | 152 | |
153 | int dsFlushDb(int dbid) { | |
154 | } |