0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

StackBufBuilder

This commit is contained in:
dwight 2011-05-10 12:40:01 -04:00
parent ce0dd5aec9
commit 871d923401
8 changed files with 127 additions and 50 deletions

View File

@ -1,20 +1,19 @@
// inline.h
// inline_decls.h
/**
* Copyright (C) 2010 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Copyright 2010 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

View File

@ -20,8 +20,6 @@
#include <string>
#include <string.h>
#include <stdio.h>
//#include <boost/shared_ptr.hpp>
#include "../inline_decls.h"
#include "../stringdata.h"
@ -49,11 +47,44 @@ namespace mongo {
void msgasserted(int msgid, const char *msg);
class BufBuilder {
class TrivialAllocator {
public:
BufBuilder(int initsize = 512) : size(initsize) {
void* Malloc(size_t sz) { return malloc(sz); }
void* Realloc(void *p, size_t sz) { return realloc(p, sz); }
void Free(void *p) { free(p); }
};
class StackAllocator {
public:
enum { SZ = 512 };
void* Malloc(size_t sz) {
if( sz <= SZ ) return buf;
return malloc(sz);
}
void* Realloc(void *p, size_t sz) {
if( p == buf ) {
if( sz <= SZ ) return buf;
void *d = malloc(sz);
memcpy(d, p, SZ);
return d;
}
return realloc(p, sz);
}
void Free(void *p) {
if( p != buf )
free(p);
}
private:
char buf[SZ];
};
template< class Allocator >
class _BufBuilder : boost::noncopyable {
Allocator al;
public:
_BufBuilder(int initsize = 512) : size(initsize) {
if ( size > 0 ) {
data = (char *) malloc(size);
data = (char *) al.Malloc(size);
if( data == 0 )
msgasserted(10000, "out of memory BufBuilder");
}
@ -62,13 +93,11 @@ namespace mongo {
}
l = 0;
}
~BufBuilder() {
kill();
}
~_BufBuilder() { kill(); }
void kill() {
if ( data ) {
free(data);
al.Free(data);
data = 0;
}
}
@ -79,8 +108,8 @@ namespace mongo {
void reset( int maxSize ) {
l = 0;
if ( maxSize && size > maxSize ) {
free(data);
data = (char*)malloc(maxSize);
al.Free(data);
data = (char*)al.Malloc(maxSize);
size = maxSize;
}
}
@ -168,7 +197,7 @@ namespace mongo {
a = l + 16 * 1024;
if ( a > BufferMaxSize )
msgasserted(13548, "BufBuilder grow() > 64MB");
data = (char *) realloc(data, a);
data = (char *) al.Realloc(data, a);
size= a;
}
@ -179,6 +208,22 @@ namespace mongo {
friend class StringBuilder;
};
template class _BufBuilder<TrivialAllocator>;
typedef _BufBuilder<TrivialAllocator> BufBuilder;
/** The StackBufBuilder builds smaller datasets on the stack instead of using malloc.
this can be significantly faster for small bufs. However, you can not decouple() the
buffer with StackBufBuilder.
While designed to be a variable on the stack, if you were to dynamically allocate one,
nothing bad would happen. In fact in some circumstances this might make sense, say,
embedded in some other object.
*/
class StackBufBuilder : public _BufBuilder<StackAllocator> {
public:
StackBufBuilder() : _BufBuilder<StackAllocator>(StackAllocator::SZ) { }
void decouple(); // not allowed. not implemented.
};
#if defined(_WIN32)
#pragma warning( push )
// warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS.

View File

