diff --git a/util/alignedbuilder.cpp b/util/alignedbuilder.cpp index 59ba2b564b5..efde68a7236 100644 --- a/util/alignedbuilder.cpp +++ b/util/alignedbuilder.cpp @@ -21,59 +21,64 @@ namespace mongo { - AlignedBuilder::AlignedBuilder(unsigned init_size) : _size(init_size) { - _data = (char *) _malloc(_size); - if( _data == 0 ) - uasserted(13584, "out of memory AlignedBuilder"); + AlignedBuilder::AlignedBuilder(unsigned initSize) { _len = 0; + _malloc(initSize); + uassert(13584, "out of memory AlignedBuilder", _p._allocationAddress); } - void* AlignedBuilder::mallocSelfAligned(unsigned sz) { + void AlignedBuilder::mallocSelfAligned(unsigned sz) { + assert( sz == _p._size ); void *p = malloc(sz + Alignment - 1); - _realAddr = p; + _p._allocationAddress = p; size_t s = (size_t) p; + size_t sold = s; s += Alignment - 1; s = (s/Alignment)*Alignment; - return (void*) s; + dassert( s >= sold ); + _p._data = (char *) s; } /* "slow"/infrequent portion of 'grow()' */ - void NOINLINE_DECL AlignedBuilder::grow_reallocate() { - unsigned a = _size * 2; + void NOINLINE_DECL AlignedBuilder::growReallocate(unsigned oldLen) { + unsigned a = _p._size; assert( a ); - if ( _len > a ) - a = _len + 16 * 1024; - assert( a < 0x20000000 ); - _data = (char *) _realloc(_data, a, _len); - _size = a; + while( 1 ) { + a *= 2; + assert( a < 0x20000000 ); + if( _len < a ) + break; + } + _realloc(a, oldLen); } - void* AlignedBuilder::_malloc(unsigned sz) { + void AlignedBuilder::_malloc(unsigned sz) { + _p._size = sz; #if defined(_WIN32) void *p = VirtualAlloc(0, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - _realAddr = p; -//#elif defined(_POSIX_VERSION) -// in theory _POSIX_VERSION should work, but it doesn't on OS X 10.4, and needs to be testeed on solaris. -// so for now, linux only for this. + _p._allocationAddress = p; + _p._data = (char *) p; #elif defined(__linux__) + // in theory #ifdef _POSIX_VERSION should work, but it doesn't on OS X 10.4, and needs to be testeed on solaris. + // so for now, linux only for this. void *p = 0; int res = posix_memalign(&p, Alignment, sz); massert(13524, "out of memory AlignedBuilder", res == 0); - _realAddr = p; + _p._allocationAddress = p; + _p._data = (char *) p; #else void *p = mallocSelfAligned(sz); assert( ((size_t) p) % Alignment == 0 ); #endif - return p; } - void* AlignedBuilder::_realloc(void *ptr, unsigned newSize, unsigned oldSize) { - // posix_memalign alignment is not maintained on reallocs - void *oldAddr = _realAddr; - void *p = _malloc(newSize); - memcpy(p, ptr, oldSize); - _free(oldAddr); - return p; + void AlignedBuilder::_realloc(unsigned newSize, unsigned oldLen) { + // posix_memalign alignment is not maintained on reallocs, so we can't use realloc(). + AllocationInfo old = _p; + _malloc(newSize); + assert( oldLen <= _len ); + memcpy(_p._data, old._data, oldLen); + _free(old._allocationAddress); } void AlignedBuilder::_free(void *p) { @@ -85,9 +90,9 @@ namespace mongo { } void AlignedBuilder::kill() { - _free(_realAddr); - _data = 0; - _realAddr = 0; + _free(_p._allocationAddress); + _p._allocationAddress = 0; + _p._data = 0; } } diff --git a/util/alignedbuilder.h b/util/alignedbuilder.h index aa88bf11bb2..12774d8ee3c 100644 --- a/util/alignedbuilder.h +++ b/util/alignedbuilder.h @@ -32,7 +32,7 @@ namespace mongo { void reset() { _len = 0; } /** note this may be deallocated (realloced) if you keep writing or reset(). */ - const char* buf() const { return _data; } + const char* buf() const { return _p._data; } /** leave room for some stuff later @return offset in the buffer that was our current position @@ -43,7 +43,7 @@ namespace mongo { return l; } - char* atOfs(unsigned ofs) { return _data + ofs; } + char* atOfs(unsigned ofs) { return _p._data + ofs; } void appendChar(char j){ *((char*)grow(sizeof(char))) = j; @@ -80,6 +80,7 @@ namespace mongo { void appendStr(const StringData &str , bool includeEOO = true ) { const unsigned len = str.size() + ( includeEOO ? 1 : 0 ); + assert( len < BSONObjMaxUserSize ); memcpy(grow(len), str.data(), len); } @@ -93,23 +94,25 @@ namespace mongo { inline char* grow(unsigned by) { unsigned oldlen = _len; _len += by; - if ( _len > _size ) { - grow_reallocate(); + if ( _len > _p._size ) { + growReallocate(oldlen); } - return _data + oldlen; + return _p._data + oldlen; } - void grow_reallocate(); + void growReallocate(unsigned oldLenInUse); void kill(); - void* mallocSelfAligned(unsigned sz); - void* _malloc(unsigned sz); - void* _realloc(void *ptr, unsigned newSize, unsigned oldSize); + void mallocSelfAligned(unsigned sz); + void _malloc(unsigned sz); + void _realloc(unsigned newSize, unsigned oldLenInUse); void _free(void*); - char *_data; - unsigned _len; - unsigned _size; - void *_realAddr; + struct AllocationInfo { + char *_data; + void *_allocationAddress; + unsigned _size; + } _p; + unsigned _len; // bytes in use }; }