Skip to content

Commit 08032ef

Browse files
committed
core: add reusable slab allocator
1 parent a58659c commit 08032ef

3 files changed

Lines changed: 178 additions & 0 deletions

File tree

node.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
'src/node_zlib.cc',
8585
'src/pipe_wrap.cc',
8686
'src/stream_wrap.cc',
87+
'src/slab_allocator.cc',
8788
'src/tcp_wrap.cc',
8889
'src/timer_wrap.cc',
8990
'src/tty_wrap.cc',
@@ -107,6 +108,7 @@
107108
'src/node_version.h',
108109
'src/pipe_wrap.h',
109110
'src/req_wrap.h',
111+
'src/slab_allocator.h',
110112
'src/stream_wrap.h',
111113
'src/v8_typed_array.h',
112114
'deps/http_parser/http_parser.h',

src/slab_allocator.cc

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
#include "v8.h"
23+
#include "node.h"
24+
#include "node_buffer.h"
25+
#include "slab_allocator.h"
26+
#include <stdio.h>
27+
#include <stdlib.h>
28+
#include <assert.h>
29+
30+
31+
using v8::Handle;
32+
using v8::HandleScope;
33+
using v8::Integer;
34+
using v8::Local;
35+
using v8::Null;
36+
using v8::Object;
37+
using v8::Persistent;
38+
using v8::String;
39+
using v8::Value;
40+
41+
42+
namespace node {
43+
44+
SlabAllocator::SlabAllocator(unsigned int size) {
45+
size_ = ROUND_UP(size ? size : 1, 8192);
46+
initialized_ = false;
47+
}
48+
49+
50+
SlabAllocator::~SlabAllocator() {
51+
if (!initialized_) return;
52+
slab_sym_.Clear();
53+
slab_sym_.Dispose();
54+
slab_.Clear();
55+
slab_.Dispose();
56+
}
57+
58+
59+
void SlabAllocator::Initialize() {
60+
HandleScope scope;
61+
char sym[256];
62+
snprintf(sym, sizeof(sym), "slab_%p", this); // namespace object key
63+
offset_ = 0;
64+
last_ptr_ = NULL;
65+
initialized_ = true;
66+
slab_sym_ = Persistent<String>::New(String::New(sym));
67+
}
68+
69+
70+
static Local<Object> NewSlab(unsigned int size) {
71+
HandleScope scope;
72+
Local<Value> arg = Integer::NewFromUnsigned(ROUND_UP(size, 16));
73+
Local<Object> buf = Buffer::constructor_template
74+
->GetFunction()
75+
->NewInstance(1, &arg);
76+
return scope.Close(buf);
77+
}
78+
79+
80+
char* SlabAllocator::Allocate(Handle<Object> obj, unsigned int size) {
81+
HandleScope scope;
82+
83+
assert(!obj.IsEmpty());
84+
85+
if (size == 0) return NULL;
86+
if (!initialized_) Initialize();
87+
88+
if (size > size_) {
89+
Local<Object> buf = NewSlab(size);
90+
obj->SetHiddenValue(slab_sym_, buf);
91+
return Buffer::Data(buf);
92+
}
93+
94+
if (slab_.IsEmpty() || offset_ + size > size_) {
95+
slab_.Clear();
96+
slab_.Dispose();
97+
slab_ = Persistent<Object>::New(NewSlab(size_));
98+
offset_ = 0;
99+
last_ptr_ = NULL;
100+
}
101+
102+
obj->SetHiddenValue(slab_sym_, slab_);
103+
last_ptr_ = Buffer::Data(slab_) + offset_;
104+
offset_ += size;
105+
106+
return last_ptr_;
107+
}
108+
109+
110+
Local<Object> SlabAllocator::Shrink(Handle<Object> obj,
111+
char* ptr,
112+
unsigned int size) {
113+
HandleScope scope;
114+
Local<Value> slab_v = obj->GetHiddenValue(slab_sym_);
115+
obj->SetHiddenValue(slab_sym_, Null());
116+
assert(!slab_v.IsEmpty());
117+
assert(slab_v->IsObject());
118+
Local<Object> slab = slab_v->ToObject();
119+
if (ptr && ptr == last_ptr_) {
120+
last_ptr_ = NULL;
121+
offset_ = ptr - Buffer::Data(slab) + ROUND_UP(size, 16);
122+
}
123+
return scope.Close(slab);
124+
}
125+
126+
127+
} // namespace node

src/slab_allocator.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright Joyent, Inc. and other Node contributors.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a
4+
// copy of this software and associated documentation files (the
5+
// "Software"), to deal in the Software without restriction, including
6+
// without limitation the rights to use, copy, modify, merge, publish,
7+
// distribute, sublicense, and/or sell copies of the Software, and to permit
8+
// persons to whom the Software is furnished to do so, subject to the
9+
// following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included
12+
// in all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15+
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17+
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
22+
#include "v8.h"
23+
24+
namespace node {
25+
26+
class SlabAllocator {
27+
public:
28+
SlabAllocator(unsigned int size = 10485760); // default to 10M
29+
~SlabAllocator();
30+
31+
// allocate memory from slab, attaches the slice to `obj`
32+
char* Allocate(v8::Handle<v8::Object> obj, unsigned int size);
33+
34+
// return excess memory to the slab, returns a handle to the parent buffer
35+
v8::Local<v8::Object> Shrink(v8::Handle<v8::Object> obj,
36+
char* ptr,
37+
unsigned int size);
38+
39+
private:
40+
void Initialize();
41+
bool initialized_;
42+
v8::Persistent<v8::Object> slab_;
43+
v8::Persistent<v8::String> slab_sym_;
44+
unsigned int offset_;
45+
unsigned int size_;
46+
char* last_ptr_;
47+
};
48+
49+
} // namespace node

0 commit comments

Comments
 (0)