SlugDB

A completely native Ruby, lightweight, zero dependency, NoSQL, file based database.

I wanted a tiny database for an embedded project that could follow the advanced data modelling techniques for NoSQL. This is basically a very slimmed down SQLite but for NoSQL without any C bindings.

Installation

Add this line to your application's Gemfile:

gem 'slugdb'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install slugdb

Usage

First, go watch this: AWS re:Invent 2019: Amazon DynamoDB deep dive: Advanced design patterns (DAT403-R1)

Then watch it like a dozen more times, it'll click.

Basic usage


require 'slugdb'
# => true

# Create a database

sdb = SlugDB.new('./data.slug')
# => #<SlugDB:0x000055bd9552c238
#  @pstore=
#   #<PStore:0x000055bd9552c210
#    @abort=false,
#    @filename="./data.slug",
#    @lock=#<Thread::Mutex:0x000055bd9552c148>,
#    @rdonly=false,
#    @table={:main=>{}, :indexes=>{}},
#    @thread_safe=false,
#    @ultra_safe=false>>

# Put some data in it

sdb.put_item(pk: 'awesome#partition#1#', sk: 'metadata#')
# => {:pk=>"awesome#partition#1#", :sk=>"metadata#"}

# Read it back

sdb.get_item(pk: 'awesome#partition#1#', sk: 'metadata#')
# => {:pk=>"awesome#partition#1#", :sk=>"metadata#"}

# Put in some more data

sdb.put_item(pk: 'awesome#partition#1#', sk: 'something#useful#')
# => {:pk=>"awesome#partition#1#", :sk=>"something#useful#"}

# Query our records

sdb.query(pk: 'awesome#partition#1#')
# => [{:pk=>"awesome#partition#1#", :sk=>"metadata#"},
#  {:pk=>"awesome#partition#1#", :sk=>"something#useful#"}]

Ok, but like... this is useful, how exactly?..

Clearly you didn't watch the YouTube video, it's fine, no one does. Let me read it to you.

We're about to solve the following:

  • Get meetings
    • by date and email
    • by date and employee id
    • by date and building/floor/room
  • Load employee dashboard by email
    • get employee data
    • get meetings
    • get tickets
    • get reservations
    • get time cards
  • Get employee info
    • by employed id
    • by email
  • Get ticket history
    • by ticket id
    • by employee email
    • by assignee email
  • Get employees
    • by city, building, floor, aisle, desk
    • by manager
  • Get assigned tickets
    • by email
  • Get tickets
    • by last touched greater than 24 hours ago
  • Get projects
    • by status, start and target date
    • by name
  • Get project history
    • by date range
    • by name
  • Get rooms
    • by building id
    • by availability and time range

And like.. its really damn easy. Embrance the datas.

Let's go load all them datas into the bases.

### Create a fresh table

sdb = SlugDB.new('./demo.slug')
# => #<SlugDB:0x00005612d2ad0120
#  @pstore=
#   #<PStore:0x00005612d2ad00f8
#    @abort=false,
#    @filename="./demo.slug",
#    @lock=#<Thread::Mutex:0x00005612d2ad0030>,
#    @rdonly=false,
#    @table={:main=>{}, :indexes=>{}},
#    @thread_safe=false,
#    @ultra_safe=false>>

### Create some indexes

sdb.add_index(name: :ski, pk: :sk, sk: :pk)
# => {:name=>{:pk=>:sk, :sk=>:pk}}
sdb.add_index(name: :gsi1, pk: :gsi1_pk, sk: :gsi1_sk)
# => {:name=>{:pk=>:gsi1_pk, :sk=>:gsi1_sk}}
sdb.add_index(name: :gsi2, pk: :gsi2_pk, sk: :gsi2_sk)
# => {:name=>{:pk=>:gsi2_pk, :sk=>:gsi2_sk}}
sdb.add_index(name: :gsi3, pk: :gsi3_pk, sk: :gsi3_sk)
# => {:name=>{:pk=>:gsi3_pk, :sk=>:gsi3_sk}}

