sdsykes-ferret 0.11.6.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. data/CHANGELOG +24 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +102 -0
  4. data/Rakefile +338 -0
  5. data/TODO +17 -0
  6. data/TUTORIAL +231 -0
  7. data/bin/ferret-browser +79 -0
  8. data/ext/analysis.c +1555 -0
  9. data/ext/analysis.h +219 -0
  10. data/ext/api.c +69 -0
  11. data/ext/api.h +27 -0
  12. data/ext/array.c +123 -0
  13. data/ext/array.h +53 -0
  14. data/ext/bitvector.c +540 -0
  15. data/ext/bitvector.h +272 -0
  16. data/ext/compound_io.c +383 -0
  17. data/ext/config.h +42 -0
  18. data/ext/document.c +156 -0
  19. data/ext/document.h +53 -0
  20. data/ext/except.c +120 -0
  21. data/ext/except.h +168 -0
  22. data/ext/extconf.rb +14 -0
  23. data/ext/ferret.c +402 -0
  24. data/ext/ferret.h +91 -0
  25. data/ext/filter.c +156 -0
  26. data/ext/fs_store.c +483 -0
  27. data/ext/global.c +418 -0
  28. data/ext/global.h +117 -0
  29. data/ext/hash.c +567 -0
  30. data/ext/hash.h +473 -0
  31. data/ext/hashset.c +170 -0
  32. data/ext/hashset.h +187 -0
  33. data/ext/header.h +58 -0
  34. data/ext/helper.c +62 -0
  35. data/ext/helper.h +13 -0
  36. data/ext/inc/lang.h +48 -0
  37. data/ext/inc/threading.h +31 -0
  38. data/ext/index.c +6425 -0
  39. data/ext/index.h +961 -0
  40. data/ext/lang.h +66 -0
  41. data/ext/libstemmer.c +92 -0
  42. data/ext/libstemmer.h +79 -0
  43. data/ext/mempool.c +87 -0
  44. data/ext/mempool.h +35 -0
  45. data/ext/modules.h +162 -0
  46. data/ext/multimapper.c +310 -0
  47. data/ext/multimapper.h +51 -0
  48. data/ext/posh.c +1006 -0
  49. data/ext/posh.h +1007 -0
  50. data/ext/priorityqueue.c +151 -0
  51. data/ext/priorityqueue.h +143 -0
  52. data/ext/q_boolean.c +1608 -0
  53. data/ext/q_const_score.c +161 -0
  54. data/ext/q_filtered_query.c +209 -0
  55. data/ext/q_fuzzy.c +268 -0
  56. data/ext/q_match_all.c +148 -0
  57. data/ext/q_multi_term.c +677 -0
  58. data/ext/q_parser.c +2825 -0
  59. data/ext/q_phrase.c +1126 -0
  60. data/ext/q_prefix.c +100 -0
  61. data/ext/q_range.c +350 -0
  62. data/ext/q_span.c +2402 -0
  63. data/ext/q_term.c +337 -0
  64. data/ext/q_wildcard.c +171 -0
  65. data/ext/r_analysis.c +2575 -0
  66. data/ext/r_index.c +3472 -0
  67. data/ext/r_qparser.c +585 -0
  68. data/ext/r_search.c +4105 -0
  69. data/ext/r_store.c +513 -0
  70. data/ext/r_utils.c +963 -0
  71. data/ext/ram_store.c +471 -0
  72. data/ext/search.c +1741 -0
  73. data/ext/search.h +885 -0
  74. data/ext/similarity.c +150 -0
  75. data/ext/similarity.h +82 -0
  76. data/ext/sort.c +983 -0
  77. data/ext/stem_ISO_8859_1_danish.c +338 -0
  78. data/ext/stem_ISO_8859_1_danish.h +16 -0
  79. data/ext/stem_ISO_8859_1_dutch.c +635 -0
  80. data/ext/stem_ISO_8859_1_dutch.h +16 -0
  81. data/ext/stem_ISO_8859_1_english.c +1156 -0
  82. data/ext/stem_ISO_8859_1_english.h +16 -0
  83. data/ext/stem_ISO_8859_1_finnish.c +792 -0
  84. data/ext/stem_ISO_8859_1_finnish.h +16 -0
  85. data/ext/stem_ISO_8859_1_french.c +1276 -0
  86. data/ext/stem_ISO_8859_1_french.h +16 -0
  87. data/ext/stem_ISO_8859_1_german.c +512 -0
  88. data/ext/stem_ISO_8859_1_german.h +16 -0
  89. data/ext/stem_ISO_8859_1_italian.c +1091 -0
  90. data/ext/stem_ISO_8859_1_italian.h +16 -0
  91. data/ext/stem_ISO_8859_1_norwegian.c +296 -0
  92. data/ext/stem_ISO_8859_1_norwegian.h +16 -0
  93. data/ext/stem_ISO_8859_1_porter.c +776 -0
  94. data/ext/stem_ISO_8859_1_porter.h +16 -0
  95. data/ext/stem_ISO_8859_1_portuguese.c +1035 -0
  96. data/ext/stem_ISO_8859_1_portuguese.h +16 -0
  97. data/ext/stem_ISO_8859_1_spanish.c +1119 -0
  98. data/ext/stem_ISO_8859_1_spanish.h +16 -0
  99. data/ext/stem_ISO_8859_1_swedish.c +307 -0
  100. data/ext/stem_ISO_8859_1_swedish.h +16 -0
  101. data/ext/stem_KOI8_R_russian.c +701 -0
  102. data/ext/stem_KOI8_R_russian.h +16 -0
  103. data/ext/stem_UTF_8_danish.c +344 -0
  104. data/ext/stem_UTF_8_danish.h +16 -0
  105. data/ext/stem_UTF_8_dutch.c +653 -0
  106. data/ext/stem_UTF_8_dutch.h +16 -0
  107. data/ext/stem_UTF_8_english.c +1176 -0
  108. data/ext/stem_UTF_8_english.h +16 -0
  109. data/ext/stem_UTF_8_finnish.c +808 -0
  110. data/ext/stem_UTF_8_finnish.h +16 -0
  111. data/ext/stem_UTF_8_french.c +1296 -0
  112. data/ext/stem_UTF_8_french.h +16 -0
  113. data/ext/stem_UTF_8_german.c +526 -0
  114. data/ext/stem_UTF_8_german.h +16 -0
  115. data/ext/stem_UTF_8_italian.c +1113 -0
  116. data/ext/stem_UTF_8_italian.h +16 -0
  117. data/ext/stem_UTF_8_norwegian.c +302 -0
  118. data/ext/stem_UTF_8_norwegian.h +16 -0
  119. data/ext/stem_UTF_8_porter.c +794 -0
  120. data/ext/stem_UTF_8_porter.h +16 -0
  121. data/ext/stem_UTF_8_portuguese.c +1055 -0
  122. data/ext/stem_UTF_8_portuguese.h +16 -0
  123. data/ext/stem_UTF_8_russian.c +709 -0
  124. data/ext/stem_UTF_8_russian.h +16 -0
  125. data/ext/stem_UTF_8_spanish.c +1137 -0
  126. data/ext/stem_UTF_8_spanish.h +16 -0
  127. data/ext/stem_UTF_8_swedish.c +313 -0
  128. data/ext/stem_UTF_8_swedish.h +16 -0
  129. data/ext/stopwords.c +401 -0
  130. data/ext/store.c +692 -0
  131. data/ext/store.h +777 -0
  132. data/ext/term_vectors.c +352 -0
  133. data/ext/threading.h +31 -0
  134. data/ext/utilities.c +446 -0
  135. data/ext/win32.h +54 -0
  136. data/lib/ferret.rb +29 -0
  137. data/lib/ferret/browser.rb +246 -0
  138. data/lib/ferret/browser/s/global.js +192 -0
  139. data/lib/ferret/browser/s/style.css +148 -0
  140. data/lib/ferret/browser/views/document/list.rhtml +49 -0
  141. data/lib/ferret/browser/views/document/show.rhtml +27 -0
  142. data/lib/ferret/browser/views/error/index.rhtml +7 -0
  143. data/lib/ferret/browser/views/help/index.rhtml +8 -0
  144. data/lib/ferret/browser/views/home/index.rhtml +29 -0
  145. data/lib/ferret/browser/views/layout.rhtml +22 -0
  146. data/lib/ferret/browser/views/term-vector/index.rhtml +4 -0
  147. data/lib/ferret/browser/views/term/index.rhtml +199 -0
  148. data/lib/ferret/browser/views/term/termdocs.rhtml +1 -0
  149. data/lib/ferret/browser/webrick.rb +14 -0
  150. data/lib/ferret/document.rb +130 -0
  151. data/lib/ferret/field_infos.rb +44 -0
  152. data/lib/ferret/index.rb +786 -0
  153. data/lib/ferret/number_tools.rb +157 -0
  154. data/lib/ferret_version.rb +3 -0
  155. data/setup.rb +1555 -0
  156. data/test/test_all.rb +5 -0
  157. data/test/test_helper.rb +24 -0
  158. data/test/threading/number_to_spoken.rb +132 -0
  159. data/test/threading/thread_safety_index_test.rb +79 -0
  160. data/test/threading/thread_safety_read_write_test.rb +76 -0
  161. data/test/threading/thread_safety_test.rb +133 -0
  162. data/test/unit/analysis/tc_analyzer.rb +548 -0
  163. data/test/unit/analysis/tc_token_stream.rb +646 -0
  164. data/test/unit/index/tc_index.rb +762 -0
  165. data/test/unit/index/tc_index_reader.rb +699 -0
  166. data/test/unit/index/tc_index_writer.rb +437 -0
  167. data/test/unit/index/th_doc.rb +315 -0
  168. data/test/unit/largefile/tc_largefile.rb +46 -0
  169. data/test/unit/query_parser/tc_query_parser.rb +238 -0
  170. data/test/unit/search/tc_filter.rb +135 -0
  171. data/test/unit/search/tc_fuzzy_query.rb +147 -0
  172. data/test/unit/search/tc_index_searcher.rb +61 -0
  173. data/test/unit/search/tc_multi_searcher.rb +128 -0
  174. data/test/unit/search/tc_multiple_search_requests.rb +58 -0
  175. data/test/unit/search/tc_search_and_sort.rb +179 -0
  176. data/test/unit/search/tc_sort.rb +49 -0
  177. data/test/unit/search/tc_sort_field.rb +27 -0
  178. data/test/unit/search/tc_spans.rb +190 -0
  179. data/test/unit/search/tm_searcher.rb +384 -0
  180. data/test/unit/store/tc_fs_store.rb +77 -0
  181. data/test/unit/store/tc_ram_store.rb +35 -0
  182. data/test/unit/store/tm_store.rb +34 -0
  183. data/test/unit/store/tm_store_lock.rb +68 -0
  184. data/test/unit/tc_document.rb +81 -0
  185. data/test/unit/ts_analysis.rb +2 -0
  186. data/test/unit/ts_index.rb +2 -0
  187. data/test/unit/ts_largefile.rb +4 -0
  188. data/test/unit/ts_query_parser.rb +2 -0
  189. data/test/unit/ts_search.rb +2 -0
  190. data/test/unit/ts_store.rb +2 -0
  191. data/test/unit/ts_utils.rb +2 -0
  192. data/test/unit/utils/tc_bit_vector.rb +295 -0
  193. data/test/unit/utils/tc_number_tools.rb +117 -0
  194. data/test/unit/utils/tc_priority_queue.rb +106 -0
  195. metadata +285 -0
