]> git.cworth.org Git - apitrace/blob - trace_snappyfile.cpp
2dc5cb3c1ff30db001dd1d1e7d6d8800b5f83f9c
[apitrace] / trace_snappyfile.cpp
1 #include "trace_snappyfile.hpp"
2
3 #include <snappy.h>
4
5 #include <assert.h>
6 #include <string.h>
7
8 using namespace Trace;
9
10 /*
11  * Snappy file format.
12  * -------------------
13  *
14  * Snappy at its core is just a compressoin algorithm so we're
15  * creating a new file format which uses snappy compression
16  * to hold the trace data.
17  *
18  * The file is composed of a number of chunks, they are:
19  * chunk {
20  *     uint32 - specifying the length of the compressed data
21  *     compressed data
22  * }
23  * File can contain any number of such chunks.
24  * The default size of an uncompressed chunk is specified in
25  * SNAPPY_CHUNK_SIZE.
26  *
27  * Note:
28  * Currently the default size for a a to-be-compressed data is
29  * 1mb, meaning that the compressed data will be <= 1mb.
30  * The reason it's 1mb is because it seems
31  * to offer a pretty good compression/disk io speed ratio
32  * but that might change.
33  *
34  */
35
36 SnappyFile::SnappyFile(const std::string &filename,
37                               File::Mode mode)
38     : File(),
39       m_cache(0),
40       m_cachePtr(0),
41       m_cacheSize(0)
42 {
43     m_compressedCache = new char[SNAPPY_CHUNK_SIZE];
44 }
45
46 SnappyFile::~SnappyFile()
47 {
48     delete [] m_compressedCache;
49 }
50
51 bool SnappyFile::rawOpen(const std::string &filename, File::Mode mode)
52 {
53     std::ios_base::openmode fmode = std::fstream::binary;
54     if (mode == File::Write) {
55         fmode |= (std::fstream::out | std::fstream::trunc);
56         createCache(SNAPPY_CHUNK_SIZE);
57     } else if (mode == File::Read) {
58         fmode |= std::fstream::in;
59     }
60
61     m_stream.open(filename.c_str(), fmode);
62
63     //read in the initial buffer if we're reading
64     if (m_stream.is_open() && mode == File::Read) {
65         // read the snappy file identifier
66         unsigned char byte1, byte2;
67         m_stream >> byte1;
68         m_stream >> byte2;
69         assert(byte1 == SNAPPY_BYTE1 && byte2 == SNAPPY_BYTE2);
70
71         flushCache();
72     } else if (m_stream.is_open() && mode == File::Write) {
73         // write the snappy file identifier
74         m_stream << SNAPPY_BYTE1;
75         m_stream << SNAPPY_BYTE2;
76     }
77     return m_stream.is_open();
78 }
79
80 bool SnappyFile::rawWrite(const void *buffer, int length)
81 {
82     if (freeCacheSize() > length) {
83         memcpy(m_cachePtr, buffer, length);
84         m_cachePtr += length;
85     } else if (freeCacheSize() == length) {
86         memcpy(m_cachePtr, buffer, length);
87         m_cachePtr += length;
88         flushCache();
89     } else {
90         int sizeToWrite = length;
91
92         while (sizeToWrite >= freeCacheSize()) {
93             int endSize = freeCacheSize();
94             int offset = length - sizeToWrite;
95             memcpy(m_cachePtr, (char*)buffer + offset, endSize);
96             sizeToWrite -= endSize;
97             m_cachePtr += endSize;
98             flushCache();
99         }
100         if (sizeToWrite) {
101             int offset = length - sizeToWrite;
102             memcpy(m_cachePtr, (char*)buffer + offset, sizeToWrite);
103             m_cachePtr += sizeToWrite;
104         }
105     }
106
107     return true;
108 }
109
110 bool SnappyFile::rawRead(void *buffer, int length)
111 {
112     if (m_stream.eof()) {
113         return false;
114     }
115     if (freeCacheSize() > length) {
116         memcpy(buffer, m_cachePtr, length);
117         m_cachePtr += length;
118     } else if (freeCacheSize() == length) {
119         memcpy(buffer, m_cachePtr, length);
120         m_cachePtr += length;
121         flushCache();
122     } else {
123         int sizeToRead = length;
124         int offset = 0;
125         while (sizeToRead) {
126             int chunkSize = std::min(freeCacheSize(), sizeToRead);
127             offset = length - sizeToRead;
128             memcpy((char*)buffer + offset, m_cachePtr, chunkSize);
129             m_cachePtr += chunkSize;
130             sizeToRead -= chunkSize;
131             if (sizeToRead > 0)
132                 flushCache();
133             if (!m_cacheSize)
134                 break;
135         }
136     }
137
138     return true;
139 }
140
141 int SnappyFile::rawGetc()
142 {
143     int c = 0;
144     if (!rawRead(&c, 1))
145         return -1;
146     return c;
147 }
148
149 void SnappyFile::rawClose()
150 {
151     flushCache();
152     m_stream.close();
153     delete [] m_cache;
154     m_cache = NULL;
155     m_cachePtr = NULL;
156 }
157
158 void SnappyFile::rawFlush(FlushType type)
159 {
160     if (type == FlushDeep) {
161         flushCache();
162     }
163     m_stream.flush();
164 }
165
166 void SnappyFile::flushCache()
167 {
168     if (m_mode == File::Write) {
169         size_t compressedLength;
170
171         ::snappy::RawCompress(m_cache, SNAPPY_CHUNK_SIZE - freeCacheSize(),
172                               m_compressedCache, &compressedLength);
173
174         writeCompressedLength(compressedLength);
175         m_stream.write(m_compressedCache, compressedLength);
176         m_cachePtr = m_cache;
177     } else if (m_mode == File::Read) {
178         if (m_stream.eof())
179             return;
180         //assert(m_cachePtr == m_cache + m_cacheSize);
181         size_t compressedLength;
182         compressedLength = readCompressedLength();
183         m_stream.read((char*)m_compressedCache, compressedLength);
184         ::snappy::GetUncompressedLength(m_compressedCache, compressedLength,
185                                         &m_cacheSize);
186         if (m_cache)
187             delete [] m_cache;
188         createCache(m_cacheSize);
189         ::snappy::RawUncompress(m_compressedCache, compressedLength,
190                                 m_cache);
191     }
192 }
193
194 void SnappyFile::createCache(size_t size)
195 {
196     m_cache = new char[size];
197     m_cachePtr = m_cache;
198     m_cacheSize = size;
199 }
200
201 void SnappyFile::writeCompressedLength(uint32_t value)
202 {
203     m_stream.write((char*)&value, sizeof value);
204 }
205
206 uint32_t SnappyFile::readCompressedLength()
207 {
208     uint32_t len;
209     m_stream.read((char*)&len, sizeof len);
210     return len;
211 }