README
Valvekit
Valvekit is a locking/synchronization mechanisms library forked from locks
.
This library implements locking/synchronization mechanisms that have traditionally
been used for protecting shared memory between multiple threads. JavaScript is
inherently single threaded and does not suffer from these security and
stability issues. However, because of its asynchronous eventy nature JavaScript
can still benefit from making particular operations wait for the completion of
others.
Installation
Node.js users:
npm install --save valvekit
Accessing the valvekit
module:
var valvekit = require('valvekit');
Barrier locks
Barriers allow synchronization between processes based on tickets.
Creating a Barrier:
var defaultTicket = 'foo-bar';
var barrier = valvekit.createBarrier(defaultTicket);
Waiting for a provided ticket that matching a value of accepted array:
barrier.wait(['th3-s3cr3t-k3y', 'invalid'], function matched() {
console.log('Provided ticket value is matched!');
}
);
or a condition test function to be met:
barrier.wait(
function conditionTest(value) {
return value.indexOf('s3cr3t') !== -1;
},
function whenConditionMet() {
console.log('Provided ticket value is matched!');
}
);
Setting the ticket on a Barrier:
barrier.set('th3-s3cr3t-k3y');
Mutex locks
Mutex locks are the most basic locks which aim to prevent the simultaneous access to a resource by more than one actor at a time. more info
Creating a Mutex Lock:
var mutex = valvekit.createMutex();
Waiting to lock:
mutex.lock(function () {
console.log('We got the lock!');
// do stuff
mutex.unlock();
});
Waiting to lock, with timeout:
mutex.lock(function (error) {
if (error) {
console.log('Could not get the lock within 5 seconds, so gave up');
} else {
console.log('We got the lock!');
// do stuff
mutex.unlock();
}
}, 5000);
Checking if a lock is held:
if (mutex.isLocked) {
console.log('Something has the lock.');
}
Optimistic attempt to lock:
if (mutex.tryLock()) {
console.log('We got the lock!');
// do stuff
mutex.unlock();
} else {
console.log('Could not get the lock at this time');
}
Read/Write locks
Read/Write Locks are used to allow many actors to read from a resource, as long as nothing is writing to it. That also means that only one actor may be writing at any given time. more info
Creating a Read/Write Lock:
var rwlock = valvekit.createLock();
Waiting to read lock:
rwlock.readLock(function () {
console.log('We may now read from a resource!');
// do stuff
rwlock.unlock();
});
Waiting to read lock, with timeout:
rwlock.readLock(function (error) {
if (error) {
console.log('Could not get the lock within 5 seconds, so gave up');
} else {
console.log('We may now read from a resource!');
// do stuff
rwlock.unlock();
}
}, 1000);
Waiting to write lock:
rwlock.writeLock(function () {
console.log('We may now write to a resource!');
// do stuff
rwlock.unlock();
});
Waiting to write lock, with timeout:
rwlock.writeLock(function (error) {
if (error) {
console.log('Could not get the lock within 5 seconds, so gave up');
} else {
console.log('We may now write to a resource!');
// do stuff
rwlock.unlock();
}
}, 5000);
Checking if a lock is held:
if (rwlock.isWriteLocked) {
console.log('Something has the write lock.');
}
else if (rwlock.isReadLocked) {
console.log('The read lock is held one or more times.');
}
Optimistic attempt to read lock:
if (rwlock.tryReadLock()) {
console.log('We may now read from a resource!');
// do stuff
rwlock.unlock();
} else {
console.log('Could not get the lock at this time');
}
Optimistic attempt to write lock:
if (rwlock.tryWriteLock()) {
console.log('We may now write to a resource!');
// do stuff
rwlock.unlock();
} else {
console.log('Could not get the lock at this time');
}
Semaphores
Semaphores solve the problem of sharing a limited set of resources. more info
Creating a Semaphore:
var resourceLimit = 3; // amount of resources available
var sem = valvekit.createSemaphore(resourceLimit);
Claiming and releasing a resource:
sem.take(function () {
// a resource is available, do something
// ...
// done, release the resource
sem.release();
});
Or using an all-in-one function:
sem.sandbox(function () {
// a resource is available, do something
// ...
// automatic release the resource
});
Example:
var sem = require('valvekit').createSemaphore(5);
function demo(i) {
return sem.sandbox(function() {
if (Math.random() > 0.7) {
throw new Error("Item[" + i + "] - accident");
}
return new Promise(function(resolved, rejected) {
setTimeout(function() {
if (Math.random() > 0.5)
rejected("Item[" + i + "] - rejected");
else
resolved("Item[" + i + "]");
}, 100)
})
})
}
function show(msg) {
console.log(typeof msg === 'string' ? msg : msg.message);
}
var count = 0;
for(var i=0; i<100; i++) {
demo(i).then(show, show).finally(function() {
count++;
console.log("current: %d", count);
});
}
License
MIT