class Raindrops - raindrops-0.17.0 Documentation

# class Raindrops

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 raindrops-public@bogomips.org

### Constants

MAX

  The maximum value a raindrop counter can hold

PAGE_SIZE

  The size of one page of memory for a mmap()-ed Raindrops region. Typically 4096 bytes under Linux.

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.

### Public Class Methods

new(size) → raindrops object click to toggle source

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`.

    static VALUE init(VALUE self, VALUE size)
    {
            struct raindrops *r = DATA_PTR(self);
            int tries = 1;
            size_t tmp;

            if (r->drops != MAP_FAILED)
                    rb_raise(rb_eRuntimeError, "already initialized");

            r->size = NUM2SIZET(size);
            if (r->size < 1)
                    rb_raise(rb_eArgError, "size must be >= 1");

            tmp = PAGE_ALIGN(raindrop_size * r->size);
            r->capa = tmp / raindrop_size;
            assert(PAGE_ALIGN(raindrop_size * r->capa) == tmp && "not aligned");

    retry:
            r->drops = mmap(NULL, tmp,
                            PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
            if (r->drops == MAP_FAILED) {
                    if ((errno == EAGAIN || errno == ENOMEM) && tries-- > 0) {
                            rb_gc();
                            goto retry;
                    }
                    rb_sys_fail("mmap");
            }
            r->pid = getpid();

            return self;
    }

### Public Instance Methods

rd[index] → value click to toggle source

Returns the value of the slot designated by `index`

    static VALUE aref(VALUE self, VALUE index)
    {
            return  ULONG2NUM(*addr_of(self, index));
    }

rd[index] = value click to toggle source

Assigns `value` to the slot designated by `index`

    static VALUE aset(VALUE self, VALUE index, VALUE value)
    {
            unsigned long *addr = addr_of(self, index);

            *addr = NUM2ULONG(value);

            return value;
    }

capa → Integer click to toggle source

Returns the number of slots allocated (but not necessarily used) by the Raindrops object.

    static VALUE capa(VALUE self)
    {
            return SIZET2NUM(get(self)->capa);
    }

decr(index[, number]) → result click to toggle source

Decrements the value referred to by the `index` by `number`. `number` defaults to `1` if unspecified.

    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! → nil click to toggle source

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.

    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(index[, number]) → result click to toggle source

Increments the value referred to by the `index` by `number`. `number` defaults to `1` if unspecified.

    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));
    }

dup → rd_copy click to toggle source

Duplicates and snapshots the current state of a Raindrops object.

    static VALUE init_copy(VALUE dest, VALUE source)
    {
            struct raindrops *dst = DATA_PTR(dest);
            struct raindrops *src = get(source);

            init(dest, SIZET2NUM(src->size));
            memcpy(dst->drops, src->drops, raindrop_size * src->size);

            return dest;
    }

size → Integer click to toggle source

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 ::new

    static VALUE size(VALUE self)
    {
            return SIZET2NUM(get(self)->size);
    }

size = new_size click to toggle source

Increases or decreases the current capacity of our Raindrop. Raises RangeError if `new_size` is too big or small for the current backing store

    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 → Array click to toggle source

converts the Raindrops structure to an Array

    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;
    }