@ -18,7 +18,6 @@
#pragma once
#include "../pch.h"
#include "jsobj.h"
#include "../util/timer.h"
@ -26,7 +25,6 @@ namespace mongo {
class BSONObj;
class BSONObjBuilder;
class BufBuilder;
class Client;
/** mongodb "commands" (sent via db.$cmd.findOne(...))

View File

@ -24,7 +24,7 @@
namespace mongo {
/* we use new here so we don't have to worry about destructor orders at program shutdown */
MongoMutex &dbMutex( *(new MongoMutex("rw:dbMutex")) );
MongoMutex &dbMutex( *(new MongoMutex("dbMutex")) );
MongoMutex::MongoMutex(const char *name) : _m(name) {
static int n = 0;

View File

@ -68,18 +68,15 @@ namespace mongo {
Given that the KeyV1Owned constructor already grabbed a bufbuilder, we reuse it here
so that we don't have to do an extra malloc.
*/
void KeyV1Owned::traditional(BufBuilder& b, const BSONObj& obj) {
void KeyV1Owned::traditional(const BSONObj& obj) {
b.reset();
b.appendUChar(IsBSON);
b.appendBuf(obj.objdata(), obj.objsize());
_toFree = b.buf();
_keyData = (const unsigned char *) _toFree;
b.decouple();
_keyData = (const unsigned char *) b.buf();
}
// fromBSON to Key format
KeyV1Owned::KeyV1Owned(const BSONObj& obj) {
BufBuilder b(512);
BSONObj::iterator i(obj);
assert( i.more() );
unsigned char bits = 0;
@ -122,7 +119,7 @@ namespace mongo {
break;
}
}
traditional(b, obj);
traditional(obj);
return;
}
case Date:
@ -135,7 +132,7 @@ namespace mongo {
// note we do not store the terminating null, to save space.
unsigned x = (unsigned) e.valuestrsize() - 1;
if( x > 255 ) {
traditional(b, obj);
traditional(obj);
return;
}
b.appendUChar(x);
@ -151,7 +148,7 @@ namespace mongo {
long long n = e._numberLong();
double d = (double) n;
if( d != n ) {
traditional(b, obj);
traditional(obj);
return;
}
b.appendUChar(clong|bits);
@ -172,18 +169,16 @@ namespace mongo {
}
default:
// if other types involved, store as traditional BSON
traditional(b, obj);
traditional(obj);
return;
}
if( !i.more() )
break;
bits = 0;
}
_toFree = b.buf();
_keyData = (const unsigned char *) _toFree;
_keyData = (const unsigned char *) b.buf();
dassert( b.len() == dataSize() ); // check datasize method is correct
dassert( (*_keyData & cNOTUSED) == 0 );
b.decouple();
}
BSONObj KeyV1::toBson() const {

View File

@ -86,11 +86,10 @@ namespace mongo {
it will stay as bson herein.
*/
KeyV1Owned(const BSONObj& obj);
~KeyV1Owned() { free((void*) _toFree); }
private:
KeyV1Owned(const KeyV1Owned&); //not copyable
const char *_toFree;
void traditional(BufBuilder& b, const BSONObj& obj); // store as traditional bson not as compact format
StackBufBuilder b;
void traditional(const BSONObj& obj); // store as traditional bson not as compact format
};
};

View File

@ -18,6 +18,7 @@
*/
#include "pch.h"
#include "../bson/util/builder.h"
#include "../db/jsobj.h"
#include "../db/jsobjmanipulator.h"
#include "../db/json.h"
@ -75,10 +76,18 @@ namespace JsobjTests {
class BufBuilderBasic {
public:
void run() {
BufBuilder b( 0 );
b.appendStr( "foo" );
ASSERT_EQUALS( 4, b.len() );
ASSERT( strcmp( "foo", b.buf() ) == 0 );
{
BufBuilder b( 0 );
b.appendStr( "foo" );
ASSERT_EQUALS( 4, b.len() );
ASSERT( strcmp( "foo", b.buf() ) == 0 );
}
{
mongo::StackBufBuilder b;
b.appendStr( "foo" );
ASSERT_EQUALS( 4, b.len() );
ASSERT( strcmp( "foo", b.buf() ) == 0 );
}
}
};

View File

@ -286,6 +286,36 @@ namespace PerfTests {
}
};
class Bldr : public B {
public:
int n;
string name() { return "BufBuilder"; }
Bldr() {
}
virtual bool showDurStats() { return false; }
void timed() {
BufBuilder b;
b.appendNum(3);
b.appendUChar(' ');
b.appendStr("abcd");
n += b.len();
}
};
class StkBldr : public B {
public:
int n;
string name() { return "StackBufBuilder"; }
virtual bool showDurStats() { return false; }
void timed() {
StackBufBuilder b;
b.appendNum(3);
b.appendUChar(' ');
b.appendStr("abcd");
n += b.len();
}
};
// if a test is this fast, it was optimized out
class Dummy : public B {
public:
@ -553,6 +583,8 @@ namespace PerfTests {
add< Dummy >();
add< TLS >();
add< Malloc >();
add< Bldr >();
add< StkBldr >();
add< BSONIter >();
add< ChecksumTest >();
add< TaskQueueTest >();