ferret 0.1.3 → 0.1.4
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.
- data/Rakefile +1 -1
- data/TODO +3 -0
- data/ext/dummy.exe +0 -0
- data/lib/ferret.rb +1 -1
- data/lib/ferret/analysis/token.rb +6 -0
- data/lib/ferret/analysis/tokenizers.rb +5 -5
- data/lib/ferret/document/document.rb +10 -13
- data/lib/ferret/index/compound_file_io.rb +12 -9
- data/lib/ferret/index/field_infos.rb +0 -6
- data/lib/ferret/index/index.rb +220 -102
- data/lib/ferret/index/index_reader.rb +22 -2
- data/lib/ferret/index/index_writer.rb +55 -14
- data/lib/ferret/index/multi_reader.rb +279 -279
- data/lib/ferret/index/segment_infos.rb +3 -3
- data/lib/ferret/index/segment_merger.rb +7 -6
- data/lib/ferret/index/segment_reader.rb +23 -7
- data/lib/ferret/index/segment_term_enum.rb +6 -7
- data/lib/ferret/index/term_buffer.rb +3 -5
- data/lib/ferret/index/term_doc_enum.rb +7 -2
- data/lib/ferret/index/term_infos_io.rb +15 -8
- data/lib/ferret/query_parser/query_parser.tab.rb +49 -45
- data/lib/ferret/search/boolean_query.rb +3 -4
- data/lib/ferret/search/boolean_scorer.rb +11 -11
- data/lib/ferret/search/caching_wrapper_filter.rb +1 -1
- data/lib/ferret/search/disjunction_sum_scorer.rb +9 -7
- data/lib/ferret/search/field_cache.rb +1 -2
- data/lib/ferret/search/field_sorted_hit_queue.rb +1 -1
- data/lib/ferret/search/fuzzy_term_enum.rb +64 -58
- data/lib/ferret/search/index_searcher.rb +16 -9
- data/lib/ferret/search/prefix_query.rb +7 -0
- data/lib/ferret/search/query_filter.rb +1 -1
- data/lib/ferret/search/term_scorer.rb +5 -1
- data/lib/ferret/search/top_docs.rb +12 -0
- data/lib/ferret/store/buffered_index_io.rb +5 -6
- data/lib/ferret/store/fs_store.rb +47 -33
- data/lib/ferret/store/ram_store.rb +2 -2
- data/lib/ferret/utils.rb +1 -0
- data/lib/ferret/utils/bit_vector.rb +20 -2
- data/lib/ferret/utils/thread_local.rb +28 -0
- data/lib/ferret/utils/weak_key_hash.rb +11 -2
- data/test/benchmark/tb_rw_vint.rb +1 -1
- data/test/functional/thread_safety_index_test.rb +81 -0
- data/test/functional/thread_safety_test.rb +137 -0
- data/test/test_all.rb +3 -7
- data/test/test_helper.rb +2 -1
- data/test/unit/index/tc_compound_file_io.rb +2 -2
- data/test/unit/index/tc_index.rb +128 -6
- data/test/unit/index/tc_index_reader.rb +1 -1
- data/test/unit/index/tc_segment_infos.rb +1 -1
- data/test/unit/index/th_doc.rb +1 -1
- data/test/unit/search/tc_index_searcher.rb +6 -0
- data/test/unit/store/tc_fs_store.rb +3 -3
- data/test/unit/utils/tc_bit_vector.rb +8 -0
- data/test/unit/utils/tc_thread.rb +61 -0
- data/test/unit/utils/tc_weak_key_hash.rb +2 -2
- data/test/utils/number_to_spoken.rb +132 -0
- metadata +7 -2
@@ -251,10 +251,9 @@ module Ferret::Search
|
|
251
251
|
return Query.merge_boolean_queries(queries)
|
252
252
|
end
|
253
253
|
|
254
|
-
def
|
255
|
-
|
256
|
-
|
257
|
-
return clone
|
254
|
+
def initialize_copy(o)
|
255
|
+
super
|
256
|
+
@clauses = o.clauses.clone
|
258
257
|
end
|
259
258
|
|
260
259
|
# Prints a user-readable version of this query.
|
@@ -87,11 +87,11 @@ module Ferret::Search
|
|
87
87
|
def next?
|
88
88
|
return @scorer.next?
|
89
89
|
end
|
90
|
-
def skip_to(
|
91
|
-
return @scorer.skip_to(
|
90
|
+
def skip_to(doc_num)
|
91
|
+
return @scorer.skip_to(doc_num)
|
92
92
|
end
|
93
|
-
def explain(
|
94
|
-
return @scorer.explain(
|
93
|
+
def explain(doc_num)
|
94
|
+
return @scorer.explain(doc_num)
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -116,13 +116,13 @@ module Ferret::Search
|
|
116
116
|
def initialize(parent_scorer, similarity)
|
117
117
|
super(similarity)
|
118
118
|
@parent_scorer = parent_scorer
|
119
|
-
@
|
119
|
+
@required_num_matchers = parent_scorer.required_scorers.size
|
120
120
|
@last_scored_doc = -1
|
121
121
|
end
|
122
122
|
def score
|
123
123
|
if (@parent_scorer.doc() > @last_scored_doc)
|
124
124
|
@last_scored_doc = @parent_scorer.doc()
|
125
|
-
@parent_scorer.coordinator.nr_matchers += @
|
125
|
+
@parent_scorer.coordinator.nr_matchers += @required_num_matchers
|
126
126
|
end
|
127
127
|
|
128
128
|
return super
|
@@ -132,7 +132,7 @@ module Ferret::Search
|
|
132
132
|
def counting_conjunction_sum_scorer(required_scorers)
|
133
133
|
# each scorer from the list counted as a single matcher
|
134
134
|
|
135
|
-
|
135
|
+
required_num_matchers = required_scorers.size
|
136
136
|
ccs = CountingConjunctionScorer.new(self, Similarity.default)
|
137
137
|
@required_scorers.each do |scorer|
|
138
138
|
ccs << scorer
|
@@ -239,13 +239,13 @@ module Ferret::Search
|
|
239
239
|
# returns:: true if more matching documents may remain.
|
240
240
|
def each_hit_up_to(max = MAX_DOCS) # :yields: doc, score
|
241
241
|
# nil pointer exception when next? was not called before:
|
242
|
-
|
243
|
-
while (
|
244
|
-
yield(
|
242
|
+
doc_num = @counting_sum_scorer.doc()
|
243
|
+
while (doc_num < max)
|
244
|
+
yield(doc_num, score())
|
245
245
|
if not @counting_sum_scorer.next?
|
246
246
|
return false
|
247
247
|
end
|
248
|
-
|
248
|
+
doc_num = @counting_sum_scorer.doc()
|
249
249
|
end
|
250
250
|
return true
|
251
251
|
end
|
@@ -8,13 +8,15 @@ module Ferret::Search
|
|
8
8
|
# Construct a +DisjunctionScorer+.
|
9
9
|
# sub_scorers:: A collection of at least two subscorers.
|
10
10
|
#
|
11
|
-
# minimum_nr_matchers:: The positive minimum number of subscorers that
|
12
|
-
# match to match this query.
|
13
|
-
#
|
14
|
-
# the number
|
15
|
-
# no matches will be produced.
|
16
|
-
#
|
17
|
-
#
|
11
|
+
# minimum_nr_matchers:: The positive minimum number of subscorers that
|
12
|
+
# should match to match this query.
|
13
|
+
#
|
14
|
+
# When +@minimum_nr_matchers+ is bigger than the number
|
15
|
+
# of +sub_scorers+,no matches will be produced.
|
16
|
+
#
|
17
|
+
# When @minimum_nr_matchers equals the number of
|
18
|
+
# sub_scorers, it more efficient to use
|
19
|
+
# +ConjunctionScorer+.
|
18
20
|
def initialize(sub_scorers, minimum_nr_matchers = 1)
|
19
21
|
super(nil)
|
20
22
|
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Ferret::Search
|
2
|
-
require 'monitor'
|
3
2
|
|
4
3
|
# Expert: The default cache implementation, storing all values in memory.
|
5
4
|
# A WeakKeyHash is used for storage.
|
@@ -36,7 +35,7 @@ module Ferret::Search
|
|
36
35
|
FLOAT_PARSER = lambda {|i| i.to_f}
|
37
36
|
|
38
37
|
# The internal cache. Maps Entry to array of interpreted term values.
|
39
|
-
@@cache = Ferret::Utils::WeakKeyHash.new
|
38
|
+
@@cache = Ferret::Utils::WeakKeyHash.new
|
40
39
|
|
41
40
|
# See if an object is in the cache.
|
42
41
|
def FieldCache.lookup(reader, field, sort_type)
|
@@ -83,7 +83,7 @@ module Ferret::Search
|
|
83
83
|
|
84
84
|
# Internal cache of comparators. Similar to FieldCache, only
|
85
85
|
# caches comparators instead of term values.
|
86
|
-
@@comparators = Ferret::Utils::WeakKeyHash.new
|
86
|
+
@@comparators = Ferret::Utils::WeakKeyHash.new
|
87
87
|
|
88
88
|
# Returns a comparator if it is in the cache.
|
89
89
|
def lookup(reader, field, sort_type, comproc)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
1
3
|
module Ferret::Search
|
2
4
|
# Subclass of FilteredTermEnum for enumerating all terms that are similiar
|
3
5
|
# to the specified filter term.
|
@@ -5,6 +7,8 @@ module Ferret::Search
|
|
5
7
|
# Term enumerations are always ordered by Term.compareTo(). Each term in
|
6
8
|
# the enumeration is greater than all that precede it.
|
7
9
|
class FuzzyTermEnum < FilteredTermEnum
|
10
|
+
include MonitorMixin
|
11
|
+
|
8
12
|
include Ferret::Index
|
9
13
|
attr_reader :end_enum
|
10
14
|
|
@@ -144,73 +148,75 @@ module Ferret::Search
|
|
144
148
|
# than the required threshold and 1.0 indicates that the text and
|
145
149
|
# target are identical
|
146
150
|
def similarity(target)
|
147
|
-
|
148
|
-
|
151
|
+
synchronize do
|
152
|
+
m = target.length
|
153
|
+
n = @text.length
|
154
|
+
|
155
|
+
if (n == 0)
|
156
|
+
# we don't have anything to compare. That means if we just add the
|
157
|
+
# letters for m we get the new word
|
158
|
+
return (@prefix_length == 0) ? 0.0 : 1.0 - (m.to_f / @prefix_length)
|
159
|
+
end
|
160
|
+
if (m == 0)
|
161
|
+
return (@prefix_length == 0) ? 0.0 : 1.0 - (n.to_f / @prefix_length)
|
162
|
+
end
|
149
163
|
|
150
|
-
|
151
|
-
# we don't have anything to compare. That means if we just add the
|
152
|
-
# letters for m we get the new word
|
153
|
-
return (@prefix_length == 0) ? 0.0 : 1.0 - (m.to_f / @prefix_length)
|
154
|
-
end
|
155
|
-
if (m == 0)
|
156
|
-
return (@prefix_length == 0) ? 0.0 : 1.0 - (n.to_f / @prefix_length)
|
157
|
-
end
|
164
|
+
max_distance = max_distance(m)
|
158
165
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
return 0.0
|
170
|
-
end
|
166
|
+
if (max_distance < (m-n).abs)
|
167
|
+
#just adding the characters of m to n or vice-versa results in
|
168
|
+
#too many edits
|
169
|
+
#for example "pre" length is 3 and "prefixes" length is 8. We can see that
|
170
|
+
#given this optimal circumstance, the edit distance cannot be less than 5.
|
171
|
+
#which is 8-3 or more precisesly Math.abs(3-8).
|
172
|
+
#if our maximum edit distance is 4, then we can discard this word
|
173
|
+
#without looking at it.
|
174
|
+
return 0.0
|
175
|
+
end
|
171
176
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
177
|
+
#let's make sure we have enough room in our array to do the distance calculations.
|
178
|
+
if (@d[0].length <= m)
|
179
|
+
grow_distance_array(m)
|
180
|
+
end
|
176
181
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
182
|
+
# init matrix d
|
183
|
+
(n+1).times {|i| @d[i][0] = i}
|
184
|
+
(m+1).times {|j| @d[0][j] = j}
|
185
|
+
|
186
|
+
# start computing edit distance
|
187
|
+
1.upto(n) do |i|
|
188
|
+
best_possible_edit_distance = m
|
189
|
+
s_i = @text[i-1]
|
190
|
+
1.upto(m) do |j|
|
191
|
+
if (s_i != target[j-1])
|
192
|
+
@d[i][j] = min(@d[i-1][j], @d[i][j-1], @d[i-1][j-1])+1
|
193
|
+
else
|
194
|
+
@d[i][j] = min(@d[i-1][j]+1, @d[i][j-1]+1, @d[i-1][j-1])
|
195
|
+
end
|
196
|
+
if @d[i][j] < best_possible_edit_distance
|
197
|
+
best_possible_edit_distance = @d[i][j]
|
198
|
+
end
|
190
199
|
end
|
191
|
-
|
192
|
-
|
200
|
+
|
201
|
+
# After calculating row i, the best possible edit distance can be
|
202
|
+
# found by found by finding the smallest value in a given column.
|
203
|
+
# If the best_possible_edit_distance is greater than the max distance,
|
204
|
+
# abort.
|
205
|
+
if (i > max_distance and best_possible_edit_distance > max_distance)
|
206
|
+
# equal is okay, but not greater
|
207
|
+
# the closest the target can be to the text is just too far away.
|
208
|
+
# this target is leaving the party early.
|
209
|
+
return 0.0
|
193
210
|
end
|
194
211
|
end
|
195
212
|
|
196
|
-
#
|
197
|
-
#
|
198
|
-
#
|
199
|
-
#
|
200
|
-
|
201
|
-
|
202
|
-
# the closest the target can be to the text is just too far away.
|
203
|
-
# this target is leaving the party early.
|
204
|
-
return 0.0
|
205
|
-
end
|
213
|
+
# this will return less than 0.0 when the edit distance is
|
214
|
+
# greater than the number of characters in the shorter word.
|
215
|
+
# but this was the formula that was previously used in FuzzyTermEnum,
|
216
|
+
# so it has not been changed (even though minimum_similarity must be
|
217
|
+
# greater than 0.0)
|
218
|
+
return 1.0 - (@d[n][m].to_f / (@prefix_length + (n < m ? n : m)))
|
206
219
|
end
|
207
|
-
|
208
|
-
# this will return less than 0.0 when the edit distance is
|
209
|
-
# greater than the number of characters in the shorter word.
|
210
|
-
# but this was the formula that was previously used in FuzzyTermEnum,
|
211
|
-
# so it has not been changed (even though minimum_similarity must be
|
212
|
-
# greater than 0.0)
|
213
|
-
return 1.0 - (@d[n][m].to_f / (@prefix_length + (n < m ? n : m)))
|
214
220
|
end
|
215
221
|
|
216
222
|
# Grow the second dimension of the array, so that we can calculate the
|
@@ -11,13 +11,20 @@ module Ferret::Search
|
|
11
11
|
attr_accessor :similarity, :reader
|
12
12
|
|
13
13
|
# Creates a searcher searching the index in the provided directory.
|
14
|
+
#
|
15
|
+
# You need to pass one argument which should be one of the following:
|
16
|
+
#
|
17
|
+
# * An index reader which the searcher will search
|
18
|
+
# * A directory where the searcher will open an index reader to search
|
19
|
+
# * A string which represents a path to the directory to be searched
|
20
|
+
#
|
14
21
|
def initialize(arg)
|
15
22
|
if arg.is_a?(IndexReader)
|
16
23
|
@reader = arg
|
17
24
|
elsif arg.is_a?(Ferret::Store::Directory)
|
18
|
-
@reader = IndexReader.open(arg)
|
25
|
+
@reader = IndexReader.open(arg, false)
|
19
26
|
elsif arg.is_a?(String)
|
20
|
-
@dir = Ferret::Store::FSDirectory.new(arg,
|
27
|
+
@dir = Ferret::Store::FSDirectory.new(arg, false)
|
21
28
|
@reader = IndexReader.open(@dir, true)
|
22
29
|
else
|
23
30
|
raise ArgumentError, "Unknown argument passed to initialize IndexReader"
|
@@ -50,10 +57,10 @@ module Ferret::Search
|
|
50
57
|
end
|
51
58
|
|
52
59
|
# Expert: Returns the stored fields of document +i+.
|
53
|
-
#
|
60
|
+
#
|
54
61
|
# See IndexReader#get_document
|
55
62
|
def doc(i)
|
56
|
-
return @reader.
|
63
|
+
return @reader.get_document(i)
|
57
64
|
end
|
58
65
|
|
59
66
|
# Expert: Returns one greater than the largest possible document number.
|
@@ -73,12 +80,12 @@ module Ferret::Search
|
|
73
80
|
# pass to this method. You can also pass a hash with one or more of the
|
74
81
|
# following; {filter, num_docs, first_doc, sort}
|
75
82
|
#
|
76
|
-
# query::
|
77
|
-
# filter::
|
83
|
+
# query:: The query to run on the index
|
84
|
+
# filter:: filters docs from the search result
|
78
85
|
# first_doc:: The index in the results of the first doc retrieved.
|
79
|
-
#
|
80
|
-
# num_docs::
|
81
|
-
# sort::
|
86
|
+
# Default is 0
|
87
|
+
# num_docs:: The number of results returned. Default is 10
|
88
|
+
# sort:: An array of SortFields describing how to sort the results.
|
82
89
|
def search(query, options = {})
|
83
90
|
filter = options[:filter]
|
84
91
|
first_doc = options[:first_doc]||0
|
@@ -25,6 +25,8 @@ module Ferret::Search
|
|
25
25
|
@weight = weight
|
26
26
|
@term_docs = td
|
27
27
|
@norms = norms
|
28
|
+
#XXX
|
29
|
+
@norms_size = @norms.size
|
28
30
|
@weight_value = weight.value
|
29
31
|
|
30
32
|
SCORE_CACHE_SIZE.times do |i|
|
@@ -85,8 +87,10 @@ module Ferret::Search
|
|
85
87
|
|
86
88
|
|
87
89
|
# Advances to the next document matching the query.
|
88
|
-
#
|
90
|
+
#
|
91
|
+
# The iterator over the matching documents is buffered using
|
89
92
|
# TermDocEnum#read(int[],int[]).
|
93
|
+
#
|
90
94
|
# returns:: true iff there is another document matching the query.
|
91
95
|
def next?()
|
92
96
|
@pointer += 1
|
@@ -5,6 +5,18 @@ module Ferret::Search
|
|
5
5
|
# Expert: The total number of hits for the query.
|
6
6
|
# See Hits#length()
|
7
7
|
attr_accessor :score_docs, :total_hits, :fields
|
8
|
+
alias :size :total_hits
|
9
|
+
|
10
|
+
# iterate through each of the score docs, yielding the document number and
|
11
|
+
# the score. eg:
|
12
|
+
#
|
13
|
+
# top_docs.each do |doc, score|
|
14
|
+
# puts "Doc number #{doc} found with score of #{score}"}
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
def each
|
18
|
+
score_docs.each {|sd| yield(sd.doc, sd.score) }
|
19
|
+
end
|
8
20
|
|
9
21
|
# Expert: Constructs a TopDocs.
|
10
22
|
def initialize(total_hits, score_docs, fields = SortField::FIELD_SCORE)
|
@@ -140,14 +140,13 @@ module Ferret::Store
|
|
140
140
|
# Creates a clone of the BufferedIndexReader. Reading from a
|
141
141
|
# BufferedIndexInput should not change the state (read position) in the
|
142
142
|
# clone and vice-versa.
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
return bii
|
143
|
+
def initialize_copy(o)
|
144
|
+
super
|
145
|
+
@buffer = o.buffer.clone if o.buffer
|
147
146
|
end
|
148
147
|
|
149
|
-
|
150
|
-
protected :buffer
|
148
|
+
attr_reader :buffer
|
149
|
+
protected :buffer
|
151
150
|
|
152
151
|
private
|
153
152
|
|
@@ -31,6 +31,30 @@ module Ferret::Store
|
|
31
31
|
# The lock dir is the directory where the file locks will be stored
|
32
32
|
LOCK_DIR = nil
|
33
33
|
|
34
|
+
# Create a new directory from the path.
|
35
|
+
# path:: the path to the directory.
|
36
|
+
# create:: if true, create, or erase any existing contents.
|
37
|
+
def initialize(path, create)
|
38
|
+
super()
|
39
|
+
if create then FileUtils.mkdir_p(path) end
|
40
|
+
if not File.directory?(path) then
|
41
|
+
raise "There is no directory: #{path}. Use create = true to create one"
|
42
|
+
end
|
43
|
+
@dir = Dir.new(path)
|
44
|
+
# put the lock_dir here as well if no default exists.
|
45
|
+
if LOCK_DIR then
|
46
|
+
@lock_dir = Dir.new(LOCK_DIR)
|
47
|
+
else
|
48
|
+
@lock_dir = Dir.new(path)
|
49
|
+
end
|
50
|
+
@ref_count = 0
|
51
|
+
end
|
52
|
+
|
53
|
+
class <<FSDirectory
|
54
|
+
alias :allocate :new
|
55
|
+
protected :allocate
|
56
|
+
end
|
57
|
+
|
34
58
|
# Returns the directory instance for the named location.
|
35
59
|
#
|
36
60
|
# Directories are cached, so that, for a given canonical path, the same
|
@@ -39,12 +63,12 @@ module Ferret::Store
|
|
39
63
|
#
|
40
64
|
# path:: the path to the directory.
|
41
65
|
# create:: if true, create, or erase any existing contents.
|
42
|
-
def FSDirectory.
|
66
|
+
def FSDirectory.new(path, create = false)
|
43
67
|
dir = nil
|
44
68
|
@@Directories.synchronize do
|
45
69
|
dir = @@Directories[path]
|
46
70
|
if not dir then
|
47
|
-
dir = FSDirectory.
|
71
|
+
dir = FSDirectory.allocate(path, create)
|
48
72
|
@@Directories[path] = dir
|
49
73
|
end
|
50
74
|
dir.refresh if create
|
@@ -76,6 +100,7 @@ module Ferret::Store
|
|
76
100
|
def refresh
|
77
101
|
synchronize do
|
78
102
|
# delete all the files
|
103
|
+
refresh_dir
|
79
104
|
each do |fname|
|
80
105
|
File.delete(dir_path(fname))
|
81
106
|
end
|
@@ -133,7 +158,9 @@ module Ferret::Store
|
|
133
158
|
# If a file already exists with the new name, then it is replaced.
|
134
159
|
# This replacement should be atomic.
|
135
160
|
def rename(from, to)
|
136
|
-
|
161
|
+
synchronize do
|
162
|
+
File.rename(dir_path(from), dir_path(to))
|
163
|
+
end
|
137
164
|
end
|
138
165
|
|
139
166
|
|
@@ -160,10 +187,12 @@ module Ferret::Store
|
|
160
187
|
|
161
188
|
# Closes the store.
|
162
189
|
def close()
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
@@Directories.
|
190
|
+
synchronize do
|
191
|
+
@ref_count -= 1
|
192
|
+
if (@ref_count <= 0) then
|
193
|
+
@@Directories.synchronize do
|
194
|
+
@@Directories.delete(@dir.path)
|
195
|
+
end
|
167
196
|
end
|
168
197
|
end
|
169
198
|
end
|
@@ -242,29 +271,32 @@ module Ferret::Store
|
|
242
271
|
|
243
272
|
# A file system input stream extending InputStream to read from the file system
|
244
273
|
class FSIndexInput < BufferedIndexInput
|
245
|
-
|
246
|
-
attr_reader :
|
247
|
-
attr_reader :file
|
274
|
+
attr_accessor :is_clone
|
275
|
+
attr_reader :length, :file
|
248
276
|
|
249
277
|
def initialize(path)
|
250
278
|
@file = File.open(path, "rb")
|
251
279
|
@file.extend(MonitorMixin)
|
280
|
+
#class <<@file
|
281
|
+
# attr_accessor :ref_count
|
282
|
+
#end
|
283
|
+
#@file.ref_count = 1
|
252
284
|
@length = File.size(path)
|
253
285
|
@is_clone = false
|
254
286
|
super()
|
255
287
|
end
|
256
288
|
|
257
289
|
def close
|
290
|
+
#@file.ref_count -= 1
|
291
|
+
#@file.close if @file.ref_count == 0
|
258
292
|
@file.close if not @is_clone
|
259
293
|
end
|
260
294
|
|
261
295
|
# We need to record if this is a clone so we know when to close the file.
|
262
296
|
# The file should only be closed when the original FSIndexInput is closed.
|
263
|
-
def
|
264
|
-
|
265
|
-
|
266
|
-
fsii.file.seek(@file.pos)
|
267
|
-
return fsii
|
297
|
+
def initialize_copy(o)
|
298
|
+
super
|
299
|
+
@is_clone = true
|
268
300
|
end
|
269
301
|
|
270
302
|
private
|
@@ -290,24 +322,6 @@ module Ferret::Store
|
|
290
322
|
end
|
291
323
|
|
292
324
|
private
|
293
|
-
# Create a new directory from the path.
|
294
|
-
# path:: the path to the directory.
|
295
|
-
# create:: if true, create, or erase any existing contents.
|
296
|
-
def initialize(path, create)
|
297
|
-
super()
|
298
|
-
if create then FileUtils.mkdir_p(path) end
|
299
|
-
if not File.directory?(path) then
|
300
|
-
raise "There is no directory: #{path}. Use create = true to create one"
|
301
|
-
end
|
302
|
-
@dir = Dir.new(path)
|
303
|
-
# put the lock_dir here as well if no default exists.
|
304
|
-
if LOCK_DIR then
|
305
|
-
@lock_dir = Dir.new(LOCK_DIR)
|
306
|
-
else
|
307
|
-
@lock_dir = Dir.new(path)
|
308
|
-
end
|
309
|
-
@ref_count = 0
|
310
|
-
end
|
311
325
|
|
312
326
|
# Add the directory path to the file name for opening
|
313
327
|
def dir_path(name)
|