From ed154f6dc4f5ca82f20d2f3d4383cdbb07872594 Mon Sep 17 00:00:00 2001 From: "gabor@google.com" Date: Thu, 30 Jun 2011 23:17:03 +0000 Subject: [PATCH] Fixed a snappy compression wrapper bug (passing wrong variable). Change atomic_pointer.h to prefer a memory barrier based implementation over a based implementation for the following reasons: (1) On a x86-32-bit gcc-4.4 build, was corrupting the AtomicPointer. (2) On a x86-64-bit gcc build, a based acquire-load takes ~15ns as opposed to the ~1ns for a memory-barrier based implementation. Fixes issue 9 (corruption_test fails) http://code.google.com/p/leveldb/issues/detail?id=9 Fixes issue 16 (CorruptionTest.MissingDescriptor fails) http://code.google.com/p/leveldb/issues/detail?id=16 git-svn-id: https://leveldb.googlecode.com/svn/trunk@36 62dab493-f737-651d-591e-8d6aee1b9529 --- port/atomic_pointer.h | 254 +++++++++++++++--------------------------- port/port_posix.h | 2 +- 2 files changed, 89 insertions(+), 167 deletions(-) diff --git a/port/atomic_pointer.h b/port/atomic_pointer.h index 3bae00717..7659840c1 100644 --- a/port/atomic_pointer.h +++ b/port/atomic_pointer.h @@ -4,30 +4,101 @@ // AtomicPointer provides storage for a lock-free pointer. // Platform-dependent implementation of AtomicPointer: +// - If the platform provides a cheap barrier, we use it with raw pointers // - If cstdatomic is present (on newer versions of gcc, it is), we use -// a cstdatomic-based AtomicPointer -// - If it is not, we define processor-dependent AtomicWord operations, -// and then use them to build AtomicPointer -// +// a cstdatomic-based AtomicPointer. However we prefer the memory +// barrier based version, because at least on a gcc 4.4 32-bit build +// on linux, we have encountered a buggy +// implementation. Also, some implementations are much +// slower than a memory-barrier based implementation (~16ns for +// based acquire-load vs. ~1ns for a barrier based +// acquire-load). // This code is based on atomicops-internals-* in Google's perftools: // http://code.google.com/p/google-perftools/source/browse/#svn%2Ftrunk%2Fsrc%2Fbase #ifndef PORT_ATOMIC_POINTER_H_ #define PORT_ATOMIC_POINTER_H_ -#ifdef LEVELDB_CSTDATOMIC_PRESENT - -/////////////////////////////////////////////////////////////////////////////// -// WE HAVE -// Use a -based AtomicPointer - -#include #include +#ifdef LEVELDB_CSTDATOMIC_PRESENT +#include +#endif +#ifdef OS_WIN +#include +#endif +#ifdef OS_MACOSX +#include +#endif + +#if defined(_M_X64) || defined(__x86_64__) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) +#define ARCH_CPU_X86_FAMILY 1 +#elif defined(__ARMEL__) +#define ARCH_CPU_ARM_FAMILY 1 +#endif namespace leveldb { namespace port { -// Storage for a lock-free pointer +// Define MemoryBarrier() if available +// Windows on x86 +#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) +// windows.h already provides a MemoryBarrier(void) macro +// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Gcc on x86 +#elif defined(__GNUC__) && defined(ARCH_CPU_X86_FAMILY) +inline void MemoryBarrier() { + // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on + // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. + __asm__ __volatile__("" : : : "memory"); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// Mac OS +#elif defined(OS_MACOSX) +inline void MemoryBarrier() { + OSMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +// ARM +#elif defined(ARCH_CPU_ARM_FAMILY) +typedef void (*LinuxKernelMemoryBarrierFunc)(void); +LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) = + (LinuxKernelMemoryBarrierFunc) 0xffff0fa0; +inline void MemoryBarrier() { + pLinuxKernelMemoryBarrier(); +} +#define LEVELDB_HAVE_MEMORY_BARRIER + +#endif + +// AtomicPointer built using platform-specific MemoryBarrier() +#if defined(LEVELDB_HAVE_MEMORY_BARRIER) +class AtomicPointer { + private: + void* rep_; + public: + AtomicPointer() { } + explicit AtomicPointer(void* p) : rep_(p) {} + inline void* NoBarrier_Load() const { return rep_; } + inline void NoBarrier_Store(void* v) { rep_ = v; } + inline void* Acquire_Load() const { + void* result = rep_; + MemoryBarrier(); + return result; + } + inline void Release_Store(void* v) { + MemoryBarrier(); + rep_ = v; + } +}; + +// AtomicPointer based on +#elif defined(LEVELDB_CSTDATOMIC_PRESENT) class AtomicPointer { private: std::atomic rep_; @@ -48,166 +119,17 @@ class AtomicPointer { } }; -} // namespace leveldb::port -} // namespace leveldb - +// We have neither MemoryBarrier(), nor #else -/////////////////////////////////////////////////////////////////////////////// -// NO -// The entire rest of this file covers that case +#error Please implement AtomicPointer for this platform. -#if defined(_M_X64) || defined(__x86_64__) -#define ARCH_CPU_X86_FAMILY 1 -#elif defined(_M_IX86) || defined(__i386__) || defined(__i386) -#define ARCH_CPU_X86_FAMILY 1 -#elif defined(__ARMEL__) -#define ARCH_CPU_ARM_FAMILY 1 -#else -#warning Please add support for your architecture in atomicpointer.h #endif -namespace leveldb { -namespace port { -namespace internal { - -// AtomicWord is a machine-sized pointer. -typedef intptr_t AtomicWord; - -} // namespace leveldb::port::internal -} // namespace leveldb::port -} // namespace leveldb - -// Include our platform specific implementation. -/////////////////////////////////////////////////////////////////////////////// -// Windows on x86 -#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY) - -// void MemoryBarrier(void) macro is defined in windows.h: -// http://msdn.microsoft.com/en-us/library/ms684208(v=vs.85).aspx -// Including windows.h here; MemoryBarrier() gets used below. -#include - -/////////////////////////////////////////////////////////////////////////////// -// Mac OS on x86 -#elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY) - -#include - -namespace leveldb { -namespace port { -namespace internal { - -inline void MemoryBarrier() { -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - // See http://gcc.gnu.org/ml/gcc/2003-04/msg01180.html for a discussion on - // this idiom. Also see http://en.wikipedia.org/wiki/Memory_ordering. - __asm__ __volatile__("" : : : "memory"); -#else - OSMemoryBarrier(); -#endif -} - -} // namespace leveldb::port::internal -} // namespace leveldb::port -} // namespace leveldb - -/////////////////////////////////////////////////////////////////////////////// -// Any x86 CPU -#elif defined(ARCH_CPU_X86_FAMILY) - -namespace leveldb { -namespace port { -namespace internal { - -inline void MemoryBarrier() { - __asm__ __volatile__("" : : : "memory"); -} - -} // namespace leveldb::port::internal -} // namespace leveldb::port -} // namespace leveldb - -#undef ATOMICOPS_COMPILER_BARRIER - -/////////////////////////////////////////////////////////////////////////////// -// ARM -#elif defined(ARCH_CPU_ARM_FAMILY) - -namespace leveldb { -namespace port { -namespace internal { - -typedef void (*LinuxKernelMemoryBarrierFunc)(void); -LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) = - (LinuxKernelMemoryBarrierFunc) 0xffff0fa0; - -inline void MemoryBarrier() { - pLinuxKernelMemoryBarrier(); -} - -} // namespace leveldb::port::internal -} // namespace leveldb::port -} // namespace leveldb - -#else -#error "Atomic operations are not supported on your platform" -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Implementation of AtomicPointer based on MemoryBarriers above - -namespace leveldb { -namespace port { -namespace internal { - -// Atomic operations using per-system MemoryBarrier()s - -inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) { - AtomicWord value = *ptr; - MemoryBarrier(); - return value; -} - -inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) { - MemoryBarrier(); - *ptr = value; -} - -inline AtomicWord NoBarrier_Load(volatile const AtomicWord* ptr) { - return *ptr; -} - -inline void NoBarrier_Store(volatile AtomicWord* ptr, AtomicWord value) { - *ptr = value; -} - -} // namespace leveldb::port::internal - -// AtomicPointer definition for systems without . -class AtomicPointer { - private: - typedef internal::AtomicWord Rep; - Rep rep_; - public: - AtomicPointer() { } - explicit AtomicPointer(void* p) : rep_(reinterpret_cast(p)) {} - inline void* Acquire_Load() const { - return reinterpret_cast(internal::Acquire_Load(&rep_)); - } - inline void Release_Store(void* v) { - internal::Release_Store(&rep_, reinterpret_cast(v)); - } - inline void* NoBarrier_Load() const { - return reinterpret_cast(internal::NoBarrier_Load(&rep_)); - } - inline void NoBarrier_Store(void* v) { - internal::NoBarrier_Store(&rep_, reinterpret_cast(v)); - } -}; +#undef LEVELDB_HAVE_MEMORY_BARRIER +#undef ARCH_CPU_X86_FAMILY +#undef ARCH_CPU_ARM_FAMILY } // namespace leveldb::port } // namespace leveldb -#endif // LEVELDB_CSTDATOMIC_PRESENT - #endif // PORT_ATOMIC_POINTER_H_ diff --git a/port/port_posix.h b/port/port_posix.h index 3f329f0f8..2995026f5 100644 --- a/port/port_posix.h +++ b/port/port_posix.h @@ -97,7 +97,7 @@ inline bool Snappy_Uncompress(const char* input_data, size_t input_length, ::std::string* output) { #ifdef SNAPPY size_t ulength; - if (!snappy::GetUncompressedLength(input_data, ulength, &ulength)) { + if (!snappy::GetUncompressedLength(input_data, input_length, &ulength)) { return false; } output->resize(ulength);