Class: Isomorfeus::Hamster::Database

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/isomorfeus/hamster/database.rb,
ext/isomorfeus_hamster_ext/isomorfeus_hamster.c

Instance Method Summary collapse

Instance Method Details

#[](key) ⇒ Object

Retrieve the value of a record from a database

Parameters:

  • key

    the record key to retrieve

Returns:

  • value of the record for that key, or nil if there is no record with that key

See Also:

  • #get(key)


29
30
31
# File 'lib/isomorfeus/hamster/database.rb', line 29

def [](key)
  get(key)
end

#[]=(key, value) ⇒ Object

Set (write or update) a record in a database.

Examples:

db['a'] = 'b'     #=> 'b'
db['b'] = 1234    #=> 1234
db['a']           #=> 'b'

Parameters:

  • key

    key for the record

  • value

    the value of the record

Returns:

  • returns the value of the record

See Also:

  • value)


42
43
44
45
# File 'lib/isomorfeus/hamster/database.rb', line 42

def []=(key, value)
  put(key, value)
  value
end

#cardinality(key) ⇒ Integer

Return the cardinality (number of duplicates) of a given key. Works whether :dupsort is set or not.

Parameters:

  • key (#to_s)

    The key in question.

Returns:

  • (Integer)

    The number of entries under the key.



98
99
100
101
102
103
104
105
106
107
# File 'lib/isomorfeus/hamster/database.rb', line 98

def cardinality(key)
  env.transaction true do
    return 0 unless get key
    return 1 unless dupsort?
    cursor do |c|
      c.set key
      return c.count
    end
  end
end

#clearObject

Note:

The clear happens transactionally.

Empty out the database

Returns:

  • nil



867
868
869
870
871
872
873
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 867

static VALUE database_clear(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self, "clear", 0, 0, 0);
        check(mdb_drop(need_txn(database->env), database->dbi, 0));
        return Qnil;
}

#cursor {|cursor| ... } ⇒ Object

Create a cursor to iterate through a database. Uses current transaction, if any. Otherwise, if called with a block, creates a new transaction for the scope of the block. Otherwise, fails.

Examples:

db = env.database "abc"
db.cursor do |c|
  key, value = c.next
  puts "#{key}: #{value}"
end

Yields:

  • (cursor)

    A block to be executed with the cursor.

Yield Parameters:

  • cursor (Cursor)

    The cursor to be used to iterate

See Also:



1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 1056

static VALUE database_cursor(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env)) {
                if (!rb_block_given_p()) {
                        rb_raise(cError, "Must call with block or active transaction.");
                }
                return call_with_transaction(database->env, self, "cursor", 0, 0, 0);
        }

        MDB_cursor* cur;
        check(mdb_cursor_open(need_txn(database->env), database->dbi, &cur));

        Cursor* cursor;
        VALUE vcur = Data_Make_Struct(cCursor, Cursor, cursor_mark, cursor_free, cursor);
        cursor->cur = cur;
        cursor->db = self;

        if (rb_block_given_p()) {
                int exception;
                VALUE ret = rb_protect(rb_yield, vcur, &exception);
                if (exception) {
                        cursor_close(vcur);
                        rb_jump_tag(exception);
                }
                cursor_close(vcur);
                return ret;
        }
        else {
                VALUE vtxn = environment_active_txn(database->env);
                if (NIL_P(vtxn)) {
                        rb_fatal("Internal error: transaction finished unexpectedly.");
                }
                else {
                        TRANSACTION(vtxn, txn);
                        rb_ary_push(txn->cursors, vcur);
                }
        }

        return vcur;
}

#delete(key, value = nil) ⇒ Object

Deletes records from the database. This function removes key/data pairs from the database. If the database does not support sorted duplicate data items (:dupsort) the value parameter is ignored. If the database supports sorted duplicates and the value parameter is nil, all of the duplicate data items for the key will be deleted. Otherwise, if the data parameter is non-nil only the matching data item will be deleted.

Parameters:

  • key

    The key of the record to delete.

  • value

    The optional value of the record to delete.

Raises:

  • (Error)

    if the specified key/value pair is not in the database.



974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 974