### Create some records

sdb.put_item(
  pk: 'yxz58',
  sk: '2021-03-04T10:00:00Z|10.106',
  gsi1_pk: '[email protected]',
  gsi1_sk: '2021-03-04T10:00:00Z|10.106',
  duration: 30,
  attendees: ['[email protected]', '[email protected]'],
  subject: 'Discuss Project How does NoSQL?'
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#  :duration=>30,
#  :attendees=>["[email protected]", "[email protected]"],
#  :subject=>"Discuss Project How does NoSQL?",
#  :pk=>"yxz58",
#  :sk=>"2021-03-04T10:00:00Z|10.106"}
sdb.put_item(
  pk: 'yxz58',
  sk: '2021-03-04T10:15:00Z|10.106',
  attendees: ['[email protected]', '[email protected]'],
  subject: 'Discuss Project How does NoSQL?',
  organizer: '[email protected]'
)
# => {:attendees=>["[email protected]", "[email protected]"],
#  :subject=>"Discuss Project How does NoSQL?",
#  :organizer=>"[email protected]",
#  :pk=>"yxz58",
#  :sk=>"2021-03-04T10:15:00Z|10.106"}
sdb.put_item(
  pk: 'yxz58',
  sk: 'rooms',
  room_spec: {
    some: 'data',
    more: 'and more'
  }
)
# => {:room_spec=>{:some=>"data", :more=>"and more"}, :pk=>"yxz58", :sk=>"rooms"}

sdb.put_item(
  pk: 'employee#1',
  sk: '2021-03-04T10:00:00Z|10.106',
  gsi1_pk: '[email protected]',
  gsi1_sk: '2021-03-04T10:00:00Z|10.106',
  duration: 30,
  attendees: ['[email protected]', '[email protected]'],
  subject: 'Discuss Project How does NoSQL?'
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#  :duration=>30,
#  :attendees=>["[email protected]", "[email protected]"],
#  :subject=>"Discuss Project How does NoSQL?",
#  :pk=>"employee#1",
#  :sk=>"2021-03-04T10:00:00Z|10.106"}
sdb.put_item(
  pk: 'employee#1',
  sk: 'ext#965',
  gsi1_pk: '[email protected]',
  gsi1_sk: 'ext#965',
  gsi3_pk: 'yxz',
  gsi3_sk: '10.11.123.G9',
  name: 'Not John',
  title: 'Imposter',
  gsi2_pk: '[email protected]',
  gsi2_sk: nil
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"ext#965",
#  :gsi3_pk=>"yxz",
#  :gsi3_sk=>"10.11.123.G9",
#  :name=>"Not John",
#  :title=>"Imposter",
#  :gsi2_pk=>"[email protected]",
#  :gsi2_sk=>nil,
#  :pk=>"employee#1",
#  :sk=>"ext#965"}

sdb.put_item(
  pk: 'employee#2',
  sk: 'ext#293',
  gsi1_pk: '[email protected]',
  gsi1_sk: 'ext#293',
  gsi3_pk: 'yxz',
  gsi3_sk: '11.10.123.G9',
  name: 'Actual John',
  title: 'Real',
  gsi2_pk: '[email protected]',
  gsi2_sk: nil
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"ext#293",
#  :gsi3_pk=>"yxz",
#  :gsi3_sk=>"11.10.123.G9",
#  :name=>"Actual John",
#  :title=>"Real",
#  :gsi2_pk=>"[email protected]",
#  :gsi2_sk=>nil,
#  :pk=>"employee#2",
#  :sk=>"ext#293"}

sdb.put_item(
  pk: 'Project How does NoSQL?',
  sk: '2021-03-04#[email protected]',
  gsi1_pk: '[email protected]',
  gsi1_sk: '2021-03-04',
  hours: 12,
  role: 'Lord of Data'
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"2021-03-04",
#  :hours=>12,
#  :role=>"Lord of Data",
#  :pk=>"Project How does NoSQL?",
#  :sk=>"2021-03-04#[email protected]"}
sdb.put_item(
  pk: 'Project How does NoSQL?',
  sk: '2021-03-04#[email protected]',
  gsi1_pk: '[email protected]',
  gsi1_sk: '2021-03-04',
  hours: 24,
  role: 'Not as cool'
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"2021-03-04",
#  :hours=>24,
#  :role=>"Not as cool",
#  :pk=>"Project How does NoSQL?",
#  :sk=>"2021-03-04#[email protected]"}
sdb.put_item(
  pk: 'Project How does NoSQL?',
  sk: 'Project How does NoSQL?',
  gsi1_pk: 'Active',
  gsi1_sk: '2021-02-25',
  description: 'A project, darkly',
  target_delivery: '2021-04-15'
)
# => {:gsi1_pk=>"Active",
#  :gsi1_sk=>"2021-02-25",
#  :description=>"A project, darkly",
#  :target_delivery=>"2021-04-15",
#  :pk=>"Project How does NoSQL?",
#  :sk=>"Project How does NoSQL?"}

sdb.put_item(
  pk: 'ticket#1',
  sk: '2021-03-04T10:30:29Z',
  gsi1_pk: '[email protected]',
  gsi1_sk: '2021-03-04T10:30:29Z',
  subject: 'halp',
  gsi3_pk: '7',
  gsi3_sk: '2021-03-04T10:30:29Z',
  gsi2_pk: '[email protected]',
  gsi2_sk: 'need halps, datas iz hard'
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"2021-03-04T10:30:29Z",
#  :subject=>"halp",
#  :gsi3_pk=>'7',
#  :gsi3_sk=>"2021-03-04T10:30:29Z",
#  :gsi2_pk=>"[email protected]",
#  :gsi2_sk=>"need halps, datas iz hard",
#  :pk=>"ticket#1",
#  :sk=>"2021-03-04T10:30:29Z"}
sdb.put_item(
  pk: 'ticket#1',
  sk: '2021-03-04T10:35:46Z',
  gsi1_pk: '[email protected]',
  gsi1_sk: '2021-03-04T10:35:46Z',
  gsi2_pk: '[email protected]',
  message: 'ack, halps requested'
)
# => {:gsi1_pk=>"[email protected]",
#  :gsi1_sk=>"2021-03-04T10:35:46Z",
#  :gsi2_pk=>"[email protected]",
#  :message=>"ack, halps requested",
#  :pk=>"ticket#1",
#  :sk=>"2021-03-04T10:35:46Z"}

### Ok, let's get meetings by date and employee id and toss in a filter for greater than zero duration

sdb.query(
  pk: 'employee#1',
  select: ->(sk) { sk >= '2021-03-03T10:00:00Z' && sk <= '2021-03-05T10:00:00Z' },
  filter: ->(item) { !item[:duration].nil? && item[:duration] > 0 }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#   :duration=>30,
#   :attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :pk=>"employee#1",
#   :sk=>"2021-03-04T10:00:00Z|10.106"}]

### Neat, now let's get meetings by date a building/floor/room

sdb.query(
  pk: 'yxz58',
  select: ->(sk) { sk >= '2021-03-03T10:00:00Z' && sk <= '2021-03-05T10:00:00Z' },
  filter: ->(item) { item[:sk] =~ /\|10\./ }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#   :duration=>30,
#   :attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :pk=>"yxz58",
#   :sk=>"2021-03-04T10:00:00Z|10.106"},
#  {:attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :organizer=>"[email protected]",
#   :pk=>"yxz58",
#   :sk=>"2021-03-04T10:15:00Z|10.106"}]

### I'm not a wizard, maybe a sorceror. How about getting employee info by employee id

sdb.query(
  pk: 'employee#2',
  select: ->(sk) { sk.start_with?('ext#') }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"ext#293",
#   :gsi3_pk=>"yxz",
#   :gsi3_sk=>"11.10.123.G9",
#   :name=>"Actual John",
#   :title=>"Real",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>nil,
#   :pk=>"employee#2",
#   :sk=>"ext#293"}]

### That was a bit too easy, maybe not a sorceror. Some spell have a long cast time. Where's my ticket history?

sdb.query(pk: 'ticket#1')
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:30:29Z",
#   :subject=>"halp",
#   :gsi3_pk=>'7',
#   :gsi3_sk=>"2021-03-04T10:30:29Z",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>"need halps, datas iz hard",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:30:29Z"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:35:46Z",
#   :gsi2_pk=>"[email protected]",
#   :message=>"ack, halps requested",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:35:46Z"}]

### Yeah.. a little **too** easy, right? Can I get project info?

sdb.query(
  pk: 'Project How does NoSQL?',
  select: ->(sk) { sk == 'Project How does NoSQL?' }
)
# => [{:gsi1_pk=>"Active",
#   :gsi1_sk=>"2021-02-25",
#   :description=>"A project, darkly",
#   :target_delivery=>"2021-04-15",
#   :pk=>"Project How does NoSQL?",
#   :sk=>"Project How does NoSQL?"}]

### I'm wondering if I even NoSQL? Can I get project history?

sdb.query(
  pk: 'Project How does NoSQL?',
  select: ->(sk) { sk >= '2021-03-03' && sk <= '2021-03-05' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04",
#   :hours=>12,
#   :role=>"Lord of Data",
#   :pk=>"Project How does NoSQL?",
#   :sk=>"2021-03-04#[email protected]"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04",
#   :hours=>24,
#   :role=>"Not as cool",
#   :pk=>"Project How does NoSQL?",
#   :sk=>"2021-03-04#[email protected]"}]

### I think I can NoSQL, gimme dem projects by role

sdb.query(
  pk: 'Project How does NoSQL?',
  filter: ->(item) { item[:role] == 'Lord of Data' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04",
#   :hours=>12,
#   :role=>"Lord of Data",
#   :pk=>"Project How does NoSQL?",
#   :sk=>"2021-03-04#[email protected]"}]

### I still have way more to, I need a seat, got a room that'll work?

sdb.query(
  pk: 'yxz58',
  select: ->(sk) { sk == 'rooms' }
)
# => [{:room_spec=>
#    {:some=>"data",
#     :more=>"and more"},
#   :pk=>"yxz58",
#   :sk=>"rooms"}]

### Nice, is that room available?

sdb.query(
  pk: 'yxz58',
  select: ->(sk) { sk >= '2021-03-03T09:00:00Z' && sk <= '2021-03-05T18:00:00Z' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#   :duration=>30,
#   :attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :pk=>"yxz58",
#   :sk=>"2021-03-04T10:00:00Z|10.106"},
#  {:attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :organizer=>"[email protected]",
#   :pk=>"yxz58",
#   :sk=>"2021-03-04T10:15:00Z|10.106"}]


### Book it! But, am I busy? My sorcery is bubbling up...

sdb.query(
  index: :gsi1,
  pk: '[email protected]',
  select: ->(sk) { sk >= '2021-03-03T09:00:00Z' && sk <= '2021-03-05T18:00:00Z' },
  filter: ->(item) { !item[:duration].nil? && item[:duration] > 0 }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#   :duration=>30,
#   :attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :pk=>"yxz58",
#   :sk=>"2021-03-04T10:00:00Z|10.106"}]

### MMMM.. Dems some good datas. Gimme more datas!! I need to render a dashbaord

sdb.query(
  index: :gsi1,
  pk: '[email protected]',
  select: ->(sk) { sk >= '2021-02-03T09:00:00Z' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:00:00Z|10.106",
#   :duration=>30,
#   :attendees=>["[email protected]", "[email protected]"],
#   :subject=>"Discuss Project How does NoSQL?",
#   :pk=>"yxz58",
#   :sk=>"2021-03-04T10:00:00Z|10.106"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"ext#293",
#   :gsi3_pk=>"yxz",
#   :gsi3_sk=>"11.10.123.G9",
#   :name=>"Actual John",
#   :title=>"Real",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>nil,
#   :pk=>"employee#2",
#   :sk=>"ext#293"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04",
#   :hours=>12,
#   :role=>"Lord of Data",
#   :pk=>"Project How does NoSQL?",
#   :sk=>"2021-03-04#[email protected]"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:30:29Z",
#   :subject=>"halp",
#   :gsi3_pk=>'7',
#   :gsi3_sk=>"2021-03-04T10:30:29Z",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>"need halps, datas iz hard",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:30:29Z"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:35:46Z",
#   :gsi2_pk=>"[email protected]",
#   :message=>"ack, halps requested",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:35:46Z"}]

### Truly magical! Hit with some more info

sdb.query(
  index: :gsi1,
  pk: '[email protected]',
  select: ->(sk) { sk.start_with?('ext#') }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"ext#293",
#   :gsi3_pk=>"yxz",
#   :gsi3_sk=>"11.10.123.G9",
#   :name=>"Actual John",
#   :title=>"Real",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>nil,
#   :pk=>"employee#2",
#   :sk=>"ext#293"}]

### Delicious, how about some ticket history?

sdb.query(
  index: :gsi1,
  pk: '[email protected]',
  filter: ->(item) { item[:pk] == 'ticket#1' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:30:29Z",
#   :subject=>"halp",
#   :gsi3_pk=>'7',
#   :gsi3_sk=>"2021-03-04T10:30:29Z",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>"need halps, datas iz hard",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:30:29Z"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:35:46Z",
#   :gsi2_pk=>"[email protected]",
#   :message=>"ack, halps requested",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:35:46Z"}]

### Is it setting in yet? How much you totally don't know about NoSQL? Can you riddle me this? What active projects do I have?

sdb.query(
  index: :gsi1,
  pk: 'Active',
  select: ->(sk) { sk >= '2021-02-25' },
  filter: ->(item) { item[:target_delivery] < '2021-05-01' }
)
# => [{:gsi1_pk=>"Active",
#   :gsi1_sk=>"2021-02-25",
#   :description=>"A project, darkly",
#   :target_delivery=>"2021-04-15",
#   :pk=>"Project How does NoSQL?",
#   :sk=>"Project How does NoSQL?"}]

### We're still not done yet, we've only used a single index so far. Give me the ticket history by assignee

sdb.query(
  index: :gsi2,
  pk: '[email protected]',
  filter: ->(item) { item[:pk] == 'ticket#1' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:30:29Z",
#   :subject=>"halp",
#   :gsi3_pk=>'7',
#   :gsi3_sk=>"2021-03-04T10:30:29Z",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>"need halps, datas iz hard",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:30:29Z"}]

### Neato, I'm still not out of tricks. Can you give me all employees by location?

sdb.query(
  index: :gsi3,
  pk: 'yxz',
  select: ->(sk) { sk.start_with?('10.11') }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"ext#965",
#   :gsi3_pk=>"yxz",
#   :gsi3_sk=>"10.11.123.G9",
#   :name=>"Not John",
#   :title=>"Imposter",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>nil,
#   :pk=>"employee#1",
#   :sk=>"ext#965"},
#  {:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"ext#293",
#   :gsi3_pk=>"yxz",
#   :gsi3_sk=>"10.11.124.G9",
#   :name=>"Actual John",
#   :title=>"Real",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>nil,
#   :pk=>"employee#2",
#   :sk=>"ext#293"}]

### Final trick.. for now.. show me all the tickets that haven't bene dealt with recently

sdb.query(
  index: :gsi3,
  pk: '7',
  select: ->(sk) { sk < '2021-03-06T10:30:29Z' }
)
# => [{:gsi1_pk=>"[email protected]",
#   :gsi1_sk=>"2021-03-04T10:30:29Z",
#   :subject=>"halp",
#   :gsi3_pk=>'7',
#   :gsi3_sk=>"2021-03-04T10:30:29Z",
#   :gsi2_pk=>"[email protected]",
#   :gsi2_sk=>"need halps, datas iz hard",
#   :pk=>"ticket#1",
#   :sk=>"2021-03-04T10:30:29Z"}]

Performance

Using Ubuntu 20.04 on an i7-10710U with Ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux] I got the following:

john@devbox:~/work/ruby-slugdb$ bundle exec bin/benchmark
Rehearsal -------------------------------------------------------------------------------
put_item 5 partitions, 1000 items           124.536929   0.864719 125.401648 (125.411962)
put_item 50 partitions, 100 items           114.684999   0.332007 115.017006 (115.025352)
put_item 500 partitions, 10 items           118.303101   0.288004 118.591105 (118.601603)
put_item 5000 partitions, 1 items           160.530284   0.883942 161.414226 (161.427220)
2 indexes put_item 5 partitions, 1000 items 251.300281   1.031866 252.332147 (252.364579)
2 indexes put_item 50 partitions, 100 items 235.390541   0.963895 236.354436 (236.383481)
2 indexes put_item 500 partitions, 10 items 241.453317   0.999958 242.453275 (242.479636)
2 indexes put_item 5000 partitions, 1 items 310.027647   1.291865 311.319512 (311.353699)
put_item, get_item 5 partitions, 1000 items 201.732843   0.499968 202.232811 (202.251035)
put_item, get_item 50 partitions, 100 items 191.160082   0.427998 191.588080 (191.604090)
put_item, get_item 500 partitions, 10 items 197.149766   0.419959 197.569725 (197.586483)
put_item, get_item 5000 partitions, 1 items 266.727467   0.575973 267.303440 (267.323639)
------------------------------------------------------------------- total: 2421.577411sec

                                                  user     system      total        real
put_item 5 partitions, 1000 items           120.888413   0.347965 121.236378 (121.245881)
put_item 50 partitions, 100 items           113.471668   0.268009 113.739677 (113.747636)
put_item 500 partitions, 10 items           117.166616   0.319974 117.486590 (117.492926)
put_item 5000 partitions, 1 items           158.001298   0.427986 158.429284 (158.434901)
2 indexes put_item 5 partitions, 1000 items 251.204792   0.719985 251.924777 (251.937582)
2 indexes put_item 50 partitions, 100 items 235.023671   0.715972 235.739643 (235.755838)
2 indexes put_item 500 partitions, 10 items 241.072163   0.575991 241.648154 (241.662752)
2 indexes put_item 5000 partitions, 1 items 310.193882   1.339952 311.533834 (311.556014)
put_item, get_item 5 partitions, 1000 items 201.417776   0.467966 201.885742 (201.898954)
put_item, get_item 50 partitions, 100 items 190.772848   0.523983 191.296831 (191.308661)
put_item, get_item 500 partitions, 10 items 197.940498   0.475973 198.416471 (198.428618)
put_item, get_item 5000 partitions, 1 items 267.390145   0.715933 268.106078 (268.127310)

A key take away is that PStore kinda sucks with large data sets. My initial use case is hosting maybe a few hundred items. I wanted NoSQL funcitonality that didn't have a third part dep. Making this performant could be a thing but I'm not interested in that right now. PStore serializes the entire hash to disk on every write, keep that in mind.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/watmin/Ruby-slugdb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the SlugDB project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.