Class: Raindrops
- Inherits:
-
Object
- Object
- Raindrops
- Defined in:
- lib/raindrops.rb,
ext/raindrops/raindrops.c,
ext/raindrops/linux_inet_diag.c,
ext/raindrops/tcp_info.c
Overview
Each Raindrops object is a container that holds several counters. It is internally a page-aligned, shared memory area that allows atomic increments, decrements, assignments and reads without any locking.
rd = Raindrops.new 4
rd.incr(0, 1) -> 1
rd.to_ary -> [ 1, 0, 0, 0 ]
Unlike many classes in this package, the core Raindrops class is intended to be portable to all reasonably modern *nix systems supporting mmap(). Please let us know if you have portability issues, patches or pull requests at [email protected]
Defined Under Namespace
Modules: Aggregate, Linux Classes: InetDiagSocket, LastDataRecv, ListenStats, Middleware, Struct, TCP_Info, Watcher
Constant Summary collapse
- PAGE_SIZE =
The size of one page of memory for a mmap()-ed Raindrops region. Typically 4096 bytes under Linux.
SIZET2NUM(rd_page_size)
- SIZE =
The size (in bytes) of a slot in a Raindrops object. This is the size of a word on single CPU systems and the size of the L1 cache line size if detectable.
Defaults to 128 bytes if undetectable.
SIZET2NUM(raindrop_size)
- MAX =
The maximum value a raindrop counter can hold
ULONG2NUM((unsigned long)-1)
- TCP =
tcp
Instance Method Summary collapse
-
#[](index) ⇒ Object
rd -> value.
-
#[]=(index, value) ⇒ Object
rd = value.
-
#capa ⇒ Object
rd.capa -> Integer.
-
#decr(*args) ⇒ Object
rd.decr(index[, number]) -> result.
-
#evaporate! ⇒ Object
rd.evaporate! -> nil.
-
#incr(*args) ⇒ Object
rd.incr(index[, number]) -> result.
-
#initialize(size, io: nil, zero: false) ⇒ Raindrops
constructor
call-seq: Raindrops.new(size, io: nil) -> raindrops object.
-
#initialize_copy(source) ⇒ Object
rd.dup -> rd_copy.
-
#size ⇒ Object
rd.size -> Integer.
-
#size=(new_size) ⇒ Object
rd.size = new_size.
-
#to_ary ⇒ Object
rd.to_ary -> Array.
-
#- ⇒ Object
Returns the IO object backing the memory for this raindrop, if one was specified when constructing this Raindrop.
Constructor Details
#initialize(size, io: nil, zero: false) ⇒ Raindrops
call-seq: Raindrops.new(size, io: nil) -> raindrops object
Initializes a Raindrops object to hold size
counters. size
is only a hint and the actual number of counters the object has is dependent on the CPU model, number of cores, and page size of the machine. The actual size of the object will always be equal or greater than the specified size
. If io
is provided, then the Raindrops memory will be backed by the specified file; otherwise, it will allocate anonymous memory. The IO object must respond to truncate
, as this is used to set the size of the file. If zero
is provided, then the memory region is zeroed prior to returning. This is only meaningful if io
is also provided; in that case it controls whether any existing counter values in io
are retained (false) or whether it is entirely zeroed (true).
57 58 59 60 61 62 63 |
# File 'lib/raindrops.rb', line 57 def initialize(size, io: nil, zero: false) # This ruby wrapper exists to handle the keyword-argument handling, # which is otherwise kind of awkward in C. We delegate the keyword # arguments to the _actual_ initialize implementation as positional # args. initialize_cimpl(size, io, zero) end |
Instance Method Details
#[](index) ⇒ Object
rd -> value
Returns the value of the slot designated by index
354 355 356 357 |
# File 'ext/raindrops/raindrops.c', line 354
static VALUE aref(VALUE self, VALUE index)
{
return ULONG2NUM(*addr_of(self, index));
}
|
#[]=(index, value) ⇒ Object
rd = value
Assigns value
to the slot designated by index
339 340 341 342 343 344 345 346 |
# File 'ext/raindrops/raindrops.c', line 339
static VALUE aset(VALUE self, VALUE index, VALUE value)
{
unsigned long *addr = addr_of(self, index);
*addr = NUM2ULONG(value);
return value;
}
|
#capa ⇒ Object
rd.capa -> Integer
Returns the number of slots allocated (but not necessarily used) by the Raindrops object.
227 228 229 230 |
# File 'ext/raindrops/raindrops.c', line 227
static VALUE capa(VALUE self)
{
return SIZET2NUM(get(self)->capa);
}
|
#decr(*args) ⇒ Object
rd.decr(index[, number]) -> result
Decrements the value referred to by the index
by number
. number
defaults to 1
if unspecified.
292 293 294 295 296 297 |
# File 'ext/raindrops/raindrops.c', line 292
static VALUE decr(int argc, VALUE *argv, VALUE self)
{
unsigned long nr = incr_decr_arg(argc, argv);
return ULONG2NUM(__sync_sub_and_fetch(addr_of(self, argv[0]), nr));
}
|
#evaporate! ⇒ Object
rd.evaporate! -> nil
Releases mmap()-ed memory allocated for the Raindrops object back to the OS. The Ruby garbage collector will also release memory automatically when it is not needed, but this forces release under high memory pressure.
385 386 387 388 389 390 391 392 393 394 |
# File 'ext/raindrops/raindrops.c', line 385
static VALUE evaporate_bang(VALUE self)
{
struct raindrops *r = get(self);
void *addr = r->drops;
r->drops = MAP_FAILED;
if (munmap(addr, raindrop_size * r->capa) != 0)
rb_sys_fail("munmap");
return Qnil;
}
|
#incr(*args) ⇒ Object
rd.incr(index[, number]) -> result
Increments the value referred to by the index
by number
. number
defaults to 1
if unspecified.
278 279 280 281 282 283 |
# File 'ext/raindrops/raindrops.c', line 278
static VALUE incr(int argc, VALUE *argv, VALUE self)
{
unsigned long nr = incr_decr_arg(argc, argv);
return ULONG2NUM(__sync_add_and_fetch(addr_of(self, argv[0]), nr));
}
|
#initialize_copy(source) ⇒ Object
rd.dup -> rd_copy
Duplicates and snapshots the current state of a Raindrops object. Even if the given Raindrops object is backed by a file, the copy will be backed by independent, anonymously mapped memory.
240 241 242 243 244 245 246 247 248 249 |
# File 'ext/raindrops/raindrops.c', line 240
static VALUE init_copy(VALUE dest, VALUE source)
{
struct raindrops *dst = DATA_PTR(dest);
struct raindrops *src = get(source);
init_cimpl(dest, SIZET2NUM(src->size), Qnil, Qfalse);
memcpy(dst->drops, src->drops, raindrop_size * src->size);
return dest;
}
|
#size ⇒ Object
rd.size -> Integer
Returns the number of counters a Raindrops object can hold. Due to page alignment, this is always equal or greater than the number of requested slots passed to Raindrops.new
328 329 330 331 |
# File 'ext/raindrops/raindrops.c', line 328
static VALUE size(VALUE self)
{
return SIZET2NUM(get(self)->size);
}
|
#size=(new_size) ⇒ Object
rd.size = new_size
Increases or decreases the current capacity of our Raindrop. Raises RangeError if new_size
is too big or small for the current backing store
207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'ext/raindrops/raindrops.c', line 207
static VALUE setsize(VALUE self, VALUE new_size)
{
size_t new_rd_size = NUM2SIZET(new_size);
struct raindrops *r = get(self);
if (new_rd_size <= r->capa)
r->size = new_rd_size;
else
resize(r, new_rd_size);
return new_size;
}
|
#to_ary ⇒ Object
rd.to_ary -> Array
converts the Raindrops structure to an Array
305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'ext/raindrops/raindrops.c', line 305
static VALUE to_ary(VALUE self)
{
struct raindrops *r = get(self);
VALUE rv = rb_ary_new2(r->size);
size_t i;
unsigned long base = (unsigned long)r->drops;
for (i = 0; i < r->size; i++) {
rb_ary_push(rv, ULONG2NUM(*((unsigned long *)base)));
base += raindrop_size;
}
return rv;
}
|
#- ⇒ Object
Returns the IO object backing the memory for this raindrop, if one was specified when constructing this Raindrop. If this Raindrop is backed by anonymous memory, this method returns nil.
404 405 406 407 408 |
# File 'ext/raindrops/raindrops.c', line 404
static VALUE to_io(VALUE self)
{
struct raindrops *r = get(self);
return r->io;
}
|