static VALUE database_delete(int argc, VALUE *argv, VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self, "delete", argc, argv, 0);

        VALUE vkey, vval;
        rb_scan_args(argc, argv, "11", &vkey, &vval);

        vkey = StringValue(vkey);

        MDB_val key;
        key.mv_size = RSTRING_LEN(vkey);
        key.mv_data = RSTRING_PTR(vkey);

        if (NIL_P(vval)) {
                check(mdb_del(need_txn(database->env), database->dbi, &key, 0));
        } else {
                vval = StringValue(vval);
                MDB_val value;
                value.mv_size = RSTRING_LEN(vval);
                value.mv_data = RSTRING_PTR(vval);
                check(mdb_del(need_txn(database->env), database->dbi, &key, &value));
        }

        return Qnil;
}

#delete?(key, value = nil) ⇒ Boolean

Delete the key (and optional value pair) if it exists; do not complain about missing keys.

Parameters:

  • key (#to_s)

    The key.

  • value (#to_s) (defaults to: nil)

    The optional value.

Returns:

  • (Boolean)


127
128
129
# File 'lib/isomorfeus/hamster/database.rb', line 127

def delete?(key, value = nil)
  delete key, value if has? key, value
end

#dropObject

Note:

The drop happens transactionally.

Remove a database from the environment.

Returns:

  • nil



853
854
855
856
857
858
859
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 853

static VALUE database_drop(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self, "drop", 0, 0, 0);
        check(mdb_drop(need_txn(database->env), database->dbi, 1));
        return Qnil;
}

#dupfixed?true, false

Returns whether the database is in :dupfixed mode.

Returns:

  • (true, false)


836
837
838
839
840
841
842
843
844
845
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 836

static VALUE database_is_dupfixed(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self,
                                             "dupfixed?", 0, 0, MDB_RDONLY);
        unsigned int flags;
        check(mdb_dbi_flags(need_txn(database->env), database->dbi, &flags));

        return (flags & MDB_DUPFIXED) == 0 ? Qfalse : Qtrue;
}

#dupsort?true, false

Returns whether the database is in :dupsort mode.

Returns:

  • (true, false)


820
821
822
823
824
825
826
827
828
829
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 820

static VALUE database_is_dupsort(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self,
                                             "dupsort?", 0, 0, MDB_RDONLY);
        unsigned int flags;
        check(mdb_dbi_flags(need_txn(database->env), database->dbi, &flags));

        return (flags & MDB_DUPSORT) == 0 ? Qfalse : Qtrue;
}

#each(readonly: true) {|i| ... } ⇒ Object

Iterate through the records in a database

Examples:

db.each do |record|
  key, value = record
  puts "at #{key}: #{value}"
end

Yields:

  • (i)

    Gives a record [key, value] to the block

Yield Parameters:

  • i (Array)

    The key, value pair for each record



14
15
16
17
18
19
20
21
22
# File 'lib/isomorfeus/hamster/database.rb', line 14

def each(readonly: true)
  env.transaction readonly do
    cursor do |c|
      while i = c.next
        yield(i)
      end
    end
  end
end

#each_key(readonly: true, &block) ⇒ Enumerator

Iterate over each key in the database, skipping over duplicate records.

Returns:

  • (Enumerator)

    in lieu of a block.



57
58
59
60
61
62
63
64
65
66
# File 'lib/isomorfeus/hamster/database.rb', line 57

def each_key(readonly: true, &block)
  return enum_for :each_key unless block_given?
  env.transaction readonly do
    cursor do |c|
      while (rec = c.next true)
        yield rec.first
      end
    end
  end
end

#each_value(key, readonly: true, &block) ⇒ Enumerator

Iterate over the duplicate values of a given key, using an implicit cursor. Works whether :dupsort is set or not.

Parameters:

  • key (#to_s)

    The key in question.

Returns:

  • (Enumerator)

    in lieu of a block.



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/isomorfeus/hamster/database.rb', line 74

def each_value(key, readonly: true,  &block)
  return enum_for :each_value, key unless block_given?

  value = get(key) or return
  unless dupsort?
    yield value
    return
  end

  env.transaction readonly do
    cursor do |c|
      method = :set
      while rec = c.send(method, key)
        method = :next_range
        yield rec[1]
      end
    end
  end
end

#envEnvironment

Returns the environment to which this database belongs.

Returns:

  • (Environment)

    the environment to which this database belongs.



1101
1102
1103
1104
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 1101

static VALUE database_env(VALUE self) {
        DATABASE(self, database);
        return database->env;
}

#flagsHash

Return the flags used to open the database.

Returns:

  • (Hash)

    The flags.



803
804
805
806
807
808
809
810
811
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 803

static VALUE database_get_flags(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env,
                                             self, "flags", 0, 0, MDB_RDONLY);
        unsigned int flags;
        check(mdb_dbi_flags(need_txn(database->env), database->dbi, &flags));
        return flags2hash(flags);
}

