mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
StackBufBuilder
This commit is contained in:
parent
ce0dd5aec9
commit
871d923401
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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(...))
|
||||
|
@ -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;
|
||||
|
19
db/key.cpp
19
db/key.cpp
@ -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 {
|
||||
|
5
db/key.h
5
db/key.h
@ -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
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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 >();
|
||||
|
Loading…
Reference in New Issue
Block a user