Synchronous Cycle Collectionの適当なRuby実装


元の論文はこれです。
Concurrent Cycle Collection in Reference Counted Systems

http://www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf

この中の、Fig. 2. Synchronous Cycle Collectionを丸写してクラスメソッドにしました。
以下ソースです。

require 'set'

class S
	attr_accessor :color, :buffered, :rc, :children

	def initialize(data)
		@rc = 0
		@children = Hash.new
		@color = :black
		@buffered = false
		@data = data
		@@roots = Set.new
		print "new("+@data+")\n"
	end

	def delete()
		print "delete("+@data+")\n"
	end

	def []=(i, o)
		if (@children.key?(i))
			self.class.decrement(@children[i])
		end

		if (o == nil)
			@children.delete(i)
		else
			@children[i] = o
			self.class.increment(o)
		end
	end

	def [](i)
		@children[i]
	end

	def self.increment(s)
		s.rc = s.rc + 1
		s.color = :black
	end

	def self.decrement(s)
		s.rc = s.rc - 1
		if (s.rc == 0)
			release(s)
		else
			possibleRoot(s)
		end
	end

	def self.release(s)
		s.children.each do |k,t|
			decrement(t)
		end
		s.color = :black
		if (!s.buffered)
			 s.delete
		end
	end

	def self.possibleRoot(s)
		if (s.color != :purple)
			s.color = :purple
			if (!s.buffered)
				s.buffered = true
				@@roots.add(s)
			end
		end
	end

	def self.collectCycles()
		markRoots()
		scanRoots()
		collectRoots()
	end

	def self.markRoots()
		@@roots.each do |s|
			if (s.color == :purple)
				markGray(s)
			else
				s.buffered = false
				@@roots.delete(s)
				if (s.color == :black && s.rc == 0)
					s.delete
				end
			end
		end
	end

	def self.scanRoots()
		@@roots.each do |s|
			scan(s)
		end
	end

	def self.collectRoots()
		@@roots.each do |s|
			s.buffered = false
			collectWhite(s)
		end
		@@roots.clear
	end

	def self.markGray(s)
		if (s.color != :gray)
			s.color = :gray
			s.children.each do |k,t|
				t.rc = t.rc - 1
				markGray(t)
			end
		end
	end

	def self.scan(s)
		if (s.color == :gray)
			if (s.rc > 0)
				scanBlack(s)
			else
				s.color = :white
				s.children.each do |k,t|
					scan(t)
				end
			end
		end
	end

	def self.scanBlack(s)
		s.color = :black
		s.children.each do |k,t|
			t.rc = t.rc + 1
			if (t.color != :black)
				scanBlack(t)
			end
		end
	end

	def self.collectWhite(s)
		if (s.color == :white && !s.buffered)
			s.color = :black
			s.children.each do |k,t|
				collectWhite(t)
			end
			s.delete
		end

	end

end

def main()
	t = S.new("root")
	S.increment(t)

	t[:a] = S.new("a")
	t[:b] = S.new("b")
	print("delete root\n")
	t[:a] = nil
	t[:b] = nil
	print("ok\n")
	print("increment root 2\n")
	t[:a] = S.new("d")
	t[:a][:a] = S.new("e")
	t[:a][:a][:a] = S.new("f")
	print("--\n")
	print("increment root 3\n")
	t[:b] = S.new("g")
	t[:b][:a] = S.new("h")
	t[:b][:a][:a] = t[:b]
	print("make cycle ref\n")
	t[:b] = nil
	print("collect\n")
	S.collectCycles()

	print("delete root\n")
	S.decrement(t)
end

main