port_posix.h 11.2 KB
Newer Older
1 2 3 4 5
//  Copyright (c) 2013, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
J
jorlow@chromium.org 已提交
6 7 8 9 10 11 12 13 14
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
//
// See port_example.h for documentation for the following types/functions.

#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_
#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_

H
heyongqiang 已提交
15
#undef PLATFORM_IS_LITTLE_ENDIAN
16
#if defined(OS_MACOSX)
17
  #include <machine/endian.h>
H
heyongqiang 已提交
18 19 20 21
  #if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER)
    #define PLATFORM_IS_LITTLE_ENDIAN \
        (__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
  #endif
22 23 24
#elif defined(OS_SOLARIS)
  #include <sys/isa_defs.h>
  #ifdef _LITTLE_ENDIAN
H
heyongqiang 已提交
25
    #define PLATFORM_IS_LITTLE_ENDIAN true
26
  #else
H
heyongqiang 已提交
27
    #define PLATFORM_IS_LITTLE_ENDIAN false
28
  #endif
29
#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
H
heyongqiang 已提交
30
      defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
31 32
  #include <sys/types.h>
  #include <sys/endian.h>
33 34 35
#else
  #include <endian.h>
#endif
J
jorlow@chromium.org 已提交
36
#include <pthread.h>
37 38 39
#ifdef SNAPPY
#include <snappy.h>
#endif
H
heyongqiang 已提交
40

H
heyongqiang 已提交
41 42 43
#ifdef ZLIB
#include <zlib.h>
#endif
H
heyongqiang 已提交
44 45 46 47 48

#ifdef BZIP2
#include <bzlib.h>
#endif

J
jorlow@chromium.org 已提交
49 50
#include <stdint.h>
#include <string>
H
heyongqiang 已提交
51
#include <string.h>
52
#include "rocksdb/options.h"
53 54
#include "port/atomic_pointer.h"

H
heyongqiang 已提交
55 56
#ifndef PLATFORM_IS_LITTLE_ENDIAN
#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
57 58
#endif

59
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
H
heyongqiang 已提交
60 61
    defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
    defined(OS_ANDROID)
62
// Use fread/fwrite/fflush on platforms without _unlocked variants
63 64 65 66 67
#define fread_unlocked fread
#define fwrite_unlocked fwrite
#define fflush_unlocked fflush
#endif

68 69 70
#if defined(OS_MACOSX) || defined(OS_FREEBSD) ||\
    defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)
// Use fsync() on platforms without fdatasync()
71 72
#define fdatasync fsync
#endif
J
jorlow@chromium.org 已提交
73

H
heyongqiang 已提交
74 75 76 77 78 79
#if defined(OS_ANDROID) && __ANDROID_API__ < 9
// fdatasync() was only introduced in API level 9 on Android. Use fsync()
// when targetting older platforms.
#define fdatasync fsync
#endif

80
namespace rocksdb {
J
jorlow@chromium.org 已提交
81 82
namespace port {

H
heyongqiang 已提交
83 84
static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN;
#undef PLATFORM_IS_LITTLE_ENDIAN
J
jorlow@chromium.org 已提交
85 86 87 88 89

class CondVar;

class Mutex {
 public:
90
  /* implicit */ Mutex(bool adaptive = false);
J
jorlow@chromium.org 已提交
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  ~Mutex();

  void Lock();
  void Unlock();
  void AssertHeld() { }

 private:
  friend class CondVar;
  pthread_mutex_t mu_;

  // No copying
  Mutex(const Mutex&);
  void operator=(const Mutex&);
};

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
class RWMutex {
 public:
  RWMutex();
  ~RWMutex();

  void ReadLock();
  void WriteLock();
  void Unlock();
  void AssertHeld() { }

 private:
  pthread_rwlock_t mu_; // the underlying platform mutex

