1 /* Copyright (C) 2004 - 2009  Versant Inc.  http://www.db4o.com */
2 
3 using System;
4 using Db4objects.Db4o.Foundation;
5 using Db4objects.Db4o.Internal;
6 using Db4objects.Db4o.Internal.Freespace;
7 using Db4objects.Db4o.Internal.Slots;
8 
9 namespace Db4objects.Db4o.Internal.Freespace
10 {
11 	public abstract class AbstractFreespaceManager : IFreespaceManager
12 	{
13 		public const byte FmDebug = 127;
14 
15 		public const byte FmDefault = 0;
16 
17 		public const byte FmLegacyRam = 1;
18 
19 		public const byte FmRam = 2;
20 
21 		public const byte FmIx = 3;
22 
23 		public const byte FmBtree = 4;
24 
25 		private const int IntsInSlot = 12;
26 
27 		public const int RemainderSizeLimit = 20;
28 
CheckType(byte systemType)29 		public static byte CheckType(byte systemType)
30 		{
31 			if (systemType == FmDefault)
32 			{
33 				return FmRam;
34 			}
35 			return systemType;
36 		}
37 
38 		protected IProcedure4 _slotFreedCallback;
39 
40 		private readonly int _discardLimit;
41 
AbstractFreespaceManager(IProcedure4 slotFreedCallback, int discardLimit)42 		public AbstractFreespaceManager(IProcedure4 slotFreedCallback, int discardLimit)
43 		{
44 			_slotFreedCallback = slotFreedCallback;
45 			_discardLimit = discardLimit;
46 		}
47 
CreateNew(LocalObjectContainer file)48 		public static Db4objects.Db4o.Internal.Freespace.AbstractFreespaceManager CreateNew
49 			(LocalObjectContainer file)
50 		{
51 			return CreateNew(file, file.SystemData().FreespaceSystem());
52 		}
53 
CreateNew(LocalObjectContainer file, byte systemType)54 		public static Db4objects.Db4o.Internal.Freespace.AbstractFreespaceManager CreateNew
55 			(LocalObjectContainer file, byte systemType)
56 		{
57 			systemType = CheckType(systemType);
58 			int unblockedDiscardLimit = file.ConfigImpl.DiscardFreeSpace();
59 			int blockedDiscardLimit = unblockedDiscardLimit == int.MaxValue ? unblockedDiscardLimit
60 				 : file.BlockConverter().BytesToBlocks(unblockedDiscardLimit);
61 			IProcedure4 slotFreedCallback = new _IProcedure4_50(file);
62 			switch (systemType)
63 			{
64 				case FmIx:
65 				{
66 					return new FreespaceManagerIx(blockedDiscardLimit);
67 				}
68 
69 				case FmBtree:
70 				{
71 					return new BTreeFreespaceManager(file, slotFreedCallback, blockedDiscardLimit);
72 				}
73 
74 				default:
75 				{
76 					return new InMemoryFreespaceManager(slotFreedCallback, blockedDiscardLimit);
77 					break;
78 				}
79 			}
80 		}
81 
82 		private sealed class _IProcedure4_50 : IProcedure4
83 		{
_IProcedure4_50(LocalObjectContainer file)84 			public _IProcedure4_50(LocalObjectContainer file)
85 			{
86 				this.file = file;
87 			}
88 
Apply(object slot)89 			public void Apply(object slot)
90 			{
91 				file.OverwriteDeletedBlockedSlot(((Slot)slot));
92 			}
93 
94 			private readonly LocalObjectContainer file;
95 		}
96 
InitSlot(LocalObjectContainer file)97 		public static int InitSlot(LocalObjectContainer file)
98 		{
99 			int address = file.AllocateSlot(SlotLength()).Address();
100 			SlotEntryToZeroes(file, address);
101 			return address;
102 		}
103 
MigrateTo(IFreespaceManager fm)104 		public virtual void MigrateTo(IFreespaceManager fm)
105 		{
106 			Traverse(new _IVisitor4_72(fm));
107 		}
108 
109 		private sealed class _IVisitor4_72 : IVisitor4
110 		{
_IVisitor4_72(IFreespaceManager fm)111 			public _IVisitor4_72(IFreespaceManager fm)
112 			{
113 				this.fm = fm;
114 			}
115 
Visit(object obj)116 			public void Visit(object obj)
117 			{
118 				fm.Free((Slot)obj);
119 			}
120 
121 			private readonly IFreespaceManager fm;
122 		}
123 
SlotEntryToZeroes(LocalObjectContainer file, int address)124 		internal static void SlotEntryToZeroes(LocalObjectContainer file, int address)
125 		{
126 			StatefulBuffer writer = new StatefulBuffer(file.SystemTransaction(), address, SlotLength
127 				());
128 			for (int i = 0; i < IntsInSlot; i++)
129 			{
130 				writer.WriteInt(0);
131 			}
132 			writer.WriteEncrypt();
133 		}
134 
SlotLength()135 		internal static int SlotLength()
136 		{
137 			return Const4.IntLength * IntsInSlot;
138 		}
139 
TotalFreespace()140 		public virtual int TotalFreespace()
141 		{
142 			IntByRef mint = new IntByRef();
143 			Traverse(new _IVisitor4_97(mint));
144 			return mint.value;
145 		}
146 
147 		private sealed class _IVisitor4_97 : IVisitor4
148 		{
_IVisitor4_97(IntByRef mint)149 			public _IVisitor4_97(IntByRef mint)
150 			{
151 				this.mint = mint;
152 			}
153 
Visit(object obj)154 			public void Visit(object obj)
155 			{
156 				Slot slot = (Slot)obj;
157 				mint.value += slot.Length();
158 			}
159 
160 			private readonly IntByRef mint;
161 		}
162 
DiscardLimit()163 		protected virtual int DiscardLimit()
164 		{
165 			return _discardLimit;
166 		}
167 
SplitRemainder(int length)168 		protected bool SplitRemainder(int length)
169 		{
170 			if (CanDiscard(length))
171 			{
172 				return false;
173 			}
174 			return length > RemainderSizeLimit;
175 		}
176 
CanDiscard(int length)177 		internal bool CanDiscard(int length)
178 		{
179 			return length == 0 || length < DiscardLimit();
180 		}
181 
Migrate(IFreespaceManager oldFM, IFreespaceManager newFM)182 		public static void Migrate(IFreespaceManager oldFM, IFreespaceManager newFM)
183 		{
184 			oldFM.MigrateTo(newFM);
185 			oldFM.FreeSelf();
186 		}
187 
DebugCheckIntegrity()188 		public virtual void DebugCheckIntegrity()
189 		{
190 			IntByRef lastStart = new IntByRef();
191 			IntByRef lastEnd = new IntByRef();
192 			Traverse(new _IVisitor4_129(lastEnd, lastStart));
193 		}
194 
195 		private sealed class _IVisitor4_129 : IVisitor4
196 		{
_IVisitor4_129(IntByRef lastEnd, IntByRef lastStart)197 			public _IVisitor4_129(IntByRef lastEnd, IntByRef lastStart)
198 			{
199 				this.lastEnd = lastEnd;
200 				this.lastStart = lastStart;
201 			}
202 
Visit(object obj)203 			public void Visit(object obj)
204 			{
205 				Slot slot = (Slot)obj;
206 				if (slot.Address() <= lastEnd.value)
207 				{
208 					throw new InvalidOperationException();
209 				}
210 				lastStart.value = slot.Address();
211 				lastEnd.value = slot.Address() + slot.Length();
212 			}
213 
214 			private readonly IntByRef lastEnd;
215 
216 			private readonly IntByRef lastStart;
217 		}
218 
MigrationRequired(byte systemType)219 		public static bool MigrationRequired(byte systemType)
220 		{
221 			return systemType == FmLegacyRam || systemType == FmIx;
222 		}
223 
SlotFreed(Slot slot)224 		public virtual void SlotFreed(Slot slot)
225 		{
226 			if (_slotFreedCallback == null)
227 			{
228 				return;
229 			}
230 			_slotFreedCallback.Apply(slot);
231 		}
232 
AllocateSafeSlot(int arg1)233 		public abstract Slot AllocateSafeSlot(int arg1);
234 
AllocateSlot(int arg1)235 		public abstract Slot AllocateSlot(int arg1);
236 
AllocateTransactionLogSlot(int arg1)237 		public abstract Slot AllocateTransactionLogSlot(int arg1);
238 
BeginCommit()239 		public abstract void BeginCommit();
240 
Commit()241 		public abstract void Commit();
242 
EndCommit()243 		public abstract void EndCommit();
244 
Free(Slot arg1)245 		public abstract void Free(Slot arg1);
246 
FreeSafeSlot(Slot arg1)247 		public abstract void FreeSafeSlot(Slot arg1);
248 
FreeSelf()249 		public abstract void FreeSelf();
250 
IsStarted()251 		public abstract bool IsStarted();
252 
Listener(IFreespaceListener arg1)253 		public abstract void Listener(IFreespaceListener arg1);
254 
Read(LocalObjectContainer arg1, Slot arg2)255 		public abstract void Read(LocalObjectContainer arg1, Slot arg2);
256 
SlotCount()257 		public abstract int SlotCount();
258 
Start(int arg1)259 		public abstract void Start(int arg1);
260 
SystemType()261 		public abstract byte SystemType();
262 
Traverse(IVisitor4 arg1)263 		public abstract void Traverse(IVisitor4 arg1);
264 
Write(LocalObjectContainer arg1)265 		public abstract void Write(LocalObjectContainer arg1);
266 	}
267 }
268