jio 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }