jio 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ #ifndef JIO_FILE_H
2
+ #define JIO_FILE_H
3
+
4
+ #define JIO_FILE_CLOSED 0x01
5
+
6
+ typedef struct {
7
+ jfs_t *fs;
8
+ int flags;
9
+ } jio_jfs_wrapper;
10
+
11
+ #define JioAssertFile(obj) JioAssertType(obj, rb_cJioFile, "JIO::File")
12
+ #define JioGetFile(obj) \
13
+ jio_jfs_wrapper *file = NULL; \
14
+ JioAssertFile(obj); \
15
+ Data_Get_Struct(obj, jio_jfs_wrapper, file); \
16
+ if (!file) rb_raise(rb_eTypeError, "uninitialized JIO file handle!");
17
+
18
+ void _init_rb_jio_file();
19
+
20
+ #endif
@@ -0,0 +1,119 @@
1
+ #include "jio_ext.h"
2
+
3
+ VALUE mJio;
4
+ VALUE rb_cJioFile;
5
+ VALUE rb_cJioTransaction;
6
+
7
+ VALUE jio_zero;
8
+ VALUE jio_empty_view;
9
+
10
+ #ifdef HAVE_RUBY_ENCODING_H
11
+ rb_encoding *binary_encoding;
12
+ #endif
13
+
14
+ static VALUE jio_s_total;
15
+ static VALUE jio_s_invalid;
16
+ static VALUE jio_s_in_progress;
17
+ static VALUE jio_s_broken;
18
+ static VALUE jio_s_corrupt;
19
+ static VALUE jio_s_reapplied;
20
+
21
+ /*
22
+ * call-seq:
23
+ * JIO.check("/path/file", JIO::J_CLEANUP) => Hash
24
+ *
25
+ * Checks and repairs a file previously created and managed through libjio.
26
+ *
27
+ * === Examples
28
+ * JIO.check("/path/file", JIO::J_CLEANUP) => Hash
29
+ *
30
+ */
31
+
32
+ static VALUE rb_jio_s_check(JIO_UNUSED VALUE jio, VALUE path, VALUE flags)
33
+ {
34
+ int ret;
35
+ VALUE result;
36
+ struct jfsck_result res;
37
+ Check_Type(path, T_STRING);
38
+ Check_Type(flags, T_FIXNUM);
39
+ ret = jfsck(RSTRING_PTR(path), NULL, &res, FIX2UINT(flags));
40
+ if (ret == J_ENOMEM) rb_memerror();
41
+ if (ret < 0) rb_sys_fail("jfsck");
42
+ result = rb_hash_new();
43
+ rb_hash_aset(result, jio_s_total, INT2NUM(res.total));
44
+ rb_hash_aset(result, jio_s_invalid, INT2NUM(res.invalid));
45
+ rb_hash_aset(result, jio_s_in_progress, INT2NUM(res.in_progress));
46
+ rb_hash_aset(result, jio_s_broken, INT2NUM(res.broken));
47
+ rb_hash_aset(result, jio_s_corrupt, INT2NUM(res.corrupt));
48
+ rb_hash_aset(result, jio_s_reapplied, INT2NUM(res.reapplied));
49
+ return result;
50
+ }
51
+
52
+ void
53
+ Init_jio_ext()
54
+ {
55
+ mJio = rb_define_module("JIO");
56
+
57
+ /*
58
+ * Generic globals (Fixnum 0 and empty Array for blank transaction views)
59
+ */
60
+ jio_zero = INT2NUM(0);
61
+ rb_gc_register_address(&jio_empty_view);
62
+ jio_empty_view = rb_ary_new();
63
+
64
+ jio_s_total = ID2SYM(rb_intern("total"));
65
+ jio_s_invalid = ID2SYM(rb_intern("invalid"));
66
+ jio_s_in_progress = ID2SYM(rb_intern("in_progress"));
67
+ jio_s_broken = ID2SYM(rb_intern("broken"));
68
+ jio_s_corrupt = ID2SYM(rb_intern("corrupt"));
69
+ jio_s_reapplied = ID2SYM(rb_intern("reapplied"));
70
+
71
+ #ifdef HAVE_RUBY_ENCODING_H
72
+ binary_encoding = rb_enc_find("binary");
73
+ #endif
74
+
75
+ /*
76
+ * Journal check specific constants
77
+ */
78
+ rb_define_const(mJio, "J_ESUCCESS", INT2NUM(J_ESUCCESS));
79
+ rb_define_const(mJio, "J_ENOENT", INT2NUM(J_ENOENT));
80
+ rb_define_const(mJio, "J_ENOJOURNAL", INT2NUM(J_ENOJOURNAL));
81
+ rb_define_const(mJio, "J_ENOMEM", INT2NUM(J_ENOMEM));
82
+ rb_define_const(mJio, "J_ECLEANUP", INT2NUM(J_ECLEANUP));
83
+ rb_define_const(mJio, "J_EIO", INT2NUM(J_EIO));
84
+
85
+ /*
86
+ * jfscheck specific constants
87
+ */
88
+ rb_define_const(mJio, "J_CLEANUP", INT2NUM(J_CLEANUP));
89
+
90
+ /*
91
+ * Open specific constants (POSIX)
92
+ */
93
+ rb_define_const(mJio, "RDONLY", INT2NUM(O_RDONLY));
94
+ rb_define_const(mJio, "WRONLY", INT2NUM(O_WRONLY));
95
+ rb_define_const(mJio, "RDWR", INT2NUM(O_RDWR));
96
+ rb_define_const(mJio, "CREAT", INT2NUM(O_CREAT));
97
+ rb_define_const(mJio, "EXCL", INT2NUM(O_EXCL));
98
+ rb_define_const(mJio, "TRUNC", INT2NUM(O_TRUNC));
99
+ rb_define_const(mJio, "APPEND", INT2NUM(O_APPEND));
100
+ rb_define_const(mJio, "NONBLOCK", INT2NUM(O_NONBLOCK));
101
+ rb_define_const(mJio, "NDELAY", INT2NUM(O_NDELAY));
102
+ rb_define_const(mJio, "SYNC", INT2NUM(O_SYNC));
103
+ rb_define_const(mJio, "ASYNC", INT2NUM(O_ASYNC));
104
+
105
+ /*
106
+ * lseek specific constants
107
+ */
108
+ rb_define_const(mJio, "SEEK_SET", INT2NUM(SEEK_SET));
109
+ rb_define_const(mJio, "SEEK_CUR", INT2NUM(SEEK_CUR));
110
+ rb_define_const(mJio, "SEEK_END", INT2NUM(SEEK_END));
111
+
112
+ /*
113
+ * JIO module methods
114
+ */
115
+ rb_define_module_function(mJio, "check", rb_jio_s_check, 2);
116
+
117
+ _init_rb_jio_file();
118
+ _init_rb_jio_transaction();
119
+ }
@@ -0,0 +1,46 @@
1
+ #ifndef JIO_EXT_H
2
+ #define JIO_EXT_H
3
+
4
+ #include "libjio.h"
5
+ #include "trans.h"
6
+ #include "ruby.h"
7
+ #include <sys/types.h>
8
+ #include <sys/stat.h>
9
+ #include <fcntl.h>
10
+ #include <unistd.h>
11
+
12
+ /* Compiler specific */
13
+
14
+ #if defined(__GNUC__) && (__GNUC__ >= 3)
15
+ #define JIO_UNUSED __attribute__ ((unused))
16
+ #define JIO_NOINLINE __attribute__ ((noinline))
17
+ #else
18
+ #define JIO_UNUSED
19
+ #define JIO_NOINLINE
20
+ #endif
21
+
22
+ #include "jio_prelude.h"
23
+
24
+ #define JioAssertType(obj, type, desc) \
25
+ if (!rb_obj_is_kind_of(obj,type)) \
26
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected %s): %s", rb_obj_classname(obj), desc, RSTRING_PTR(rb_obj_as_string(obj)));
27
+
28
+ #define AssertOffset(off) \
29
+ Check_Type(off, T_FIXNUM); \
30
+ if (off < jio_zero) rb_raise(rb_eArgError, "offset must be >= 0"); \
31
+
32
+ #define AssertLength(len) \
33
+ Check_Type(len, T_FIXNUM); \
34
+ if (len < jio_zero) rb_raise(rb_eArgError, "length must be >= 0"); \
35
+
36
+ #include "file.h"
37
+ #include "transaction.h"
38
+
39
+ extern VALUE mJio;
40
+ extern VALUE rb_cJioFile;
41
+ extern VALUE rb_cJioTransaction;
42
+
43
+ extern VALUE jio_zero;
44
+ extern VALUE jio_empty_view;
45
+
46
+ #endif
@@ -0,0 +1,22 @@
1
+ #ifndef JIO_PRELUDE_H
2
+ #define JIO_PRELUDE_H
3
+
4
+ #ifndef RFLOAT_VALUE
5
+ #define RFLOAT_VALUE(v) (RFLOAT(v)->value)
6
+ #endif
7
+
8
+ #ifdef RUBINIUS
9
+ #include "rubinius.h"
10
+ #else
11
+ #ifdef JRUBY
12
+ #include "jruby.h"
13
+ #else
14
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
15
+ #include "ruby19.h"
16
+ #else
17
+ #include "ruby18.h"
18
+ #endif
19
+ #endif
20
+ #endif
21
+
22
+ #endif
@@ -0,0 +1,20 @@
1
+ #ifndef JIO_JRUBY_H
2
+ #define JIO_JRUBY_H
3
+
4
+ #include "st.h"
5
+
6
+ /* XXX */
7
+ #define JioEncode(str) str
8
+ #ifndef THREAD_PASS
9
+ #define THREAD_PASS rb_thread_schedule();
10
+ #endif
11
+
12
+ #define TRAP_BEG
13
+ #define TRAP_END
14
+
15
+ #undef rb_errinfo
16
+ #define rb_errinfo() (rb_gv_get("$!"))
17
+
18
+ #define HAVE_RB_THREAD_BLOCKING_REGION 1
19
+
20
+ #endif
@@ -0,0 +1,22 @@
1
+ #ifndef JIO_RUBINIUS_H
2
+ #define JIO_RUBINIUS_H
3
+
4
+ #define RSTRING_NOT_MODIFIED
5
+
6
+ #ifdef HAVE_RUBY_ENCODING_H
7
+ #include <ruby/st.h>
8
+ #include <ruby/encoding.h>
9
+ #include <ruby/io.h>
10
+ extern rb_encoding *binary_encoding;
11
+ #define JioEncode(str) rb_enc_associate(str, binary_encoding)
12
+ #else
13
+ #include "st.h"
14
+ #define JioEncode(str) str
15
+ #endif
16
+
17
+ #define TRAP_BEG
18
+ #define TRAP_END
19
+
20
+ #define THREAD_PASS rb_thread_schedule();
21
+
22
+ #endif
@@ -0,0 +1,43 @@
1
+ #ifndef JIO_RUBY18_H
2
+ #define JIO_RUBY18_H
3
+
4
+ #define THREAD_PASS rb_thread_schedule();
5
+ #define JioEncode(str) str
6
+ #include "rubyio.h"
7
+ #include "rubysig.h"
8
+ #include "st.h"
9
+
10
+ #ifndef RSTRING_PTR
11
+ #define RSTRING_PTR(str) RSTRING(str)->ptr
12
+ #endif
13
+ #ifndef RSTRING_LEN
14
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
15
+ #endif
16
+
17
+ /*
18
+ * partial emulation of the 1.9 rb_thread_blocking_region under 1.8,
19
+ * this is enough for dealing with blocking I/O functions in the
20
+ * presence of threads.
21
+ */
22
+
23
+ #define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
24
+ typedef void rb_unblock_function_t(void *);
25
+ typedef VALUE rb_blocking_function_t(void *);
26
+ static VALUE
27
+ rb_thread_blocking_region(
28
+ rb_blocking_function_t *func, void *data1,
29
+ JIO_UNUSED rb_unblock_function_t *ubf,
30
+ JIO_UNUSED void *data2)
31
+ {
32
+ VALUE rv;
33
+ TRAP_BEG;
34
+ rv = func(data1);
35
+ TRAP_END;
36
+ return rv;
37
+ }
38
+
39
+ struct timeval rb_time_interval _((VALUE));
40
+
41
+ #define rb_errinfo() ruby_errinfo
42
+
43
+ #endif
@@ -0,0 +1,15 @@
1
+ #ifndef JIO_RUBY19_H
2
+ #define JIO_RUBY19_H
3
+
4
+ #include <ruby/encoding.h>
5
+ #include <ruby/io.h>
6
+ extern rb_encoding *binary_encoding;
7
+ #define JioEncode(str) rb_enc_associate(str, binary_encoding)
8
+ #ifndef THREAD_PASS
9
+ #define THREAD_PASS rb_thread_schedule();
10
+ #endif
11
+
12
+ #define TRAP_BEG
13
+ #define TRAP_END
14
+
15
+ #endif
@@ -0,0 +1,260 @@
1
+ #include "jio_ext.h"
2
+
3
+ /*
4
+ * Generic transaction error handler
5
+ */
6
+ static inline VALUE rb_jio_transaction_result(ssize_t ret, const char *ctx)
7
+ {
8
+ char err_buf[BUFSIZ];
9
+ if (ret >= 0) return Qtrue;
10
+ if (ret == -1) snprintf(err_buf, BUFSIZ, "JIO transaction error on %s (atomic warranties preserved)", ctx);
11
+ if (ret == -2) snprintf(err_buf, BUFSIZ, "JIO transaction error on %s (atomic warranties broken)", ctx);
12
+ rb_sys_fail(err_buf);
13
+ }
14
+
15
+ /*
16
+ * GC callbacks for JIO::Transaction
17
+ */
18
+ void rb_jio_mark_transaction(void *ptr)
19
+ {
20
+ jio_jtrans_wrapper *trans = (jio_jtrans_wrapper *)ptr;
21
+ if (ptr) rb_gc_mark(trans->views);
22
+ }
23
+
24
+ void rb_jio_free_transaction(void *ptr)
25
+ {
26
+ jio_jtrans_wrapper *trans = (jio_jtrans_wrapper *)ptr;
27
+ if(trans) {
28
+ if (trans->trans != NULL && !(trans->flags & JIO_TRANSACTION_RELEASED)) jtrans_free(trans->trans);
29
+ xfree(trans);
30
+ }
31
+ }
32
+
33
+ /*
34
+ * call-seq:
35
+ * transaction.read(2, 2) => boolean
36
+ *
37
+ * Reads X bytes from Y offset into a transaction view. The buffered data is only visible once the
38
+ * transaction has been committed.
39
+ *
40
+ * === Examples
41
+ * transaction.read(2, 2) => boolean
42
+ *
43
+ */
44
+
45
+ static VALUE rb_jio_transaction_read(VALUE obj, VALUE length, VALUE offset)
46
+ {
47
+ int ret;
48
+ VALUE buf;
49
+ ssize_t len;
50
+ JioGetTransaction(obj);
51
+ AssertLength(length);
52
+ AssertOffset(offset);
53
+ len = (ssize_t)FIX2LONG(length);
54
+ buf = rb_str_new(0, len);
55
+ TRAP_BEG;
56
+ ret = jtrans_add_r(trans->trans, RSTRING_PTR(buf), len, (off_t)NUM2OFFT(offset));
57
+ TRAP_END;
58
+ if (ret == -1) rb_sys_fail("jtrans_add_r");
59
+ if (NIL_P(trans->views)) trans->views = rb_ary_new();
60
+ rb_ary_push(trans->views, JioEncode(buf));
61
+ return Qtrue;
62
+ }
63
+
64
+ /*
65
+ * call-seq:
66
+ * transaction.views => Array
67
+ *
68
+ * Returns a sequence of buffers representing previous transactional read operations. The result is
69
+ * always an empty Array if the transaction hasn't been committed yet. Operations will be applied in
70
+ * order, and overlapping operations are permitted, in which case the latest one will prevail.
71
+ *
72
+ * === Examples
73
+ * transaction.views => Array
74
+ *
75
+ */
76
+
77
+ static VALUE rb_jio_transaction_views(VALUE obj)
78
+ {
79
+ jtrans_t *t = NULL;
80
+ JioGetTransaction(obj);
81
+ t = trans->trans;
82
+ if ((t->flags & J_COMMITTED) && !NIL_P(trans->views)) return trans->views;
83
+ return jio_empty_view;
84
+ }
85
+
86
+ /*
87
+ * call-seq:
88
+ * transaction.write("data", 2) => boolean
89
+ *
90
+ * Spawns a write operation from a given buffer to X offset for this transaction. Only written to disk
91
+ * when the transaction has been committed. Operations will be applied in order, and overlapping
92
+ * operations are permitted, in which case the latest one will prevail.
93
+ *
94
+ * === Examples
95
+ * transaction.write("data", 2) => boolean
96
+ *
97
+ */
98
+
99
+ static VALUE rb_jio_transaction_write(VALUE obj, VALUE buf, VALUE offset)
100
+ {
101
+ int ret;
102
+ JioGetTransaction(obj);
103
+ Check_Type(buf, T_STRING);
104
+ AssertOffset(offset);
105
+ TRAP_BEG;
106
+ ret = jtrans_add_w(trans->trans, RSTRING_PTR(buf), (size_t)RSTRING_LEN(buf), (off_t)NUM2OFFT(offset));
107
+ TRAP_END;
108
+ if (ret == -1) rb_sys_fail("jtrans_add_w");
109
+ return Qtrue;
110
+ }
111
+
112
+ /*
113
+ * call-seq:
114
+ * transaction.commit => boolean
115
+ *
116
+ * Reads / writes all operations for this transaction to / from disk, in the order they were added.
117
+ * After this function returns successfully, all the data can be trusted to be on the disk. The commit
118
+ * is atomic with regards to other processes using libjio, but not accessing directly to the file.
119
+ *
120
+ * === Examples
121
+ * transaction.commit => boolean
122
+ *
123
+ */
124
+
125
+ static VALUE rb_jio_transaction_commit(VALUE obj)
126
+ {
127
+ ssize_t ret;
128
+ JioGetTransaction(obj);
129
+ TRAP_BEG;
130
+ ret = jtrans_commit(trans->trans);
131
+ TRAP_END;
132
+ return rb_jio_transaction_result(ret, "commit");
133
+ }
134
+
135
+ /*
136
+ * call-seq:
137
+ * transaction.rollback => boolean
138
+ *
139
+ * This function atomically undoes a previous committed transaction. After its successful return, the
140
+ * data can be trusted to be on disk. The read operations will be ignored as we only care about on disk
141
+ * consistency.
142
+ *
143
+ * === Examples
144
+ * transaction.rollback => boolean
145
+ *
146
+ */
147
+
148
+ static VALUE rb_jio_transaction_rollback(VALUE obj)
149
+ {
150
+ ssize_t ret;
151
+ VALUE res;
152
+ JioGetTransaction(obj);
153
+ TRAP_BEG;
154
+ ret = jtrans_rollback(trans->trans);
155
+ TRAP_END;
156
+ res = rb_jio_transaction_result(ret, "rollback");
157
+ if (!NIL_P(trans->views)) rb_ary_clear(trans->views);
158
+ return res;
159
+ }
160
+
161
+ /*
162
+ * call-seq:
163
+ * transaction.release => nil
164
+ *
165
+ * Free all transaction state and operation buffers
166
+ *
167
+ * === Examples
168
+ * transaction.release => nil
169
+ *
170
+ */
171
+
172
+ static VALUE rb_jio_transaction_release(VALUE obj)
173
+ {
174
+ JioGetTransaction(obj);
175
+ TRAP_BEG;
176
+ jtrans_free(trans->trans);
177
+ TRAP_END;
178
+ trans->flags |= JIO_TRANSACTION_RELEASED;
179
+ return Qnil;
180
+ }
181
+
182
+ /*
183
+ * call-seq:
184
+ * transaction.committed? => boolean
185
+ *
186
+ * Determines if this transaction has been committed.
187
+ *
188
+ * === Examples
189
+ * transaction.committed? => boolean
190
+ *
191
+ */
192
+
193
+ static VALUE rb_jio_transaction_committed_p(VALUE obj)
194
+ {
195
+ jtrans_t *t = NULL;
196
+ JioGetTransaction(obj);
197
+ t = trans->trans;
198
+ return (t->flags & J_COMMITTED) ? Qtrue : Qfalse;
199
+ }
200
+
201
+ /*
202
+ * call-seq:
203
+ * transaction.rollbacked? => boolean
204
+ *
205
+ * Determines if this transaction has been rolled back.
206
+ *
207
+ * === Examples
208
+ * transaction.rollbacked? => boolean
209
+ *
210
+ */
211
+
212
+ static VALUE rb_jio_transaction_rollbacked_p(VALUE obj)
213
+ {
214
+ jtrans_t *t = NULL;
215
+ JioGetTransaction(obj);
216
+ t = trans->trans;
217
+ return (t->flags & J_ROLLBACKED) ? Qtrue : Qfalse;
218
+ }
219
+
220
+ /*
221
+ * call-seq:
222
+ * transaction.rollbacking? => boolean
223
+ *
224
+ * Determines if this transaction is in the process of being rolled back.
225
+ *
226
+ * === Examples
227
+ * transaction.rollbacking? => boolean
228
+ *
229
+ */
230
+
231
+ static VALUE rb_jio_transaction_rollbacking_p(VALUE obj)
232
+ {
233
+ jtrans_t *t = NULL;
234
+ JioGetTransaction(obj);
235
+ t = trans->trans;
236
+ return (t->flags & J_ROLLBACKING) ? Qtrue : Qfalse;
237
+ }
238
+
239
+ void _init_rb_jio_transaction()
240
+ {
241
+ rb_define_const(mJio, "J_NOLOCK", INT2NUM(J_NOLOCK));
242
+ rb_define_const(mJio, "J_NOROLLBACK", INT2NUM(J_NOROLLBACK));
243
+ rb_define_const(mJio, "J_LINGER", INT2NUM(J_LINGER));
244
+ rb_define_const(mJio, "J_COMMITTED", INT2NUM(J_COMMITTED));
245
+ rb_define_const(mJio, "J_ROLLBACKED", INT2NUM(J_ROLLBACKED));
246
+ rb_define_const(mJio, "J_ROLLBACKING", INT2NUM(J_ROLLBACKING));
247
+ rb_define_const(mJio, "J_RDONLY", INT2NUM(J_RDONLY));
248
+
249
+ rb_cJioTransaction = rb_define_class_under(mJio, "Transaction", rb_cObject);
250
+
251
+ rb_define_method(rb_cJioTransaction, "read", rb_jio_transaction_read, 2);
252
+ rb_define_method(rb_cJioTransaction, "views", rb_jio_transaction_views, 0);
253
+ rb_define_method(rb_cJioTransaction, "write", rb_jio_transaction_write, 2);
254
+ rb_define_method(rb_cJioTransaction, "commit", rb_jio_transaction_commit, 0);
255
+ rb_define_method(rb_cJioTransaction, "rollback", rb_jio_transaction_rollback, 0);
256
+ rb_define_method(rb_cJioTransaction, "release", rb_jio_transaction_release, 0);
257
+ rb_define_method(rb_cJioTransaction, "committed?", rb_jio_transaction_committed_p, 0);
258
+ rb_define_method(rb_cJioTransaction, "rollbacked?", rb_jio_transaction_rollbacked_p, 0);
259
+ rb_define_method(rb_cJioTransaction, "rollbacking?", rb_jio_transaction_rollbacking_p, 0);
260
+ }