  // No copying allowed
  RWMutex(const RWMutex&);
  void operator=(const RWMutex&);
};

J
jorlow@chromium.org 已提交
124 125 126 127 128 129 130 131 132 133 134 135
class CondVar {
 public:
  explicit CondVar(Mutex* mu);
  ~CondVar();
  void Wait();
  void Signal();
  void SignalAll();
 private:
  pthread_cond_t cv_;
  Mutex* mu_;
};

H
heyongqiang 已提交
136 137 138 139
typedef pthread_once_t OnceType;
#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT
extern void InitOnce(OnceType* once, void (*initializer)());

140 141
inline bool Snappy_Compress(const CompressionOptions& opts, const char* input,
                            size_t length, ::std::string* output) {
142
#ifdef SNAPPY
143
  output->resize(snappy::MaxCompressedLength(length));
144
  size_t outlen;
145
  snappy::RawCompress(input, length, &(*output)[0], &outlen);
146 147 148 149
  output->resize(outlen);
  return true;
#endif

J
jorlow@chromium.org 已提交
150
  return false;
J
jorlow@chromium.org 已提交
151 152
}

153 154
inline bool Snappy_GetUncompressedLength(const char* input, size_t length,
                                         size_t* result) {
155
#ifdef SNAPPY
156 157 158
  return snappy::GetUncompressedLength(input, length, result);
#else
  return false;
159
#endif
160
}
161

162 163 164 165 166
inline bool Snappy_Uncompress(const char* input, size_t length,
                              char* output) {
#ifdef SNAPPY
  return snappy::RawUncompress(input, length, output);
#else
J
jorlow@chromium.org 已提交
167
  return false;
168
#endif
J
jorlow@chromium.org 已提交
169 170
}

171 172
inline bool Zlib_Compress(const CompressionOptions& opts, const char* input,
                          size_t length, ::std::string* output) {
H
heyongqiang 已提交
173 174 175 176 177 178 179 180 181
#ifdef ZLIB
  // The memLevel parameter specifies how much memory should be allocated for
  // the internal compression state.
  // memLevel=1 uses minimum memory but is slow and reduces compression ratio.
  // memLevel=9 uses maximum memory for optimal speed.
  // The default value is 8. See zconf.h for more details.
  static const int memLevel = 8;
  z_stream _stream;
  memset(&_stream, 0, sizeof(z_stream));
182 183
  int st = deflateInit2(&_stream, opts.level, Z_DEFLATED, opts.window_bits,
                        memLevel, opts.strategy);
H
heyongqiang 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
  if (st != Z_OK) {
    return false;
  }

  // Resize output to be the plain data length.
  // This may not be big enough if the compression actually expands data.
  output->resize(length);

  // Compress the input, and put compressed data in output.
  _stream.next_in = (Bytef *)input;
  _stream.avail_in = length;

  // Initialize the output size.
  _stream.avail_out = length;
  _stream.next_out = (Bytef *)&(*output)[0];

200 201 202
  int old_sz =0, new_sz =0, new_sz_delta =0;
  bool done = false;
  while (!done) {
H
heyongqiang 已提交
203 204 205
    int st = deflate(&_stream, Z_FINISH);
    switch (st) {
      case Z_STREAM_END:
206
        done = true;
H
heyongqiang 已提交
207 208 209 210 211
        break;
      case Z_OK:
        // No output space. Increase the output space by 20%.
        // (Should we fail the compression since it expands the size?)
        old_sz = output->size();
212 213
        new_sz_delta = (int)(output->size() * 0.2);
        new_sz = output->size() + (new_sz_delta < 10 ? 10 : new_sz_delta);
H
heyongqiang 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
        output->resize(new_sz);
        // Set more output.
        _stream.next_out = (Bytef *)&(*output)[old_sz];
        _stream.avail_out = new_sz - old_sz;
        break;
      case Z_BUF_ERROR:
      default:
        deflateEnd(&_stream);
        return false;
    }
  }

  output->resize(output->size() - _stream.avail_out);
  deflateEnd(&_stream);
  return true;
#endif
  return false;
}

inline char* Zlib_Uncompress(const char* input_data, size_t input_length,
234
    int* decompress_size, int windowBits = -14) {
H
heyongqiang 已提交
235 236 237 238
#ifdef ZLIB
  z_stream _stream;
  memset(&_stream, 0, sizeof(z_stream));

239
  // For raw inflate, the windowBits should be -8..-15.
H
heyongqiang 已提交
240 241 242 243 244
  // If windowBits is bigger than zero, it will use either zlib
  // header or gzip header. Adding 32 to it will do automatic detection.
  int st = inflateInit2(&_stream,
      windowBits > 0 ? windowBits + 32 : windowBits);
  if (st != Z_OK) {
245
    return nullptr;
H
heyongqiang 已提交
246 247 248 249 250 251 252 253 254 255 256 257 258
  }

  _stream.next_in = (Bytef *)input_data;
  _stream.avail_in = input_length;

  // Assume the decompressed data size will 5x of compressed size.
  int output_len = input_length * 5;
  char* output = new char[output_len];
  int old_sz = output_len;

  _stream.next_out = (Bytef *)output;
  _stream.avail_out = output_len;

259 260 261
  char* tmp = nullptr;
  int output_len_delta;
  bool done = false;
H
heyongqiang 已提交
262

263 264
  //while(_stream.next_in != nullptr && _stream.avail_in != 0) {
  while (!done) {
H
heyongqiang 已提交
265 266 267
    int st = inflate(&_stream, Z_SYNC_FLUSH);
    switch (st) {
      case Z_STREAM_END:
268
        done = true;
H
heyongqiang 已提交
269 270 271 272
        break;
      case Z_OK:
        // No output space. Increase the output space by 20%.
        old_sz = output_len;
273 274
        output_len_delta = (int)(output_len * 0.2);
        output_len += output_len_delta < 10 ? 10 : output_len_delta;
H
heyongqiang 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287
        tmp = new char[output_len];
        memcpy(tmp, output, old_sz);
        delete[] output;
        output = tmp;

        // Set more output.
        _stream.next_out = (Bytef *)(output + old_sz);
        _stream.avail_out = output_len - old_sz;
        break;
      case Z_BUF_ERROR:
      default:
        delete[] output;
        inflateEnd(&_stream);
288
        return nullptr;
H
heyongqiang 已提交
289 290 291 292 293 294 295 296
    }
  }

  *decompress_size = output_len - _stream.avail_out;
  inflateEnd(&_stream);
  return output;
#endif

297
  return nullptr;
H
heyongqiang 已提交
298 299
}

300 301
inline bool BZip2_Compress(const CompressionOptions& opts, const char* input,
                           size_t length, ::std::string* output) {
H
heyongqiang 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
#ifdef BZIP2
  bz_stream _stream;
  memset(&_stream, 0, sizeof(bz_stream));

  // Block size 1 is 100K.
  // 0 is for silent.
  // 30 is the default workFactor
  int st = BZ2_bzCompressInit(&_stream, 1, 0, 30);
  if (st != BZ_OK) {
    return false;
  }

  // Resize output to be the plain data length.
  // This may not be big enough if the compression actually expands data.
  output->resize(length);

  // Compress the input, and put compressed data in output.
  _stream.next_in = (char *)input;
  _stream.avail_in = length;

  // Initialize the output size.
  _stream.next_out = (char *)&(*output)[0];
  _stream.avail_out = length;

  int old_sz =0, new_sz =0;
327
  while(_stream.next_in != nullptr && _stream.avail_in != 0) {
H
heyongqiang 已提交
328 329 330 331 332 333 334 335
    int st = BZ2_bzCompress(&_stream, BZ_FINISH);
    switch (st) {
      case BZ_STREAM_END:
        break;
      case BZ_FINISH_OK:
        // No output space. Increase the output space by 20%.
        // (Should we fail the compression since it expands the size?)
        old_sz = output->size();
H
heyongqiang 已提交
336
        new_sz = (int)(output->size() * 1.2);
H
heyongqiang 已提交
337 338 339 340 341
        output->resize(new_sz);
        // Set more output.
        _stream.next_out = (char *)&(*output)[old_sz];
        _stream.avail_out = new_sz - old_sz;
        break;
I
Igor Canadi 已提交
342
      case BZ_SEQUENCE_ERROR:
H
heyongqiang 已提交
343 344 345 346 347 348 349 350 351 352
      default:
        BZ2_bzCompressEnd(&_stream);
        return false;
    }
  }

  output->resize(output->size() - _stream.avail_out);
  BZ2_bzCompressEnd(&_stream);
  return true;
#endif
H
heyongqiang 已提交
353
  return false;
H
heyongqiang 已提交
354 355 356 357 358 359 360 361 362 363
}

inline char*  BZip2_Uncompress(const char* input_data, size_t input_length,
    int* decompress_size) {
#ifdef BZIP2
  bz_stream _stream;
  memset(&_stream, 0, sizeof(bz_stream));

  int st = BZ2_bzDecompressInit(&_stream, 0, 0);
  if (st != BZ_OK) {
364
    return nullptr;
H
heyongqiang 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377
  }

  _stream.next_in = (char *)input_data;
  _stream.avail_in = input_length;

  // Assume the decompressed data size will be 5x of compressed size.
  int output_len = input_length * 5;
  char* output = new char[output_len];
  int old_sz = output_len;

  _stream.next_out = (char *)output;
  _stream.avail_out = output_len;

378
  char* tmp = nullptr;
H
heyongqiang 已提交
379

380
  while(_stream.next_in != nullptr && _stream.avail_in != 0) {
H
heyongqiang 已提交
381 382 383 384
    int st = BZ2_bzDecompress(&_stream);
    switch (st) {
      case BZ_STREAM_END:
        break;
I
Igor Canadi 已提交
385
      case BZ_OK:
H
heyongqiang 已提交
386 387
        // No output space. Increase the output space by 20%.
        old_sz = output_len;
H
heyongqiang 已提交
388
        output_len = (int)(output_len * 1.2);
H
heyongqiang 已提交
389 390 391 392 393 394 395 396 397 398 399 400
        tmp = new char[output_len];
        memcpy(tmp, output, old_sz);
        delete[] output;
        output = tmp;

        // Set more output.
        _stream.next_out = (char *)(output + old_sz);
        _stream.avail_out = output_len - old_sz;
        break;
      default:
        delete[] output;
        BZ2_bzDecompressEnd(&_stream);
401
        return nullptr;
H
heyongqiang 已提交
402 403 404 405 406 407 408
    }
  }

  *decompress_size = output_len - _stream.avail_out;
  BZ2_bzDecompressEnd(&_stream);
  return output;
#endif
409
  return nullptr;
H
heyongqiang 已提交
410 411
}

J
jorlow@chromium.org 已提交
412 413 414 415
inline bool GetHeapProfile(void (*func)(void*, const char*, int), void* arg) {
  return false;
}

416
} // namespace port
417
} // namespace rocksdb
J
jorlow@chromium.org 已提交
418 419

#endif  // STORAGE_LEVELDB_PORT_PORT_POSIX_H_