]>
git.saurik.com Git - redis.git/blob - src/rio.c
1 /* rio.c is a simple stream-oriented I/O abstraction that provides an interface
2 * to write code that can consume/produce data using different concrete input
3 * and output devices. For instance the same rdb.c code using the rio
4 * abstraction can be used to read and write the RDB format using in-memory
7 * A rio object provides the following methods:
8 * read: read from stream.
9 * write: write to stream.
10 * tell: get the current offset.
12 * It is also possible to set a 'checksum' method that is used by rio.c in order
13 * to compute a checksum of the data written or read, or to query the rio object
14 * for the current checksum.
16 * ----------------------------------------------------------------------------
18 * Copyright (c) 2009-2012, Pieter Noordhuis <pcnoordhuis at gmail dot com>
19 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
25 * * Redistributions of source code must retain the above copyright notice,
26 * this list of conditions and the following disclaimer.
27 * * Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * * Neither the name of Redis nor the names of its contributors may be used
31 * to endorse or promote products derived from this software without
32 * specific prior written permission.
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
38 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 * POSSIBILITY OF SUCH DAMAGE.
54 uint64_t crc64(uint64_t crc
, const unsigned char *s
, uint64_t l
);
56 /* Returns 1 or 0 for success/failure. */
57 static size_t rioBufferWrite(rio
*r
, const void *buf
, size_t len
) {
58 r
->io
.buffer
.ptr
= sdscatlen(r
->io
.buffer
.ptr
,(char*)buf
,len
);
59 r
->io
.buffer
.pos
+= len
;
63 /* Returns 1 or 0 for success/failure. */
64 static size_t rioBufferRead(rio
*r
, void *buf
, size_t len
) {
65 if (sdslen(r
->io
.buffer
.ptr
)-r
->io
.buffer
.pos
< len
)
66 return 0; /* not enough buffer to return len bytes. */
67 memcpy(buf
,r
->io
.buffer
.ptr
+r
->io
.buffer
.pos
,len
);
68 r
->io
.buffer
.pos
+= len
;
72 /* Returns read/write position in buffer. */
73 static off_t
rioBufferTell(rio
*r
) {
74 return r
->io
.buffer
.pos
;
77 /* Returns 1 or 0 for success/failure. */
78 static size_t rioFileWrite(rio
*r
, const void *buf
, size_t len
) {
79 return fwrite(buf
,len
,1,r
->io
.file
.fp
);
82 /* Returns 1 or 0 for success/failure. */
83 static size_t rioFileRead(rio
*r
, void *buf
, size_t len
) {
84 return fread(buf
,len
,1,r
->io
.file
.fp
);
87 /* Returns read/write position in file. */
88 static off_t
rioFileTell(rio
*r
) {
89 return ftello(r
->io
.file
.fp
);
92 static const rio rioBufferIO
= {
96 NULL
, /* update_checksum */
97 0, /* current checksum */
98 { { NULL
, 0 } } /* union for io-specific vars */
101 static const rio rioFileIO
= {
105 NULL
, /* update_checksum */
106 0, /* current checksum */
107 { { NULL
, 0 } } /* union for io-specific vars */
110 void rioInitWithFile(rio
*r
, FILE *fp
) {
115 void rioInitWithBuffer(rio
*r
, sds s
) {
117 r
->io
.buffer
.ptr
= s
;
118 r
->io
.buffer
.pos
= 0;
121 /* This function can be installed both in memory and file streams when checksum
122 * computation is needed. */
123 void rioGenericUpdateChecksum(rio
*r
, const void *buf
, size_t len
) {
124 r
->cksum
= crc64(r
->cksum
,buf
,len
);
127 /* ------------------------------ Higher level interface ---------------------------
128 * The following higher level functions use lower level rio.c functions to help
129 * generating the Redis protocol for the Append Only File. */
131 /* Write multi bulk count in the format: "*<count>\r\n". */
132 size_t rioWriteBulkCount(rio
*r
, char prefix
, int count
) {
137 clen
= 1+ll2string(cbuf
+1,sizeof(cbuf
)-1,count
);
140 if (rioWrite(r
,cbuf
,clen
) == 0) return 0;
144 /* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". */
145 size_t rioWriteBulkString(rio
*r
, const char *buf
, size_t len
) {
148 if ((nwritten
= rioWriteBulkCount(r
,'$',len
)) == 0) return 0;
149 if (len
> 0 && rioWrite(r
,buf
,len
) == 0) return 0;
150 if (rioWrite(r
,"\r\n",2) == 0) return 0;
151 return nwritten
+len
+2;
154 /* Write a long long value in format: "$<count>\r\n<payload>\r\n". */
155 size_t rioWriteBulkLongLong(rio
*r
, long long l
) {
159 llen
= ll2string(lbuf
,sizeof(lbuf
),l
);
160 return rioWriteBulkString(r
,lbuf
,llen
);
163 /* Write a double value in the format: "$<count>\r\n<payload>\r\n" */
164 size_t rioWriteBulkDouble(rio
*r
, double d
) {
168 dlen
= snprintf(dbuf
,sizeof(dbuf
),"%.17g",d
);
169 return rioWriteBulkString(r
,dbuf
,dlen
);