#get(key) ⇒ Object

Retrieves one value associated with this key. This function retrieves key/data pairs from the database. If the database supports duplicate keys (:dupsort) then the first data item for the key will be returned. Retrieval of other items requires the use of #cursor.

Parameters:

  • key

    The key of the record to retrieve.



884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 884

static VALUE database_get(VALUE self, VALUE vkey) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self, "get", 1, &vkey, MDB_RDONLY);

        vkey = StringValue(vkey);
        MDB_val key, value;
        key.mv_size = RSTRING_LEN(vkey);
        key.mv_data = RSTRING_PTR(vkey);

        int ret = mdb_get(need_txn(database->env), database->dbi, &key, &value);
        if (ret == MDB_NOTFOUND)
                return Qnil;
        check(ret);
        return rb_str_new(value.mv_data, value.mv_size);
}

#has?(key, value = nil) ⇒ Boolean

Test if the database has a given key (or, if opened in :dupsort, value)

Returns:

  • (Boolean)


111
112
113
114
115
116
117
118
119
120
121
# File 'lib/isomorfeus/hamster/database.rb', line 111

def has? key, value = nil
  v = get(key) or return false
  return true if value.nil? or value.to_s == v
  return false unless dupsort?

  env.transaction true do
    cursor do |c|
      return !!c.set(key, value)
    end
  end
end

#keysArray

Get the keys as an array.

Returns:

  • (Array)

    of keys.



49
50
51
# File 'lib/isomorfeus/hamster/database.rb', line 49

def keys
  each_key.to_a
end

#put(key, value, options) ⇒ Object

Stores items into a database. This function stores key/value pairs in the database. The default behavior is to enter the new key/value pair, replacing any previously existing key if duplicates are disallowed, or adding a duplicate data item if duplicates are allowed (:dupsort).

Parameters:

  • key

    The key of the record to set

  • value

    The value to insert for this key

Options Hash (options):

  • :nodupdata (Boolean)

    Enter the new key/value pair only if it does not already appear in the database. This flag may only be specified if the database was opened with :dupsort. The function will raise an Error if the key/data pair already appears in the database.

  • :nooverwrite (Boolean)

    Enter the new key/value pair only if the key does not already appear in the database. The function will raise an {Error] if the key already appears in the database, even if the database supports duplicates (:dupsort).

  • :append (Boolean)

    Append the given key/data pair to the end of the database. No key comparisons are performed. This option allows fast bulk loading when keys are already known to be in the correct order. Loading unsorted keys with this flag will cause data corruption.

  • :appenddup (Boolean)

    As above, but for sorted dup data.



934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 934

static VALUE database_put(int argc, VALUE *argv, VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env, self, "put", argc, argv, 0);

        VALUE vkey, vval, option_hash;
        rb_scan_args(argc, argv, "2:", &vkey, &vval, &option_hash);

        int flags = 0;
        if (!NIL_P(option_hash))
                rb_hash_foreach(option_hash, database_put_flags, (VALUE)&flags);

        vkey = StringValue(vkey);
        vval = StringValue(vval);

        MDB_val key, value;
        key.mv_size = RSTRING_LEN(vkey);
        key.mv_data = RSTRING_PTR(vkey);
        value.mv_size = RSTRING_LEN(vval);
        value.mv_data = RSTRING_PTR(vval);

        check(mdb_put(need_txn(database->env), database->dbi, &key, &value, flags));
        return Qnil;
}

#sizeObject

Returns the number of records in this database.

Returns:

  • the number of records in this database



132
133
134
# File 'lib/isomorfeus/hamster/database.rb', line 132

def size
  stat[:entries]
end

#statHash

Return useful statistics about a database.

  • :psize Size of a database page

  • :depth Depth (height) of the B-tree

  • :branch_pages Number of internal (non-leaf) pages

  • :leaf_pages Number of leaf pages

  • :overflow_pages Number of overflow pages

  • :entries Number of data items

Returns:

  • (Hash)

    the statistics



787
788
789
790
791
792
793
794
795
796
# File 'ext/isomorfeus_hamster_ext/isomorfeus_hamster.c', line 787

static VALUE database_stat(VALUE self) {
        DATABASE(self, database);
        if (!active_txn(database->env))
                return call_with_transaction(database->env,
                                             self, "stat", 0, 0, MDB_RDONLY);

        MDB_stat stat;
        check(mdb_stat(need_txn(database->env), database->dbi, &stat));
        return stat2hash(&stat);
}