Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ You can also [msync()](http://pubs.opengroup.org/onlinepubs/9699919799/functions

For compatibility, <b>mmap.map()</b> is an alias for <b>mmap()</b>

If you wish to use [shared memory](http://en.wikipedia.org/wiki/Shared_memory#In_software) instead of a file, you can do so by calling: `mmap.map_shm(n_bytes, protection, flags, name, offset)` method. All arguments are the same as <b>mmap()<b> except:

<table>
<tr>
<td><i>name</i></td>
<td>Name of the <a href="http://man7.org/linux/man-pages/man7/shm_overview.7.html">POSIX shared memory</a> region. <b>mmap.map_shm()</b> will create and/or attach to the region with read and write permissions, and truncate or expand the region to <b>size</b> bytes.</td>
</tr>
</table>

## See Also

* POSIX 1003.1 [mmap](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html) and [msync](http://pubs.opengroup.org/onlinepubs/9699919799/functions/msync.html)
Expand Down
82 changes: 82 additions & 0 deletions example/bloomwithshm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
fs = require("fs"),
mmap = require("../index.js"); // obv. use require("mmap") if you lift
HASH_FUNCTIONS=7; // how many hashes do you want?

size = 1024*1024; // 1mb
buffer = mmap.map_shm(size, mmap.PROT_READ|mmap.PROT_WRITE, mmap.MAP_SHARED, "/tmp/test_bloom");
add(buffer, get_offsets("testing", buffer.length));
console.log("check: ", check(buffer, get_offsets("testing", buffer.length)));


/* basic bloom filter tricks */
function get_offsets(string, buffer_size) {
var a = fnv_1a(string);
var b = fnv_1a_b(a);
var r = [];
var i = -1;
var x = a % buffer_size;
while (++i < HASH_FUNCTIONS) {
r.push(x < 0 ? (x + buffer_size) : x);
x = (x + b) % buffer_size;
}
return r;
}
function add(buffer, offsets) {
var i = -1;
var w = 0;
while (++i < HASH_FUNCTIONS) w += !!(buffer[ offsets[i] ]++);
if (HASH_FUNCTIONS == w) {
while (i-->0) --buffer[offsets[i]];
return true;
}
return false;
}
function check(buffer, offsets) {
var i = -1;
while (++i < HASH_FUNCTIONS)
if (!buffer[offsets[i]])
return false;
return true;
}

/* fowler-noll-vo (fnv) hashing */
function fnv_1a(v) {
var n = v.length, a = 2166136261, c, d, i = -1;
while (++i < n) {
c = v.charCodeAt(i);
if (d = c & 0xff000000) {
a ^= d >> 24;
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
}
if (d = c & 0xff0000) {
a ^= d >> 16;
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
}
if (d = c & 0xff00) {
a ^= d >> 8;
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
}
a ^= c & 0xff;
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
}
/* from http://home.comcast.net/~bretm/hash/6.html */
a += a << 13;
a ^= a >> 7;
a += a << 3;
a ^= a >> 17;
a += a << 5;
return a & 0xffffffff;
}

/* one additional iteration of fnv, given a hash */
function fnv_1a_b(a) {
a += (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
a += a << 13;
a ^= a >> 7;
a += a << 3;
a ^= a >> 17;
a += a << 5;
return a & 0xffffffff;
}

buffer.unlink();
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ function mmap_wrapper(size, protection, flags, fd, offset) {
};
for(var k in mmap) mmap_wrapper[k] = mmap[k];
mmap_wrapper.map = mmap_wrapper;
mmap_wrapper.map_shm = mmap.map_shm;

module.exports = mmap_wrapper;
55 changes: 55 additions & 0 deletions mmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
static v8::Persistent<v8::String> length_symbol;
static v8::Persistent<v8::String> unmap_symbol;
static v8::Persistent<v8::String> sync_symbol;
static v8::Persistent<v8::String> unlink_symbol;
static v8::Persistent<v8::String> name_symbol;
static v8::Persistent<v8::String> buffer_symbol;

static v8::Persistent<v8::Function> map_symbol;

static void Map_finalise(char *data, void*hint)
{
munmap(data, (size_t)hint);
Expand Down Expand Up @@ -112,6 +116,52 @@ v8::Handle<v8::Value> Map(const v8::Arguments& args)
return scope.Close(actualBuffer);
}

v8::Handle<v8::Value> Unlink(const v8::Arguments& args)
{
v8::HandleScope scope;
v8::String::Utf8Value name(args.This()->GetHiddenValue(name_symbol)->ToString());
if (shm_unlink(*name) < 0)
{
return v8::ThrowException(node::ErrnoException(errno, "unlink", ""));
}
return v8::True();
}

v8::Handle<v8::Value> MapShm(const v8::Arguments& args)
{
v8::HandleScope scope;

if (args.Length() <= 3)
{
return v8::ThrowException(
v8::Exception::Error(
v8::String::New("map_shm() takes 4 arguments: size, protection, flags, name and offset.")));
}

const size_t size = args[0]->ToInteger()->Value();
const v8::String::Utf8Value name(args[3]->ToString());
const int fd = shm_open(*name, O_CREAT | O_RDWR | O_SYNC, 0666);
if (fd < 0)
{
return v8::ThrowException(node::ErrnoException(errno, "map_shm", ""));
}
ftruncate(fd, size);

v8::Handle<v8::Value> *mapArgs = (v8::Handle<v8::Value> *)calloc(sizeof(v8::Handle<v8::Value>), args.Length());
for (int i = 0; i < args.Length(); i++)
mapArgs[i] = args[i];
mapArgs[3] = v8::Integer::New(fd);

v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
v8::Handle<v8::Object> actualBuffer = map_symbol->Call(global, args.Length(), mapArgs)->ToObject();
free(mapArgs);
close(fd);

actualBuffer->ToObject()->Set(unlink_symbol, v8::FunctionTemplate::New(Unlink)->GetFunction());
actualBuffer->SetHiddenValue(name_symbol, v8::String::New(*name));

return scope.Close(actualBuffer);
}

static void RegisterModule(v8::Handle<v8::Object> target)
{
Expand All @@ -120,8 +170,12 @@ static void RegisterModule(v8::Handle<v8::Object> target)
length_symbol = NODE_PSYMBOL("length");
sync_symbol = NODE_PSYMBOL("sync");
unmap_symbol = NODE_PSYMBOL("unmap");
unlink_symbol = NODE_PSYMBOL("unlink");
name_symbol = NODE_PSYMBOL("name");
buffer_symbol = NODE_PSYMBOL("Buffer");

map_symbol = v8::Persistent<v8::Function>::New(v8::FunctionTemplate::New(Map)->GetFunction());

const v8::PropertyAttribute attribs = (v8::PropertyAttribute) (v8::ReadOnly | v8::DontDelete);

target->Set(v8::String::New("PROT_READ"), v8::Integer::New(PROT_READ), attribs);
Expand All @@ -136,6 +190,7 @@ static void RegisterModule(v8::Handle<v8::Object> target)
target->Set(v8::String::New("MS_INVALIDATE"), v8::Integer::New(MS_INVALIDATE), attribs);

target->Set(v8::String::NewSymbol("map"), v8::FunctionTemplate::New(Map)->GetFunction(), attribs);
target->Set(v8::String::NewSymbol("map_shm"), v8::FunctionTemplate::New(MapShm)->GetFunction(), attribs);
}

NODE_MODULE(mmap, RegisterModule);
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "mmap",
"description": "mmap() fds into buffers",
"license": "BSD",
"version": "2.0.2",
"version": "2.1.0",
"main": "./index.js",
"repository": { "type": "git", "url": "https://github.com/geocar/mmap.git" },
"scripts": {
Expand Down