Brian Gan
2008-Mar-05  17:06 UTC
[Ferret-talk] Index Searcher Causes GC Memory Error: "irb: double free or corruption"
My linux Ruby application is using Ferret 0.11.4.  I created my own class
IndexSearcher to contain
the Searcher of multiple directories.  If I do not have the searcher.close
called, the end of
runner/console or runner/server will pop out with system error:
*** glibc detected *** irb: double free or corruption (fasttop): 0x0a51d6c0 ***
======= Backtrace: ========/lib/libc.so.6[0x638ac1]
/lib/libc.so.6(cfree+0x90)[0x63c0f0]
/usr/lib/ruby/gems/gems/ferret-0.11.4/lib/ferret_ext.so[0x247d75]
/usr/lib/ruby/gems/gems/ferret-0.11.4/lib/ferret_ext.so[0x219745]
/usr/lib/libruby.so.1.8(rb_gc_call_finalizer_at_exit+0xa7)[0xc3e237]
/usr/lib/libruby.so.1.8[0xc239e7]
/usr/lib/libruby.so.1.8(ruby_cleanup+0x100)[0xc2c280]
/usr/lib/libruby.so.1.8(ruby_stop+0x1d)[0xc2c3ad]
/usr/lib/libruby.so.1.8[0xc372c1]
irb[0x804868d]
/lib/libc.so.6(__libc_start_main+0xe0)[0x5e5390]
irb[0x8048581]
Here is the code of my class.  Any sign of what is wrong with the memory
handling?
class IndexSearcher
	attr_accessor :searcher, :sub_searchers, :object_type
	# @param paths [Array of String] full local paths
	def initialize( object_type, paths )
		# Would''ve used this way since it''s simpler and said by
author to be faster; but invalid paths
will break this entirely
		# self.searcher =
Ferret::Search::Searcher.new(Ferret::Index::IndexReader.new(paths) )
		self.sub_searchers = []
		paths.each do |cur_path|
			begin
				sub_s = Ferret::Search::Searcher.new(cur_path )
				self.sub_searchers << sub_s if sub_s
			rescue Exception => index_e
				puts "** IndexSearcher.new: #{index_e.message}"
			end
		end
		if self.sub_searchers.size > 0
			self.searcher = Ferret::Search::MultiSearcher.new(self.sub_searchers)
		else
			self.searcher = (Ferret::I.new).searcher
		end
		self.object_type = object_type
	end
	# This doc/[] has a different to Index method: argument only wants doc_id
[Integer]
	def doc(doc_id)
		return self.searcher[doc_id]
	rescue Exception => e
		puts "** IndexSearcher(#{object_type}).doc #{doc_id}\n" <<
e.backtrace.join("\n")
		return nil
	end
	alias :[] :doc
	#############################
	# Querying methods
	def process_query(query)
		query.is_a?(Ferret::Search::Query) ? query :
SearchIndex::QUERY_PARSER.parse(query)
	end
	def search(query, options = {})
		query_obj = process_query(query)
		self.searcher.search( query_obj, options )
	end
	def search_each (query, options = {})
		query_obj = process_query(query)
		self.searcher.search_each( query_obj, options )
	end
	def explain (query, doc)
		query_obj = process_query(query)
		self.searcher.explain( query_obj, doc )
	end
	# Segmentation Fault when index_searcher.highlight
	def highlight (query, doc_id, options = {})
		query_obj = process_query(query)
		doc = self.searcher[doc_id]
		field_value = doc[options[:field] ]
		field_index = Ferret::I.new(:analyzer => SearchIndex::STEMMING_ANALYZER)
		field_index << {:keywords => field_value}
		fvh = field_index.highlight(query, 0, options.merge({ :field => :keywords
}) )
		return fvh
	rescue Exception => e
		puts "** IndexSearch.highlight(''#{query}''):
#{e.message}" # << e.backtrace.join("\n")
		return field_value
	end
	def doc_freq(field, term)
		self.searcher.doc_freq(field, term)
	end
	#############################
	# Self Util methods
	def reader
		self.searcher.reader
	end
	def size
		if reader
			total_size = reader.num_docs
		else
			total_size = 0
			self.sub_searchers.each do |sub_searcher|
				total_size += sub_searcher.reader.num_docs if sub_searcher.reader
			end
			return total_size
		end
	end
	alias :num_docs :size
	def close
		self.searcher.close
	end
end