@@ -0,0 +1,513 @@
1
+ #include "ferret.h"
2
+ #include "store.h"
3
+
4
+ static ID id_ref_cnt;
5
+ VALUE cLock;
6
+ VALUE cLockError;
7
+ VALUE cDirectory;
8
+ VALUE cRAMDirectory;
9
+ VALUE cFSDirectory;
10
+
11
+ /****************************************************************************
12
+ *
13
+ * Lock Methods
14
+ *
15
+ ****************************************************************************/
16
+
17
+ void
18
+ frt_unwrap_locks(Store *store)
19
+ {
20
+ int i;
21
+ for (i = 0; i < store->locks->size; i++) {
22
+ void *lock = store->locks->elems[i];
23
+ VALUE rlock = object_get(lock);
24
+ if (rlock != Qnil) {
25
+ object_del(lock);
26
+ Frt_Unwrap_Struct(rlock);
27
+ }
28
+ }
29
+ }
30
+
31
+ void
32
+ frt_lock_free(void *p)
33
+ {
34
+ Lock *lock = (Lock *)p;
35
+ object_del(p);
36
+ close_lock(lock);
37
+ }
38
+
39
+ void
40
+ frt_lock_mark(void *p)
41
+ {
42
+ Lock *lock = (Lock *)p;
43
+ frt_gc_mark(lock->store);
44
+ }
45
+
46
+ #define GET_LOCK(lock, self) Data_Get_Struct(self, Lock, lock)
47
+
48
+ /*
49
+ * call-seq:
50
+ * lock.obtain(timeout = 1) -> bool
51
+ *
52
+ * Obtain a lock. Returns true if lock was successfully obtained. Make sure
53
+ * the lock is released using Lock#release. Otherwise you'll be left with a
54
+ * stale lock file.
55
+ *
56
+ * The timeout defaults to 1 second and 5 attempts are made to obtain the
57
+ * lock. If you're doing large batch updates on the index with multiple
58
+ * processes you may need to increase the lock timeout but 1 second will be
59
+ * substantial in most cases.
60
+ *
61
+ * timeout:: seconds to wait to obtain lock before timing out and returning
62
+ * false
63
+ * return:: true if lock was successfully obtained. Raises a
64
+ * Lock::LockError otherwise.
65
+ */
66
+ static VALUE
67
+ frt_lock_obtain(int argc, VALUE *argv, VALUE self)
68
+ {
69
+ VALUE rtimeout;
70
+ int timeout = 1;
71
+ Lock *lock;
72
+ GET_LOCK(lock, self);
73
+
74
+ if (rb_scan_args(argc, argv, "01", &rtimeout) > 0) {
75
+ timeout = FIX2INT(rtimeout);
76
+ }
77
+ /* TODO: use the lock timeout */
78
+ if (!lock->obtain(lock)) {
79
+ rb_raise(cLockError, "could not obtain lock: #%s", lock->name);
80
+ }
81
+ return Qtrue;
82
+ }
83
+
84
+ /*
85
+ * call-seq:
86
+ * lock.while_locked(timeout = 1) { do_something() } -> bool
87
+ *
88
+ * Run the code in a block while a lock is obtained, automatically releasing
89
+ * the lock when the block returns.
90
+ *
91
+ * See Lock#obtain for more information on lock timeout.
92
+ *
93
+ * timeout:: seconds to wait to obtain lock before timing out and returning
94
+ * false
95
+ * return:: true if lock was successfully obtained. Raises a
96
+ * Lock::LockError otherwise.
97
+ */
98
+ static VALUE
99
+ frt_lock_while_locked(int argc, VALUE *argv, VALUE self)
100
+ {
101
+ VALUE rtimeout;
102
+ int timeout = 1;
103
+ Lock *lock;
104
+ GET_LOCK(lock, self);
105
+ if (rb_scan_args(argc, argv, "01", &rtimeout) > 0) {
106
+ timeout = FIX2INT(rtimeout);
107
+ }
108
+ if (!lock->obtain(lock)) {
109
+ rb_raise(cLockError, "could not obtain lock: #%s", lock->name);
110
+ }
111
+ rb_yield(Qnil);
112
+ lock->release(lock);
113
+ return Qtrue;
114
+ }
115
+
116
+ /*
117
+ * call-seq:
118
+ * lock.locked? -> bool
119
+ *
120
+ * Returns true if the lock has been obtained.
121
+ */
122
+ static VALUE
123
+ frt_lock_is_locked(VALUE self)
124
+ {
125
+ Lock *lock;
126
+ GET_LOCK(lock, self);
127
+ return lock->is_locked(lock) ? Qtrue : Qfalse;
128
+ }
129
+
130
+ /*
131
+ * call-seq:
132
+ * lock.release() -> self
133
+ *
134
+ * Release the lock. This should only be called by the process which obtains
135
+ * the lock.
136
+ */
137
+ static VALUE
138
+ frt_lock_release(VALUE self)
139
+ {
140
+ Lock *lock;
141
+ GET_LOCK(lock, self);
142
+ lock->release(lock);
143
+ return self;
144
+ }
145
+
146
+ /****************************************************************************
147
+ *
148
+ * Directory Methods
149
+ *
150
+ ****************************************************************************/
151
+
152
+ void
153
+ frt_dir_free(Store *store)
154
+ {
155
+ frt_unwrap_locks(store);
156
+ object_del(store);
157
+ store_deref(store);
158
+ }
159
+
160
+ /*
161
+ * call-seq:
162
+ * dir.close() -> nil
163
+ *
164
+ * It is a good idea to close a directory when you have finished using it.
165
+ * Although the garbage collector will currently handle this for you, this
166
+ * behaviour may change in future.
167
+ */
168
+ static VALUE
169
+ frt_dir_close(VALUE self)
170
+ {
171
+ Store *store = DATA_PTR(self);
172
+ int ref_cnt = FIX2INT(rb_ivar_get(self, id_ref_cnt)) - 1;
173
+ rb_ivar_set(self, id_ref_cnt, INT2FIX(ref_cnt));
174
+ if (ref_cnt < 0) {
175
+ Frt_Unwrap_Struct(self);
176
+ object_del(store);
177
+ frt_unwrap_locks(store);
178
+ store_deref(store);
179
+ }
180
+ return Qnil;
181
+ }
182
+
183
+ /*
184
+ * call-seq:
185
+ * dir.exists?(file_name) -> nil
186
+ *
187
+ * Return true if a file with the name +file_name+ exists in the directory.
188
+ */
189
+ static VALUE
190
+ frt_dir_exists(VALUE self, VALUE rfname)
191
+ {
192
+ Store *store = DATA_PTR(self);
193
+ StringValue(rfname);
194
+ return store->exists(store, rs2s(rfname)) ? Qtrue : Qfalse;
195
+ }
196
+
197
+ /*
198
+ * call-seq:
199
+ * dir.touch(file_name) -> nil
200
+ *
201
+ * Create an empty file in the directory with the name +file_name+.
202
+ */
203
+ static VALUE
204
+ frt_dir_touch(VALUE self, VALUE rfname)
205
+ {
206
+ Store *store = DATA_PTR(self);
207
+ StringValue(rfname);
208
+ store->touch(store, rs2s(rfname));
209
+ return Qnil;
210
+ }
211
+
212
+ /*
213
+ * call-seq:
214
+ * dir.delete(file_name) -> nil
215
+ *
216
+ * Remove file +file_name+ from the directory. Returns true if successful.
217
+ */
218
+ static VALUE
219
+ frt_dir_delete(VALUE self, VALUE rfname)
220
+ {
221
+ Store *store = DATA_PTR(self);
222
+ StringValue(rfname);
223
+ return (store->remove(store, rs2s(rfname)) == 0) ? Qtrue : Qfalse;
224
+ }
225
+
226
+ /*
227
+ * call-seq:
228
+ * dir.count -> integer
229
+ *
230
+ * Return a count of the number of files in the directory.
231
+ */
232
+ static VALUE
233
+ frt_dir_file_count(VALUE self)
234
+ {
235
+ Store *store = DATA_PTR(self);
236
+ return INT2FIX(store->count(store));
237
+ }
238
+
239
+ /*
240
+ * call-seq:
241
+ * dir.refresh -> self
242
+ *
243
+ * Delete all files in the directory. It gives you a clean slate.
244
+ */
245
+ static VALUE
246
+ frt_dir_refresh(VALUE self)
247
+ {
248
+ Store *store = DATA_PTR(self);
249
+ store->clear_all(store);
250
+ return self;
251
+ }
252
+
253
+ /*
254
+ * call-seq:
255
+ * dir.rename(from, to) -> self
256
+ *
257
+ * Rename a file from +from+ to +to+. An error will be raised if the file
258
+ * doesn't exist or there is some other type of IOError.
259
+ */
260
+ static VALUE
261
+ frt_dir_rename(VALUE self, VALUE rfrom, VALUE rto)
262
+ {
263
+ Store *store = DATA_PTR(self);
264
+ StringValue(rfrom);
265
+ StringValue(rto);
266
+ store->rename(store, rs2s(rfrom), rs2s(rto));
267
+ return self;
268
+ }
269
+
270
+ /*
271
+ * call-seq:
272
+ * dir.make_lock(lock_name) -> self
273
+ *
274
+ * Make a lock with the name +lock_name+. Note that lockfiles will be stored
275
+ * in the directory with other files but they won't be visible to you. You
276
+ * should avoid using files with a .lck extension as this extension is
277
+ * reserved for lock files
278
+ */
279
+ static VALUE
280
+ frt_dir_make_lock(VALUE self, VALUE rlock_name)
281
+ {
282
+ VALUE rlock;
283
+ Lock *lock;
284
+ Store *store = DATA_PTR(self);
285
+ StringValue(rlock_name);
286
+ lock = open_lock(store, rs2s(rlock_name));
287
+ rlock = Data_Wrap_Struct(cLock, &frt_lock_mark, &frt_lock_free, lock);
288
+ object_add(lock, rlock);
289
+ return rlock;
290
+ }
291
+
292
+ /****************************************************************************
293
+ *
294
+ * RAMDirectory Methods
295
+ *
296
+ ****************************************************************************/
297
+
298
+ /*
299
+ * call-seq:
300
+ * RAMDirectory.new(dir = nil)
301
+ *
302
+ * Create a new RAMDirectory.
303
+ *
304
+ * You can optionally load another Directory (usually a FSDirectory) into
305
+ * memory. This may be useful to speed up search performance but usually the
306
+ * speedup won't be worth the trouble. Be sure to benchmark.
307
+ *
308
+ * dir:: Directory to load into memory
309
+ */
310
+ static VALUE
311
+ frt_ramdir_init(int argc, VALUE *argv, VALUE self)
312
+ {
313
+ VALUE rdir;
314
+ Store *store;
315
+ switch (rb_scan_args(argc, argv, "01", &rdir)) {
316
+ case 1: {
317
+ Store *ostore;
318
+ Data_Get_Struct(rdir, Store, ostore);
319
+ store = open_ram_store_and_copy(ostore, false);
320
+ break;
321
+ }
322
+ default: store = open_ram_store();
323
+ }
324
+ Frt_Wrap_Struct(self, NULL, &frt_dir_free, store);
325
+ object_add(store, self);
326
+ rb_ivar_set(self, id_ref_cnt, INT2FIX(0));
327
+ return self;
328
+ }
329
+
330
+ /****************************************************************************
331
+ *
332
+ * FSDirectory Methods
333
+ *
334
+ ****************************************************************************/
335
+
336
+ /*
337
+ * call-seq:
338
+ * FSDirectory.new(/path/to/index/, create = false)
339
+ *
340
+ * Create a new FSDirectory at +/path/to/index/+ which must be a valid path
341
+ * on your file system. If it doesn't exist it will be created. You can also
342
+ * specify the +create+ parameter. If +create+ is true the FSDirectory will
343
+ * be refreshed as new. That is to say, any existing files in the directory
344
+ * will be deleted. The default value for +create+ is false.
345
+ *
346
+ * path:: path to index directory. Must be a valid path on your system
347
+ * create:: set to true if you want any existing files in the directory to be
348
+ * deleted
349
+ */
350
+ static VALUE
351
+ frt_fsdir_new(int argc, VALUE *argv, VALUE klass)
352
+ {
353
+ VALUE self, rpath, rcreate;
354
+ Store *store;
355
+ bool create;
356
+
357
+ rb_scan_args(argc, argv, "11", &rpath, &rcreate);
358
+ StringValue(rpath);
359
+ create = RTEST(rcreate);
360
+ if (create) {
361
+ frt_create_dir(rpath);
362
+ }
363
+ if (!rb_funcall(rb_cFile, id_is_directory, 1, rpath)) {
364
+ rb_raise(rb_eIOError, "No directory <%s> found. Use :create => true"
365
+ " to create one.", rs2s(rpath));
366
+ }
367
+ store = open_fs_store(rs2s(rpath));
368
+ if (create) store->clear_all(store);
369
+ if ((self = object_get(store)) == Qnil) {
370
+ self = Data_Wrap_Struct(klass, NULL, &frt_dir_free, store);
371
+ object_add(store, self);
372
+ rb_ivar_set(self, id_ref_cnt, INT2FIX(0));
373
+ }
374
+ else {
375
+ int ref_cnt = FIX2INT(rb_ivar_get(self, id_ref_cnt)) + 1;
376
+ rb_ivar_set(self, id_ref_cnt, INT2FIX(ref_cnt));
377
+ DEREF(store);
378
+ }
379
+ return self;
380
+ }
381
+
382
+ /****************************************************************************
383
+ *
384
+ * Init Function
385
+ *
386
+ ****************************************************************************/
387
+
388
+ /*
389
+ * Document-class: Ferret::Store::Directory
390
+ *
391
+ * A Directory is an object which is used to access the index storage.
392
+ * Ruby's IO API is not used so that we can use different storage
393
+ * mechanisms to store the index. Some examples are;
394
+ *
395
+ * * File system based storage (currently implemented as FSDirectory)
396
+ * * RAM based storage (currently implemented as RAMDirectory)
397
+ * * Database based storage
398
+ *
399
+ * NOTE: Once a file has been written and closed, it can no longer be
400
+ * modified. To make any changes to the file it must be deleted and
401
+ * rewritten. For this reason, the method to open a file for writing is
402
+ * called _create_output_, while the method to open a file for reading is
403
+ * called _open_input_ If there is a risk of simultaneous modifications of
404
+ * the files then locks should be used. See Lock to find out how.
405
+ */
406
+ void
407
+ Init_Directory(void)
408
+ {
409
+ cDirectory = rb_define_class_under(mStore, "Directory", rb_cObject);
410
+ rb_define_const(cDirectory, "LOCK_PREFIX", rb_str_new2(LOCK_PREFIX));
411
+ rb_define_method(cDirectory, "close", frt_dir_close, 0);
412
+ rb_define_method(cDirectory, "exists?", frt_dir_exists, 1);
413
+ rb_define_method(cDirectory, "touch", frt_dir_touch, 1);
414
+ rb_define_method(cDirectory, "delete", frt_dir_delete, 1);
415
+ rb_define_method(cDirectory, "file_count", frt_dir_file_count, 0);
416
+ rb_define_method(cDirectory, "refresh", frt_dir_refresh, 0);
417
+ rb_define_method(cDirectory, "rename", frt_dir_rename, 2);
418
+ rb_define_method(cDirectory, "make_lock", frt_dir_make_lock, 1);
419
+ }
420
+
421
+ /*
422
+ * Document-class: Ferret::Store::Lock
423
+ *
424
+ * A Lock is used to lock a data source so that not more than one
425
+ * output stream can access a data source at one time. It is possible
426
+ * that locks could be disabled. For example a read only index stored
427
+ * on a CDROM would have no need for a lock.
428
+ *
429
+ * You can use a lock in two ways. Firstly:
430
+ *
431
+ * write_lock = @directory.make_lock(LOCK_NAME)
432
+ * write_lock.obtain(WRITE_LOCK_TIME_OUT)
433
+ * ... # Do your file modifications # ...
434
+ * write_lock.release()
435
+ *
436
+ * Alternatively you could use the while locked method. This ensures that
437
+ * the lock will be released once processing has finished.
438
+ *
439
+ * write_lock = @directory.make_lock(LOCK_NAME)
440
+ * write_lock.while_locked(WRITE_LOCK_TIME_OUT) do
441
+ * ... # Do your file modifications # ...
442
+ * end
443
+ */
444
+ void
445
+ Init_Lock(void)
446
+ {
447
+ cLock = rb_define_class_under(mStore, "Lock", rb_cObject);
448
+ rb_define_method(cLock, "obtain", frt_lock_obtain, -1);
449
+ rb_define_method(cLock, "while_locked", frt_lock_while_locked, -1);
450
+ rb_define_method(cLock, "release", frt_lock_release, 0);
451
+ rb_define_method(cLock, "locked?", frt_lock_is_locked, 0);
452
+
453
+ cLockError = rb_define_class_under(cLock, "LockError", rb_eStandardError);
454
+ }
455
+
456
+ /*
457
+ * Document-class: Ferret::Store::RAMDirectory
458
+ *
459
+ * Memory resident Directory implementation. You should use a RAMDirectory
460
+ * during testing but otherwise you should stick with FSDirectory. While
461
+ * loading an index into memory may slightly speed things up, on most
462
+ * operating systems there won't be much difference so it wouldn't be worth
463
+ * your trouble.
464
+ */
465
+ void
466
+ Init_RAMDirectory(void)
467
+ {
468
+ cRAMDirectory = rb_define_class_under(mStore, "RAMDirectory", cDirectory);
469
+ rb_define_alloc_func(cRAMDirectory, frt_data_alloc);
470
+ rb_define_method(cRAMDirectory, "initialize", frt_ramdir_init, -1);
471
+ }
472
+
473
+ /*
474
+ * Document-class: Ferret::Store::RAMDirectory
475
+ *
476
+ * File-system resident Directory implementation. The FSDirectory will use a
477
+ * single directory to store all of it's files. You should not otherwise
478
+ * touch this directory. Modifying the files in the directory will corrupt
479
+ * the index. The one exception to this rule is you may need to delete stale
480
+ * lock files which have a ".lck" extension.
481
+ */
482
+ void
483
+ Init_FSDirectory(void)
484
+ {
485
+ cFSDirectory = rb_define_class_under(mStore, "FSDirectory", cDirectory);
486
+ rb_define_alloc_func(cFSDirectory, frt_data_alloc);
487
+ rb_define_singleton_method(cFSDirectory, "new", frt_fsdir_new, -1);
488
+ }
489
+
490
+ /* rdoc hack
491
+ extern VALUE mFerret = rb_define_module("Ferret");
492
+ */
493
+
494
+ /*
495
+ * Document-module: Ferret::Store
496
+ *
497
+ * The Store module contains all the classes required to handle the storing
498
+ * of an index.
499
+ *
500
+ * NOTE: You can currently store an index on a file-system or in memory. If
501
+ * you want to add a different type of Directory, like a database Directory
502
+ * for instance, you will to implement it in C.
503
+ */
504
+ void
505
+ Init_Store(void)
506
+ {
507
+ id_ref_cnt = rb_intern("@id_ref_cnt");
508
+ mStore = rb_define_module_under(mFerret, "Store");
509
+ Init_Directory();
510
+ Init_Lock();
511
+ Init_RAMDirectory();
512
+ Init_FSDirectory();
513
+ }