HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StreamCompression.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file points/StreamCompression.h
5 ///
6 /// @author Dan Bailey
7 ///
8 /// @brief Convenience wrappers to using Blosc and reading and writing of Paged data.
9 ///
10 /// Blosc is most effective with large (> ~256KB) blocks of data. Writing the entire
11 /// data block contiguously would provide the most optimal compression, however would
12 /// limit the ability to use delayed-loading as the whole block would be required to
13 /// be loaded from disk at once. To balance these two competing factors, Paging is used
14 /// to write out blocks of data that are a reasonable size for Blosc. These Pages are
15 /// loaded lazily, tracking the input stream pointers and creating Handles that reference
16 /// portions of the buffer. When the Page buffer is accessed, the data will be read from
17 /// the stream.
18 
19 #ifndef OPENVDB_TOOLS_STREAM_COMPRESSION_HAS_BEEN_INCLUDED
20 #define OPENVDB_TOOLS_STREAM_COMPRESSION_HAS_BEEN_INCLUDED
21 
22 #include <openvdb/io/io.h>
23 #include <tbb/spin_mutex.h>
24 #include <memory>
25 #include <string>
26 
27 
28 class TestStreamCompression;
29 
30 namespace openvdb {
32 namespace OPENVDB_VERSION_NAME {
33 namespace compression {
34 
35 
36 // This is the minimum number of bytes below which Blosc compression is not used to
37 // avoid unecessary computation, as Blosc offers minimal compression until this limit
38 static const int BLOSC_MINIMUM_BYTES = 48;
39 
40 // This is the minimum number of bytes below which the array is padded with zeros up
41 // to this number of bytes to allow Blosc to perform compression with small arrays
42 static const int BLOSC_PAD_BYTES = 128;
43 
44 
45 /// @brief Returns true if compression is available
47 
48 /// @brief Retrieves the uncompressed size of buffer when uncompressed
49 ///
50 /// @param buffer the compressed buffer
51 OPENVDB_API size_t bloscUncompressedSize(const char* buffer);
52 
53 /// @brief Compress into the supplied buffer.
54 ///
55 /// @param compressedBuffer the buffer to compress
56 /// @param compressedBytes number of compressed bytes
57 /// @param bufferBytes the number of bytes in compressedBuffer available to be filled
58 /// @param uncompressedBuffer the uncompressed buffer to compress
59 /// @param uncompressedBytes number of uncompressed bytes
60 OPENVDB_API void bloscCompress(char* compressedBuffer, size_t& compressedBytes,
61  const size_t bufferBytes, const char* uncompressedBuffer, const size_t uncompressedBytes);
62 
63 /// @brief Compress and return the heap-allocated compressed buffer.
64 ///
65 /// @param buffer the buffer to compress
66 /// @param uncompressedBytes number of uncompressed bytes
67 /// @param compressedBytes number of compressed bytes (written to this variable)
68 /// @param resize the compressed buffer will be exactly resized to remove the
69 /// portion used for Blosc overhead, for efficiency this can be
70 /// skipped if it is known that the resulting buffer is temporary
71 OPENVDB_API std::unique_ptr<char[]> bloscCompress(const char* buffer,
72  const size_t uncompressedBytes, size_t& compressedBytes, const bool resize = true);
73 
74 /// @brief Convenience wrapper to retrieve the compressed size of buffer when compressed
75 ///
76 /// @param buffer the uncompressed buffer
77 /// @param uncompressedBytes number of uncompressed bytes
78 OPENVDB_API size_t bloscCompressedSize(const char* buffer, const size_t uncompressedBytes);
79 
80 /// @brief Decompress into the supplied buffer. Will throw if decompression fails or
81 /// uncompressed buffer has insufficient space in which to decompress.
82 ///
83 /// @param uncompressedBuffer the uncompressed buffer to decompress into
84 /// @param expectedBytes the number of bytes expected once the buffer is decompressed
85 /// @param bufferBytes the number of bytes in uncompressedBuffer available to be filled
86 /// @param compressedBuffer the compressed buffer to decompress
87 OPENVDB_API void bloscDecompress(char* uncompressedBuffer, const size_t expectedBytes,
88  const size_t bufferBytes, const char* compressedBuffer);
89 
90 /// @brief Decompress and return the the heap-allocated uncompressed buffer.
91 ///
92 /// @param buffer the buffer to decompress
93 /// @param expectedBytes the number of bytes expected once the buffer is decompressed
94 /// @param resize the compressed buffer will be exactly resized to remove the
95 /// portion used for Blosc overhead, for efficiency this can be
96 /// skipped if it is known that the resulting buffer is temporary
97 OPENVDB_API std::unique_ptr<char[]> bloscDecompress(const char* buffer,
98  const size_t expectedBytes, const bool resize = true);
99 
100 
101 ////////////////////////////////////////
102 
103 
104 // 1MB = 1048576 Bytes
105 static const int PageSize = 1024 * 1024;
106 
107 
108 /// @brief Stores a variable-size, compressed, delayed-load Page of data
109 /// that is loaded into memory when accessed. Access to the Page is
110 /// thread-safe as loading and decompressing the data is protected by a mutex.
112 {
113 private:
114  struct Info
115  {
116  io::MappedFile::Ptr mappedFile;
118  std::streamoff filepos;
119  long compressedBytes;
120  long uncompressedBytes;
121  }; // Info
122 
123 public:
124  using Ptr = std::shared_ptr<Page>;
125 
126  Page() = default;
127 
128  /// @brief load the Page into memory
129  void load() const;
130 
131  /// @brief Uncompressed bytes of the Paged data, available
132  /// when the header has been read.
133  long uncompressedBytes() const;
134 
135  /// @brief Retrieves a data pointer at the specific @param index
136  /// @note Will force a Page load when called.
137  const char* buffer(const int index) const;
138 
139  /// @brief Read the Page header
140  void readHeader(std::istream&);
141 
142  /// @brief Read the Page buffers. If @a delayed is true, stream
143  /// pointers will be stored to load the data lazily.
144  void readBuffers(std::istream&, bool delayed);
145 
146  /// @brief Test if the data is out-of-core
147  bool isOutOfCore() const;
148 
149 private:
150  /// @brief Convenience method to store a copy of the supplied buffer
151  void copy(const std::unique_ptr<char[]>& temp, int pageSize);
152 
153  /// @brief Decompress and store the supplied data
154  void decompress(const std::unique_ptr<char[]>& temp);
155 
156  /// @brief Thread-safe loading of the data
157  void doLoad() const;
158 
159  std::unique_ptr<Info> mInfo = std::unique_ptr<Info>(new Info);
160  std::unique_ptr<char[]> mData;
161  tbb::spin_mutex mMutex;
162 }; // class Page
163 
164 
165 /// @brief A PageHandle holds a unique ptr to a Page and a specific stream
166 /// pointer to a point within the decompressed Page buffer
168 {
169 public:
170 #if OPENVDB_ABI_VERSION_NUMBER >= 6
171  using Ptr = std::unique_ptr<PageHandle>;
172 #else
173  using Ptr = std::shared_ptr<PageHandle>;
174 #endif
175 
176  /// @brief Create the page handle
177  /// @param page a shared ptr to the page that stores the buffer
178  /// @param index start position of the buffer to be read
179  /// @param size total size of the buffer to be read in bytes
180  PageHandle(const Page::Ptr& page, const int index, const int size);
181 
182  /// @brief Retrieve a reference to the stored page
183  Page& page();
184 
185  /// @brief Return the size of the buffer
186  int size() const { return mSize; }
187 
188  /// @brief Read and return the buffer, loading and decompressing
189  /// the Page if necessary.
190  std::unique_ptr<char[]> read();
191 
192  /// @brief Return a copy of this PageHandle
193  Ptr copy() { return Ptr(new PageHandle(mPage, mIndex, mSize)); }
194 
195 protected:
196  friend class ::TestStreamCompression;
197 
198 private:
199  Page::Ptr mPage;
200  int mIndex = -1;
201  int mSize = 0;
202 }; // class PageHandle
203 
204 
205 /// @brief A Paging wrapper to std::istream that is responsible for reading
206 /// from a given input stream and creating Page objects and PageHandles that
207 /// reference those pages for delayed reading.
209 {
210 public:
211  using Ptr = std::shared_ptr<PagedInputStream>;
212 
213  PagedInputStream() = default;
214 
215  explicit PagedInputStream(std::istream& is);
216 
217  /// @brief Size-only mode tags the stream as only reading size data.
218  void setSizeOnly(bool sizeOnly) { mSizeOnly = sizeOnly; }
219  bool sizeOnly() const { return mSizeOnly; }
220 
221  // @brief Set and get the input stream
222  std::istream& getInputStream() { assert(mIs); return *mIs; }
223  void setInputStream(std::istream& is) { mIs = &is; }
224 
225  /// @brief Creates a PageHandle to access the next @param n bytes of the Page.
226  PageHandle::Ptr createHandle(std::streamsize n);
227 
228  /// @brief Takes a @a pageHandle and updates the referenced page with the
229  /// current stream pointer position and if @a delayed is false performs
230  /// an immediate read of the data.
231  void read(PageHandle::Ptr& pageHandle, std::streamsize n, bool delayed = true);
232 
233 private:
234  int mByteIndex = 0;
235  int mUncompressedBytes = 0;
236  std::istream* mIs = nullptr;
237  Page::Ptr mPage;
238  bool mSizeOnly = false;
239 }; // class PagedInputStream
240 
241 
242 /// @brief A Paging wrapper to std::ostream that is responsible for writing
243 /// from a given output stream at intervals set by the PageSize. As Pages are
244 /// variable in size, they are flushed to disk as soon as sufficiently large.
246 {
247 public:
248  using Ptr = std::shared_ptr<PagedOutputStream>;
249 
251 
252  explicit PagedOutputStream(std::ostream& os);
253 
254  /// @brief Size-only mode tags the stream as only writing size data.
255  void setSizeOnly(bool sizeOnly) { mSizeOnly = sizeOnly; }
256  bool sizeOnly() const { return mSizeOnly; }
257 
258  /// @brief Set and get the output stream
259  std::ostream& getOutputStream() { assert(mOs); return *mOs; }
260  void setOutputStream(std::ostream& os) { mOs = &os; }
261 
262  /// @brief Writes the given @param str buffer of size @param n
263  PagedOutputStream& write(const char* str, std::streamsize n);
264 
265  /// @brief Manually flushes the current page to disk if non-zero
266  void flush();
267 
268 private:
269  /// @brief Compress the @param buffer of @param size bytes and write
270  /// out to the stream.
271  void compressAndWrite(const char* buffer, size_t size);
272 
273  /// @brief Resize the internal page buffer to @param size bytes
274  void resize(size_t size);
275 
276  std::unique_ptr<char[]> mData = std::unique_ptr<char[]>(new char[PageSize]);
277  std::unique_ptr<char[]> mCompressedData = nullptr;
278  size_t mCapacity = PageSize;
279  int mBytes = 0;
280  std::ostream* mOs = nullptr;
281  bool mSizeOnly = false;
282 }; // class PagedOutputStream
283 
284 
285 } // namespace compression
286 } // namespace OPENVDB_VERSION_NAME
287 } // namespace openvdb
288 
289 #endif // OPENVDB_TOOLS_STREAM_COMPRESSION_HAS_BEEN_INCLUDED
GLsizeiptr size
Definition: glew.h:1681
GLuint index
Definition: glew.h:1814
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only reading size data.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:166
SharedPtr< MappedFile > Ptr
Definition: io.h:136
A Paging wrapper to std::istream that is responsible for reading from a given input stream and creati...
void read(T &in, bool &v)
Definition: ImfXdr.h:611
std::ostream & getOutputStream()
Set and get the output stream.
void setSizeOnly(bool sizeOnly)
Size-only mode tags the stream as only writing size data.
std::shared_ptr< T > SharedPtr
Definition: Types.h:91
A PageHandle holds a unique ptr to a Page and a specific stream pointer to a point within the decompr...
#define OPENVDB_API
Helper macros for defining library symbol visibility.
Definition: Platform.h:230
GLuint buffer
Definition: glew.h:1680
GLsizei n
Definition: glew.h:4040
OPENVDB_API void bloscDecompress(char *uncompressedBuffer, const size_t expectedBytes, const size_t bufferBytes, const char *compressedBuffer)
Decompress into the supplied buffer. Will throw if decompression fails or uncompressed buffer has ins...
ImageBuf OIIO_API resize(const ImageBuf &src, string_view filtername="", float filterwidth=0.0f, ROI roi={}, int nthreads=0)
Ptr copy()
Return a copy of this PageHandle.
OPENVDB_API void bloscCompress(char *compressedBuffer, size_t &compressedBytes, const size_t bufferBytes, const char *uncompressedBuffer, const size_t uncompressedBytes)
Compress into the supplied buffer.
int size() const
Return the size of the buffer.
Stores a variable-size, compressed, delayed-load Page of data that is loaded into memory when accesse...
OPENVDB_API size_t bloscCompressedSize(const char *buffer, const size_t uncompressedBytes)
Convenience wrapper to retrieve the compressed size of buffer when compressed.
OIIO_API bool copy(string_view from, string_view to, std::string &err)
OPENVDB_API bool bloscCanCompress()
Returns true if compression is available.
A Paging wrapper to std::ostream that is responsible for writing from a given output stream at interv...
OPENVDB_API size_t bloscUncompressedSize(const char *buffer)
Retrieves the uncompressed size of buffer when uncompressed.
void write(T &out, bool v)
Definition: ImfXdr.h:332
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:112