PrevalenceSystem.Mod 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343
  1. MODULE PrevalenceSystem; (** AUTHOR "Luc Blaeser"; PURPOSE "Prevalence System - Persistent Object System"*)
  2. IMPORT XML, XMLObjects, XMLScanner, XMLParser, TFClasses,
  3. Strings, Modules, Kernel, Files, Streams, KernelLog, Configuration;
  4. CONST
  5. DEBUG = FALSE; (* debug output *)
  6. ConfigurationSupperSectionName = "PrevalenceSystem";
  7. ConfigurationSubSectionName = "PersistentObjectModules";
  8. ProcNameGetDescriptors = "GetPersistentObjectDescriptors";
  9. SnapShotIntervall = 15 * 60 * 100; (* 15 minutes *)
  10. StandardPrevSystemName = "StandardPrevalenceSystem";
  11. StandardSnapShotFileName = "PrevalenceSnapShot.XML";
  12. StandardLogFileName = "PrevalenceLog.XML";
  13. XMLProlog = '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>';
  14. XMLRootElemName = "instances";
  15. XMLOidCounterAttrName = "oidcounter";
  16. XMLInstanceElemName = "instance";
  17. XMLAttrModuleName = "module";
  18. XMLAttrObjectName = "object";
  19. XMLAttrOidName = "oid";
  20. XMLAttrIsRootName = "isroot";
  21. XMLAttrSavingCounter ="time";
  22. XMLLogRootElemName = "log";
  23. XMLLogDelInstElemName = "deleted"; (* only for root elements *)
  24. TermTimeout = 1000*1000; (* Wait time to terminate *)
  25. (** abstract base type for all persistent objects.
  26. * Since there is no introspection of object fields possible the user has to implement
  27. * the externalization and internalization of an object state in XML on its own.
  28. * Each command on the PersistentObject which modifies its state must be explicitly done in a
  29. * BeginTransaction..EndTransaction block to ensure logging of the state changement.
  30. * All persistent objects have to be registered by the prevalence system to make sure that their
  31. * persistent object descriptor is known.
  32. * Certain persistent objects are registered as root objects to contribute to the root set
  33. * of reachable persistent objects for the persistent object garbage collector of the prevalence system.
  34. * Each persistent object can belong only to one prevalence system
  35. *)
  36. TYPE
  37. PersistentObject* = OBJECT
  38. VAR
  39. oid*: LONGINT; (** oid of the persistent object *)
  40. inModification, takingSnapShot: BOOLEAN;
  41. registeredAt*: PrevalenceSystem; (* prevalence system where this object is registered *)
  42. PROCEDURE &Init*;
  43. BEGIN oid := 0; inModification := FALSE; takingSnapShot := FALSE; registeredAt := NIL
  44. END Init;
  45. PROCEDURE BeginModification*;
  46. BEGIN {EXCLUSIVE}
  47. AWAIT((~takingSnapShot) & (~inModification));
  48. inModification := TRUE;
  49. END BeginModification;
  50. PROCEDURE EndModification*; (** after the return of this method the transaction is commited *)
  51. BEGIN {EXCLUSIVE}
  52. IF (registeredAt # NIL) THEN
  53. registeredAt.Log(SELF)
  54. ELSE
  55. HALT(9999); (* Object must be registered in at least one prevalence system *)
  56. END;
  57. inModification := FALSE
  58. END EndModification;
  59. PROCEDURE Externalize*() : XML.Content;
  60. BEGIN HALT(309);
  61. RETURN NIL;
  62. END Externalize;
  63. PROCEDURE Internalize*(xml: XML.Content);
  64. BEGIN HALT(309)
  65. END Internalize;
  66. PROCEDURE GetReferrencedObjects*() : PersistentObjectList;
  67. (** return all persistent objects which are referrenced by instance variables *)
  68. BEGIN RETURN NIL
  69. END GetReferrencedObjects;
  70. END PersistentObject;
  71. PersistentObjectList* = POINTER TO ARRAY OF PersistentObject;
  72. PersistentObjectFactory* = PROCEDURE (): PersistentObject;
  73. (** used to instantiate a persistent object since there is no introspection possible *)
  74. PersistentObjectDescriptor* = OBJECT
  75. VAR
  76. moduleName*, objectName*: Strings.String;
  77. factory*: PersistentObjectFactory;
  78. PROCEDURE &Init*(CONST modName, objName: ARRAY OF CHAR; factoryProc: PersistentObjectFactory);
  79. BEGIN
  80. NEW(moduleName, LEN(modName)); NEW(objectName, LEN(objName));
  81. COPY(modName, moduleName^); COPY(objName, objectName^);
  82. factory := factoryProc
  83. END Init;
  84. END PersistentObjectDescriptor;
  85. PersistentObjectDescSet* = OBJECT
  86. VAR
  87. descriptors*: POINTER TO ARRAY OF PersistentObjectDescriptor;
  88. PROCEDURE &Init*(CONST descs: ARRAY OF PersistentObjectDescriptor);
  89. VAR i: LONGINT;
  90. BEGIN
  91. NEW(descriptors, LEN(descs));
  92. FOR i := 0 TO LEN(descs)-1 DO
  93. descriptors[i] := descs[i]
  94. END
  95. END Init;
  96. PROCEDURE GetCount*() : LONGINT;
  97. BEGIN
  98. RETURN LEN(descriptors^)
  99. END GetCount;
  100. PROCEDURE GetItem*(i: LONGINT) : PersistentObjectDescriptor;
  101. BEGIN
  102. RETURN descriptors[i]
  103. END GetItem;
  104. END PersistentObjectDescSet;
  105. PersistentObjectDescSetFactory = PROCEDURE() : PersistentObjectDescSet;
  106. (** additionally there must be a procedure which gives all descriptors for the persistent objects in the module
  107. PROCEDURE GetPersistentObjectDescriptors*(par:ANY) : ANY;
  108. no parameter; returns the descriptors of active elements (PersistentObjectDescSet)
  109. must be thread safe
  110. *)
  111. (** returns true iff the persistent object satisfies the predicate *)
  112. FilterPredicate* = PROCEDURE {DELEGATE} (obj: PersistentObject) : BOOLEAN;
  113. (* belongs to exactly one prevalence system *)
  114. PersistentObjectWrapper = OBJECT
  115. VAR
  116. prevalenceSystem: PrevalenceSystem;
  117. instance: PersistentObject;
  118. descriptor: PersistentObjectDescriptor;
  119. savingCounter: LONGINT; (* when was the object the last time saved in the snapshot *)
  120. isRoot: BOOLEAN; (* true iff the object belongs to the root set of the mark phase *)
  121. isMarked: BOOLEAN; (* temporary use in the mark phase, true iff not garbage *)
  122. PROCEDURE &Init*(prevSys: PrevalenceSystem; obj: PersistentObject; desc: PersistentObjectDescriptor);
  123. BEGIN
  124. ASSERT(prevSys # NIL); ASSERT(obj # NIL); ASSERT(desc # NIL);
  125. prevalenceSystem := prevSys;
  126. IF (obj.oid = 0) THEN obj.oid := prevalenceSystem.GetNewOid() END; (* set an oid if not done yet *)
  127. instance := obj; descriptor := desc;
  128. isMarked := TRUE (* don't remove in a now running GC sweep phase *)
  129. END Init;
  130. END PersistentObjectWrapper;
  131. SnapShotManager = OBJECT
  132. VAR timer: Kernel.Timer; alive, terminated: BOOLEAN;
  133. i: LONGINT; p: ANY; prevSys: PrevalenceSystem;
  134. BEGIN {ACTIVE}
  135. IF (DEBUG) THEN KernelLog.String("Prevalence System: Snapshot Manager started."); KernelLog.Ln END;
  136. NEW(timer); alive := TRUE; terminated := FALSE;
  137. timer.Sleep(SnapShotIntervall);
  138. WHILE (alive) DO
  139. prevSystemList.Lock;
  140. FOR i := 0 TO prevSystemList.GetCount()-1 DO
  141. p := prevSystemList.GetItem(i); prevSys := p(PrevalenceSystem);
  142. IF (DEBUG) THEN
  143. KernelLog.String("Prevalence System '"); KernelLog.String(prevSys.SystemName^);
  144. KernelLog.String("': Storing a snapshot."); KernelLog.Ln
  145. END;
  146. prevSys.PersistAllObjects;
  147. IF (DEBUG) THEN
  148. KernelLog.String("Prevalence System '"); KernelLog.String(prevSys.SystemName^);
  149. KernelLog.String("': Snapshot done."); KernelLog.Ln
  150. END
  151. END;
  152. prevSystemList.Unlock;
  153. timer.Sleep(SnapShotIntervall)
  154. END;
  155. IF (DEBUG) THEN KernelLog.String("Prevalence System: Snapshot Manager terminated."); KernelLog.Ln END;
  156. terminated := TRUE;
  157. END SnapShotManager;
  158. TYPE PrevalenceSystem* = OBJECT
  159. VAR
  160. SnapShotFileName*: Strings.String;
  161. LogFileName*: Strings.String;
  162. SystemName*: Strings.String;
  163. persistentObjectList: TFClasses.List; (* List of PersistentObjectWrapper *)
  164. oidCounter: LONGINT;
  165. (* file access synchronization *)
  166. lockSnapShotFile: BOOLEAN;
  167. lockLogFile: BOOLEAN;
  168. (* persistent object list synchronization *)
  169. lockPersList: BOOLEAN;
  170. (** the prevalence system name, the snapshot file name and the log file name must be different to
  171. * those of the other present prevalence systems. *)
  172. PROCEDURE &Init*(CONST name, snapShotFn, logFn: ARRAY OF CHAR);
  173. VAR i: LONGINT; p: ANY; prevSys: PrevalenceSystem;
  174. BEGIN
  175. LockPrevSystemList;
  176. prevSystemList.Lock;
  177. FOR i := 0 TO prevSystemList.GetCount()-1 DO
  178. p := prevSystemList.GetItem(i); prevSys := p(PrevalenceSystem);
  179. IF ((prevSys.SystemName^ = name) OR (prevSys.SnapShotFileName^ = snapShotFn)
  180. OR (prevSys.LogFileName^ = logFn)) THEN
  181. prevSystemList.Unlock;
  182. UnlockPrevSystemList;
  183. HALT(9999) (* conflict with other prevalence system *)
  184. END
  185. END;
  186. prevSystemList.Unlock;
  187. NEW(SystemName, LEN(name)+1); COPY(name, SystemName^);
  188. NEW(SnapShotFileName, LEN(snapShotFn)+1); COPY(snapShotFn, SnapShotFileName^);
  189. NEW(LogFileName, LEN(logFn)+1); COPY(logFn, LogFileName^);
  190. NEW(persistentObjectList); oidCounter := 1;
  191. lockSnapShotFile := FALSE; lockLogFile := FALSE; lockPersList := FALSE;
  192. RestoreAllObjects;
  193. prevSystemList.Add(SELF);
  194. UnlockPrevSystemList;
  195. END Init;
  196. (** each persistent object has to be registered in the prevalence system to make sure that its descriptor is known.
  197. * This does not affect that the object will be collected as garbage if it is not reachable through a root persistent object *)
  198. PROCEDURE AddPersistentObject*(obj: PersistentObject; desc: PersistentObjectDescriptor);
  199. VAR wrapper : PersistentObjectWrapper;
  200. BEGIN
  201. LockPersistentObjList;
  202. IF ((desc # NIL) & (FindRegisteredDescriptor(desc.moduleName^, desc.objectName^) # NIL)) THEN
  203. IF ((obj # NIL) & (GetRegisteredWrapper(obj) = NIL)) THEN (* object is not registered yet *)
  204. IF (obj.registeredAt = NIL) THEN
  205. obj.registeredAt := SELF
  206. ELSIF (obj.registeredAt # SELF) THEN
  207. UnlockPersistentObjList;
  208. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  209. KernelLog.String("': Cannot add objects which are alreaduy registered in another prevalence system.");
  210. KernelLog.Ln; HALT(9999)
  211. END;
  212. NEW(wrapper, SELF, obj, desc);
  213. persistentObjectList.Add(wrapper);
  214. UnlockPersistentObjList;
  215. Log(obj)
  216. ELSE
  217. UnlockPersistentObjList
  218. END
  219. ELSE
  220. UnlockPersistentObjList;
  221. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  222. KernelLog.String("': Cannot add objects with an unregistered descriptor to the prevelance system");
  223. KernelLog.Ln; HALT(9999)
  224. END
  225. END AddPersistentObject;
  226. (** add object to the root set of the prevalence system. This objects must be manually removed from the prevalence system,
  227. * All objects reached by a root persistent object are also persistent *)
  228. PROCEDURE AddPersistentObjectToRootSet*(obj: PersistentObject; desc: PersistentObjectDescriptor);
  229. VAR wrapper : PersistentObjectWrapper;
  230. BEGIN
  231. LockPersistentObjList;
  232. IF ((desc # NIL) & (FindRegisteredDescriptor(desc.moduleName^, desc.objectName^) # NIL)) THEN
  233. IF (obj # NIL) THEN
  234. wrapper := GetRegisteredWrapper(obj);
  235. IF (wrapper = NIL) THEN (* object is not registered yet *)
  236. IF (obj.registeredAt = NIL) THEN
  237. obj.registeredAt := SELF
  238. ELSIF (obj.registeredAt # SELF) THEN
  239. UnlockPersistentObjList;
  240. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  241. KernelLog.String("': Cannot add objects which are alreaduy registered in another prevalence system.");
  242. KernelLog.Ln; HALT(9999)
  243. END;
  244. NEW(wrapper, SELF, obj, desc);
  245. wrapper.isRoot := TRUE;
  246. persistentObjectList.Add(wrapper)
  247. ELSE
  248. wrapper.isRoot := TRUE
  249. END;
  250. UnlockPersistentObjList;
  251. Log(obj)
  252. END
  253. ELSE
  254. UnlockPersistentObjList;
  255. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  256. KernelLog.String("': Cannot add objects with an unregistered descriptor to the prevelance system");
  257. KernelLog.Ln; HALT(9999)
  258. END
  259. END AddPersistentObjectToRootSet;
  260. (** the object will be marked to be no more belonging to the root set and all persistent objects only reachable by this
  261. * object will be removed in the next garbage collection phase *)
  262. PROCEDURE RemovePersistentRootObject*(obj: PersistentObject);
  263. VAR wrapper: PersistentObjectWrapper;
  264. BEGIN
  265. LockPersistentObjList;
  266. wrapper := GetRegisteredWrapper(obj);
  267. IF ((wrapper # NIL) & (wrapper.isRoot)) THEN
  268. wrapper.isRoot := FALSE;
  269. UnlockPersistentObjList;
  270. LogRemovalFromRootSet(wrapper)
  271. ELSE
  272. UnlockPersistentObjList
  273. END
  274. END RemovePersistentRootObject;
  275. PROCEDURE GetPersistentObject*(oid: LONGINT): PersistentObject;
  276. VAR wrapper: PersistentObjectWrapper;
  277. BEGIN
  278. wrapper := GetRegisteredWrapperByOid(oid);
  279. IF (wrapper # NIL) THEN
  280. RETURN wrapper.instance
  281. ELSE
  282. RETURN NIL
  283. END
  284. END GetPersistentObject;
  285. PROCEDURE GetDescriptorByObject*(obj: PersistentObject) : PersistentObjectDescriptor;
  286. VAR wrapper: PersistentObjectWrapper;
  287. BEGIN
  288. wrapper := GetRegisteredWrapper(obj);
  289. IF (wrapper # NIL) THEN
  290. RETURN wrapper.descriptor
  291. END
  292. END GetDescriptorByObject;
  293. PROCEDURE FindPersistentObjects*(pred: FilterPredicate) : PersistentObjectList;
  294. VAR i: LONGINT; p: ANY; wrapper: PersistentObjectWrapper; obj: PersistentObject;
  295. list: TFClasses.List; persList: PersistentObjectList;
  296. BEGIN
  297. NEW(list);
  298. persistentObjectList.Lock;
  299. FOR i := 0 TO persistentObjectList.GetCount()-1 DO
  300. p := persistentObjectList.GetItem(i); wrapper := p(PersistentObjectWrapper); (* wrapper # NIL *)
  301. obj := wrapper.instance;
  302. IF (pred(obj)) THEN
  303. list.Add(obj)
  304. END
  305. END;
  306. persistentObjectList.Unlock;
  307. IF (list.GetCount() > 0) THEN
  308. NEW(persList, list.GetCount());
  309. FOR i := 0 TO list.GetCount()-1 DO
  310. p := list.GetItem(i); obj := p(PersistentObject);
  311. persList[i] := obj
  312. END;
  313. RETURN persList
  314. ELSE
  315. RETURN NIL
  316. END
  317. END FindPersistentObjects;
  318. PROCEDURE GetNewOid() : LONGINT;
  319. BEGIN {EXCLUSIVE}
  320. INC(oidCounter); RETURN oidCounter-1
  321. END GetNewOid;
  322. PROCEDURE GetXMLDocument(file: Files.File) : XML.Document;
  323. VAR scanner: XMLScanner.Scanner; parser: XMLParser.Parser; doc: XML.Document;
  324. reader: Files.Reader;
  325. BEGIN (* file # NIL *)
  326. NEW(reader, file, 0);
  327. NEW(scanner, reader);
  328. NEW(parser, scanner);
  329. LockParsingScanning;
  330. scanner.reportError := ReportXMLParserScannerError;
  331. parser.reportError := ReportXMLParserScannerError;
  332. doc := parser.Parse();
  333. UnlockParsingScanning;
  334. IF (xmlParserErrorOccurred) THEN
  335. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  336. KernelLog.String("': "); KernelLog.String(xmlParserErrorMsg); KernelLog.Ln;
  337. RETURN NIL
  338. ELSE
  339. RETURN doc
  340. END
  341. END GetXMLDocument;
  342. PROCEDURE LockSnapShotFile;
  343. BEGIN {EXCLUSIVE}
  344. AWAIT(~lockSnapShotFile);
  345. lockSnapShotFile := TRUE
  346. END LockSnapShotFile;
  347. PROCEDURE UnlockSnapShotFile;
  348. BEGIN {EXCLUSIVE}
  349. lockSnapShotFile := FALSE
  350. END UnlockSnapShotFile;
  351. PROCEDURE LockLoggingFile;
  352. BEGIN {EXCLUSIVE}
  353. AWAIT(~lockLogFile);
  354. lockLogFile := TRUE
  355. END LockLoggingFile;
  356. PROCEDURE UnlockLoggingFile;
  357. BEGIN {EXCLUSIVE}
  358. lockLogFile := FALSE
  359. END UnlockLoggingFile;
  360. PROCEDURE LockPersistentObjList;
  361. BEGIN {EXCLUSIVE}
  362. AWAIT(~lockPersList);
  363. lockPersList := TRUE
  364. END LockPersistentObjList;
  365. PROCEDURE UnlockPersistentObjList;
  366. BEGIN {EXCLUSIVE}
  367. lockPersList := FALSE
  368. END UnlockPersistentObjList;
  369. PROCEDURE CompactLogFile;
  370. VAR file, newfile: Files.File; doc: XML.Document; root, elem: XML.Element; enum: XMLObjects.Enumerator;
  371. p: ANY; oidString, savingCounterString: Strings.String; i, oid, savingCounter: LONGINT;
  372. wrapper: PersistentObjectWrapper; removeList: TFClasses.List; fwriter: Files.Writer; writer: Streams.Writer;
  373. elemName, rootName: Strings.String;
  374. BEGIN
  375. LockLoggingFile;
  376. file := Files.Old(LogFileName^);
  377. IF (file # NIL) THEN
  378. newfile := Files.New(LogFileName^);
  379. IF (newfile # NIL) THEN
  380. NEW(removeList);
  381. doc := GetXMLDocument(file);
  382. IF (doc # NIL) THEN
  383. root := doc.GetRoot();
  384. rootName := root.GetName();
  385. IF (rootName^ = XMLLogRootElemName) THEN
  386. enum := root.GetContents();
  387. WHILE (enum.HasMoreElements()) DO
  388. p := enum.GetNext();
  389. IF (p IS XML.Element) THEN
  390. elem := p(XML.Element);
  391. elemName := elem.GetName();
  392. IF ((elemName^ = XMLInstanceElemName) OR (elemName^ = XMLLogDelInstElemName)) THEN
  393. oidString := elem.GetAttributeValue(XMLAttrOidName);
  394. savingCounterString := elem.GetAttributeValue(XMLAttrSavingCounter);
  395. IF ((oidString # NIL) & (savingCounterString # NIL)) THEN
  396. Strings.StrToInt(oidString^, oid); Strings.StrToInt(savingCounterString^, savingCounter);
  397. wrapper := GetRegisteredWrapperByOid(oid);
  398. IF (((wrapper # NIL) & (savingCounter < wrapper.savingCounter)) OR (wrapper = NIL)) THEN
  399. (* either the savingCounter for the log entry is stale or the object has been removed *)
  400. removeList.Add(elem)
  401. END
  402. ELSE
  403. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  404. KernelLog.String("': In the snapshot file '"); KernelLog.String(SnapShotFileName^);
  405. KernelLog.String("' is an instance without oid or without saving time."); KernelLog.Ln
  406. END
  407. END
  408. END
  409. END;
  410. FOR i := 0 TO removeList.GetCount()-1 DO
  411. p := removeList.GetItem(i); elem := p(XML.Element);
  412. root.RemoveContent(elem)
  413. END;
  414. Files.OpenWriter(fwriter, newfile, 0); writer := fwriter;
  415. doc.Write(writer, NIL, 0);
  416. fwriter.Update;
  417. Files.Register(newfile);
  418. IF (DEBUG) THEN
  419. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  420. KernelLog.String("': Log file compacted."); KernelLog.Ln
  421. END
  422. ELSE
  423. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  424. KernelLog.String("': Cannot overwrite the log file '"); KernelLog.String(SnapShotFileName^);
  425. KernelLog.String("' while compacting the log file."); KernelLog.Ln
  426. END
  427. ELSE
  428. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  429. KernelLog.String("': In the log file '"); KernelLog.String(LogFileName^);
  430. KernelLog.String("' must be a root defined as '"); KernelLog.String(XMLLogRootElemName);
  431. KernelLog.String("'."); KernelLog.Ln
  432. END;
  433. END
  434. END;
  435. UnlockLoggingFile
  436. END CompactLogFile;
  437. PROCEDURE GarbageCollect*;
  438. VAR i: LONGINT; pObj: ANY; wrapper: PersistentObjectWrapper; removeList: TFClasses.List;
  439. (* get the registered wrapper without locking the persistentObjectList, since it is already locked by outer procedure *)
  440. PROCEDURE GetWrapperForObj(obj: PersistentObject) : PersistentObjectWrapper;
  441. VAR k: LONGINT; ptr: ANY; wpr: PersistentObjectWrapper;
  442. BEGIN
  443. FOR k := 0 TO persistentObjectList.GetCount()-1 DO
  444. ptr := persistentObjectList.GetItem(k); wpr := ptr(PersistentObjectWrapper); (* wpr # NIL *)
  445. IF (wpr.instance = obj) THEN
  446. RETURN wpr
  447. END
  448. END;
  449. RETURN NIL
  450. END GetWrapperForObj;
  451. PROCEDURE MarkReachableObjects(obj: PersistentObject);
  452. VAR k: LONGINT; list: PersistentObjectList; wpr: PersistentObjectWrapper;
  453. BEGIN (* w # NIL & w.instance # NIL *)
  454. list := obj.GetReferrencedObjects();
  455. IF (list # NIL) THEN
  456. FOR k := 0 TO LEN(list)-1 DO
  457. wpr := GetWrapperForObj(list[k]);
  458. IF (wpr # NIL) THEN
  459. IF (~wpr.isMarked) THEN
  460. wpr.isMarked := TRUE; (* cyclic referrencing possible *)
  461. MarkReachableObjects(wpr.instance) (* wpr.instance # NIL *)
  462. ELSE
  463. wpr.isMarked := TRUE
  464. END
  465. END
  466. END
  467. END
  468. END MarkReachableObjects;
  469. BEGIN
  470. LockPersistentObjList;
  471. persistentObjectList.Lock;
  472. FOR i := 0 TO persistentObjectList.GetCount()-1 DO(* unmark all objects *)
  473. pObj := persistentObjectList.GetItem(i); wrapper := pObj(PersistentObjectWrapper);
  474. wrapper.isMarked := FALSE
  475. END;
  476. (* mark phase *)
  477. FOR i := 0 TO persistentObjectList.GetCount()-1 DO
  478. pObj := persistentObjectList.GetItem(i); wrapper := pObj(PersistentObjectWrapper);
  479. IF (wrapper.isRoot) THEN (* start from a root persistent object *)
  480. wrapper.isMarked := TRUE;
  481. MarkReachableObjects(wrapper.instance)
  482. END
  483. END;
  484. (* detect garbage *)
  485. NEW(removeList);
  486. FOR i := 0 TO persistentObjectList.GetCount()-1 DO
  487. pObj := persistentObjectList.GetItem(i); wrapper := pObj(PersistentObjectWrapper);
  488. IF (~wrapper.isMarked) THEN
  489. IF (DEBUG) THEN
  490. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  491. KernelLog.String("': Garbage collector: Free object with oid "); KernelLog.Int(wrapper.instance.oid, 0); KernelLog.String(" ");
  492. KernelLog.String(wrapper.descriptor.moduleName^); KernelLog.String("."); KernelLog.String(wrapper.descriptor.objectName^); KernelLog.Ln
  493. END;
  494. removeList.Add(wrapper)
  495. END
  496. END;
  497. persistentObjectList.Unlock;
  498. (* sweep phase *)
  499. FOR i := 0 TO removeList.GetCount()-1 DO
  500. pObj := removeList.GetItem(i);
  501. persistentObjectList.Remove(pObj)
  502. END;
  503. UnlockPersistentObjList
  504. END GarbageCollect;
  505. PROCEDURE PersistAllObjects; (* store a snapshot of the prevalence system to an XML file *)
  506. VAR fw: Files.Writer; w: Streams.Writer; newFile: Files.File; newRoot, elem: XML.Element;
  507. i: LONGINT; pObj: ANY; wrapper: PersistentObjectWrapper; instance: PersistentObject;
  508. oldDocument: XML.Document; oidCounterString: ARRAY 14 OF CHAR;
  509. PROCEDURE GetPreviousSnapShotState(oid: LONGINT) : XML.Element;
  510. VAR file: Files.File; oldRoot: XML.Element; enum: XMLObjects.Enumerator; pOldElem: ANY; oldElem: XML.Element;
  511. oidValue: Strings.String; oldOid: LONGINT; oldRootName, oldElemName: Strings.String;
  512. BEGIN (* file # NIL *)
  513. IF (oldDocument = NIL) THEN
  514. file := Files.Old(SnapShotFileName^);
  515. IF (file # NIL) THEN
  516. oldDocument := GetXMLDocument(file)
  517. END;
  518. END;
  519. IF (oldDocument # NIL) THEN
  520. oldRoot := oldDocument.GetRoot();
  521. oldRootName := oldRoot.GetName();
  522. IF ((oldRoot # NIL) & (oldRootName^ = XMLRootElemName)) THEN
  523. enum := oldRoot.GetContents();
  524. WHILE (enum.HasMoreElements()) DO
  525. pOldElem := enum.GetNext();
  526. IF (pOldElem IS XML.Element) THEN
  527. oldElem := pOldElem(XML.Element);
  528. oldElemName := oldElem.GetName();
  529. IF (oldElemName^ = XMLInstanceElemName) THEN
  530. oidValue := oldElem.GetAttributeValue(XMLAttrOidName);
  531. IF (oidValue # NIL) THEN
  532. Strings.StrToInt(oidValue^, oldOid);
  533. IF (oldOid = oid) THEN
  534. RETURN oldElem
  535. END
  536. ELSE
  537. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  538. KernelLog.String("': In the snapshot file '"); KernelLog.String(SnapShotFileName^);
  539. KernelLog.String("' is an instance without attribute 'oid'."); KernelLog.Ln
  540. END
  541. END
  542. END
  543. END
  544. ELSE
  545. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  546. KernelLog.String("': In the snapshot file '"); KernelLog.String(SnapShotFileName^);
  547. KernelLog.String("' must be a root defined as '"); KernelLog.String(XMLRootElemName);
  548. KernelLog.String("'."); KernelLog.Ln
  549. END
  550. ELSE
  551. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  552. KernelLog.String("': Could not parse the snapshot file '"); KernelLog.String(SnapShotFileName^);
  553. KernelLog.String("' during taking a snapshot of the system."); KernelLog.Ln
  554. END;
  555. (* it could be that the persistent object was not present at the last snapshot time *)
  556. RETURN NIL
  557. END GetPreviousSnapShotState;
  558. BEGIN
  559. oldDocument := NIL;
  560. LockSnapShotFile;
  561. newFile := Files.New(SnapShotFileName^);
  562. IF (newFile # NIL) THEN
  563. Strings.IntToStr(oidCounter, oidCounterString);
  564. NEW(newRoot); newRoot.SetName(XMLRootElemName);
  565. newRoot.SetAttributeValue(XMLOidCounterAttrName, oidCounterString);
  566. GarbageCollect;
  567. persistentObjectList.Lock;
  568. FOR i := 0 TO persistentObjectList.GetCount()-1 DO
  569. pObj := persistentObjectList.GetItem(i); wrapper := pObj(PersistentObjectWrapper);
  570. (* wrapper # NIL & wrapper.instance # NIL *)
  571. IF (IsModuleLoaded(wrapper.descriptor.moduleName^)) THEN
  572. instance := wrapper.instance;
  573. instance.takingSnapShot := TRUE;
  574. IF (~instance.inModification) THEN
  575. INC(wrapper.savingCounter);
  576. elem := GetSerializedXMLInstance(wrapper);
  577. instance.takingSnapShot := FALSE;
  578. newRoot.AddContent(elem)
  579. ELSE (* Is in transaction, take the previous version if present, could be recovered from log by next recovery *)
  580. instance.takingSnapShot := FALSE;
  581. elem := GetPreviousSnapShotState(instance.oid);
  582. IF (elem # NIL) THEN (* object was already present at the last snapshot time *)
  583. newRoot.AddContent(elem)
  584. END
  585. END
  586. ELSE (* Snapshot no more possible since module has been freed *)
  587. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  588. KernelLog.String("': module '"); KernelLog.String(wrapper.descriptor.moduleName^);
  589. KernelLog.String("' has been freed. Taking snapshot is no further possible, the system uses now only logging.");
  590. snapShotMgr.alive := FALSE;
  591. RETURN
  592. END
  593. END;
  594. persistentObjectList.Unlock;
  595. Files.OpenWriter(fw, newFile, 0); w := fw;
  596. w.String(XMLProlog); w.Ln;
  597. newRoot.Write(w, NIL, 0);
  598. fw.Update;
  599. Files.Register(newFile);
  600. IF (DEBUG) THEN
  601. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  602. KernelLog.String("': Snapshot stored to "); KernelLog.String(SnapShotFileName^); KernelLog.Ln
  603. END
  604. ELSE
  605. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  606. KernelLog.String("': Cannot create or overwrite file '"); KernelLog.String(SnapShotFileName^);
  607. KernelLog.String("' for storing the snapshot."); KernelLog.Ln
  608. END;
  609. UnlockSnapShotFile;
  610. (* now reduce redundant entries from the log file *)
  611. CompactLogFile;
  612. END PersistAllObjects;
  613. PROCEDURE GetSerializedXMLInstance(wrapper: PersistentObjectWrapper) : XML.Element;
  614. VAR content: XML.Content; elem: XML.Element; savingCounterString, oidString: ARRAY 14 OF CHAR;
  615. container: XML.Container; instance: PersistentObject; desc: PersistentObjectDescriptor;
  616. enum: XMLObjects.Enumerator; pChild: ANY; child: XML.Content;
  617. BEGIN
  618. instance := wrapper.instance;
  619. desc := wrapper.descriptor;
  620. (* here would be an exception handler fine*)
  621. content := instance.Externalize(); (* the instance externalization is locked while a transaction is done *)
  622. Strings.IntToStr(wrapper.savingCounter, savingCounterString);
  623. Strings.IntToStr(instance.oid, oidString);
  624. NEW(elem); elem.SetName(XMLInstanceElemName);
  625. elem.SetAttributeValue(XMLAttrModuleName, desc.moduleName^);
  626. elem.SetAttributeValue(XMLAttrObjectName, desc.objectName^);
  627. elem.SetAttributeValue(XMLAttrOidName, oidString);
  628. elem.SetAttributeValue(XMLAttrSavingCounter, savingCounterString);
  629. IF (wrapper.isRoot) THEN
  630. elem.SetAttributeValue(XMLAttrIsRootName, "true")
  631. END;
  632. IF ((content # NIL) & (content IS XML.Container) & (~(content IS XML.Element))) THEN (* it is a simple container *)
  633. container := content(XML.Container);
  634. enum := container.GetContents();
  635. WHILE (enum.HasMoreElements()) DO
  636. pChild := enum.GetNext(); child := pChild(XML.Content);
  637. elem.AddContent(child)
  638. END
  639. ELSIF (content # NIL) THEN
  640. elem.AddContent(content)
  641. END;
  642. RETURN elem
  643. END GetSerializedXMLInstance;
  644. PROCEDURE GetXMLInstanceDeletion(wrapper: PersistentObjectWrapper) : XML.Element;
  645. VAR instance: PersistentObject; desc: PersistentObjectDescriptor; elem: XML.Element;
  646. savingCounterString, oidString: ARRAY 14 OF CHAR;
  647. BEGIN
  648. instance := wrapper.instance; (* instance # NIL *)
  649. desc := wrapper.descriptor; (* desc # NIL *)
  650. Strings.IntToStr(wrapper.savingCounter, savingCounterString);
  651. Strings.IntToStr(instance.oid, oidString);
  652. NEW(elem); elem.SetName(XMLLogDelInstElemName);
  653. elem.SetAttributeValue(XMLAttrModuleName, desc.moduleName^);
  654. elem.SetAttributeValue(XMLAttrObjectName, desc.objectName^);
  655. elem.SetAttributeValue(XMLAttrOidName, oidString);
  656. elem.SetAttributeValue(XMLAttrSavingCounter, savingCounterString);
  657. RETURN elem
  658. END GetXMLInstanceDeletion;
  659. PROCEDURE LogXMLElement(elem: XML.Element);
  660. VAR file: Files.File; fwriter: Files.Writer; writer: Streams.Writer; endPos, endTagLength: LONGINT;
  661. BEGIN
  662. LockLoggingFile;
  663. file := Files.Old(LogFileName^);
  664. IF (file = NIL) THEN
  665. file := Files.New(LogFileName^);
  666. Files.Register(file)
  667. END;
  668. IF (file # NIL) THEN
  669. (* Don't use the XML parser, it's too inefficient.
  670. Append the XML serialized state an the end of the xml file *)
  671. endTagLength := Strings.Length(XMLLogRootElemName)+5; (* LEN("</XMLLogRootElemName>"+CR+LF *)
  672. IF (file.Length()-endTagLength-Strings.Length(XMLProlog)-2 <= 0) THEN (* empty file or only <log/> in it *)
  673. Files.OpenWriter(fwriter, file, 0); writer := fwriter;
  674. writer.String(XMLProlog); writer.Ln;
  675. writer.String("<"); writer.String(XMLLogRootElemName);
  676. writer.String(">"); writer.Ln; (* opening tag "<log>" *)
  677. ELSE
  678. endPos := file.Length()-endTagLength;
  679. ASSERT(endPos >= 0, 9999);
  680. Files.OpenWriter(fwriter, file, endPos); writer := fwriter
  681. END;
  682. elem.Write(writer, NIL, 0);
  683. writer.Ln;
  684. writer.String("</");
  685. writer.String(XMLLogRootElemName);
  686. writer.String(">"); writer.Ln;
  687. writer.Update
  688. ELSE
  689. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  690. KernelLog.String("': Cannot open or create file '"); KernelLog.String(LogFileName^);
  691. KernelLog.String("'."); KernelLog.Ln;
  692. UnlockLoggingFile; HALT(9999); (* Cannot commit the transaction, could support "ABORT" at a later time *)
  693. END;
  694. UnlockLoggingFile
  695. END LogXMLElement;
  696. PROCEDURE Log(obj: PersistentObject);
  697. VAR elem: XML.Element; wrapper: PersistentObjectWrapper;
  698. BEGIN
  699. wrapper := GetRegisteredWrapper(obj);
  700. IF (wrapper # NIL) THEN
  701. elem := GetSerializedXMLInstance(wrapper);
  702. LogXMLElement(elem)
  703. ELSE
  704. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  705. KernelLog.String("': The object with oid '"); KernelLog.Int(obj.oid, 0);
  706. KernelLog.String("' is not stored in the prevalence system and will therefore not be logged."); KernelLog.Ln
  707. END
  708. END Log;
  709. PROCEDURE LogRemovalFromRootSet(wrapper: PersistentObjectWrapper);
  710. VAR elem: XML.Element;
  711. BEGIN
  712. IF (wrapper # NIL) THEN
  713. elem := GetXMLInstanceDeletion(wrapper);
  714. LogXMLElement(elem)
  715. ELSE
  716. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  717. KernelLog.String("': The object with is not stored in the prevalence system and will therefore not be logged.");
  718. KernelLog.Ln
  719. END
  720. END LogRemovalFromRootSet;
  721. (* The last oid counter can be restored by the max(oidCounter in the snapshot file, max(oid of all logged object)+1)
  722. For all objects which were created before the last snapshot was taken, the oidCounter in the snapshot file is
  723. greater the oid for this objects. If an object O was created after the last snapshot was taken and O has been
  724. registered in the prevalence system for a time (even if it was later removed) then by looking at the maximum oid
  725. occurring in the log file the oidCounter is chosen greater than the oid of O. If an object O was created before the last
  726. snapshot was taken and O has never been registered in the prevalence system then O will be destroyed if the module
  727. PrevalenceSystem is freed, since each module M using O imports the module PrevalenceSystem. Hence O will not affect
  728. the oid uniqueness condition at the next incarnation time for the prevalence system. *)
  729. PROCEDURE RestoreAllObjects;
  730. VAR snapShotFile, logFile: Files.File; snapShotDoc, logDoc: XML.Document;
  731. snapShotRoot, logRoot, elem: XML.Element; enum: XMLObjects.Enumerator; p: ANY;
  732. moduleName, objectName, oidString, savingCounterString, isRootString: Strings.String;
  733. oid, savingCounter: LONGINT; isRoot: BOOLEAN;
  734. snapShotRootName, logRootName, elemName, oidCounterString: Strings.String;
  735. desc: PersistentObjectDescriptor; objWrapper: PersistentObjectWrapper;
  736. PROCEDURE CreatePersistentObject;
  737. VAR persObj: PersistentObject; wrapper: PersistentObjectWrapper;
  738. BEGIN
  739. IF (desc # NIL) THEN
  740. (* persistent object serializations could occur multiple times in log file *)
  741. IF (GetPersistentObject(oid) = NIL) THEN (* first time that the persistent object occurs *)
  742. (* Always overwriting savingCounter and isRoot would lead to inconsistent states since there could be
  743. * stale informations in the log file *)
  744. persObj := desc.factory();
  745. IF (persObj # NIL) THEN
  746. persObj.oid := oid;
  747. NEW(wrapper, SELF, persObj, desc);
  748. wrapper.savingCounter := savingCounter;
  749. wrapper.isRoot := isRoot;
  750. persistentObjectList.Add(wrapper);
  751. persObj.registeredAt := SELF
  752. ELSE
  753. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  754. KernelLog.String("': cannot create an instance of the persistent object '");
  755. KernelLog.String(objectName^); KernelLog.String("' in module '"); KernelLog.String(moduleName^);
  756. KernelLog.String("'."); KernelLog.Ln;
  757. HALT(9999)
  758. END
  759. END
  760. ELSE
  761. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  762. KernelLog.String("': persistent object '"); KernelLog.String(objectName^);
  763. KernelLog.String("' in module '"); KernelLog.String(moduleName^);
  764. KernelLog.String("' must be installed because it is stored in the snapshot or log file."); KernelLog.Ln;
  765. HALT(9999)
  766. END
  767. END CreatePersistentObject;
  768. PROCEDURE RestorePersistentObject;
  769. VAR pContent: ANY; content: XML.Content; contentEnum: XMLObjects.Enumerator; contentList: TFClasses.List;
  770. persObj: PersistentObject; container: XML.Container; j: LONGINT;
  771. BEGIN
  772. persObj := GetPersistentObject(oid);
  773. IF (persObj # NIL) THEN
  774. contentEnum := elem.GetContents();
  775. NEW(contentList);
  776. WHILE (contentEnum.HasMoreElements()) DO
  777. pContent := contentEnum.GetNext();
  778. contentList.Add(pContent)
  779. END;
  780. IF (contentList.GetCount() = 0) THEN
  781. content := NIL
  782. ELSIF (contentList.GetCount() = 1) THEN
  783. pContent := contentList.GetItem(0);
  784. content := pContent(XML.Content)
  785. ELSE
  786. NEW(container);
  787. FOR j := 0 TO contentList.GetCount()-1 DO
  788. pContent := contentList.GetItem(j); content := pContent(XML.Content);
  789. container.AddContent(content)
  790. END;
  791. content := container
  792. END;
  793. (* here would be an exception handler fine *)
  794. persObj.Internalize(content);
  795. ELSE
  796. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  797. KernelLog.String("': Recovery process: there is no object with oid '"); KernelLog.Int(oid, 0);
  798. KernelLog.String("' present."); KernelLog.Ln
  799. END
  800. END RestorePersistentObject;
  801. PROCEDURE AllocatePersistentObjects(root: XML.Element);
  802. VAR contentEnum: XMLObjects.Enumerator;
  803. BEGIN
  804. contentEnum := root.GetContents();
  805. WHILE (contentEnum.HasMoreElements()) DO
  806. p := contentEnum.GetNext();
  807. IF (p IS XML.Element) THEN
  808. elem := p(XML.Element);
  809. elemName := elem.GetName();
  810. IF (elemName^ = XMLInstanceElemName) THEN
  811. moduleName := elem.GetAttributeValue(XMLAttrModuleName);
  812. objectName := elem.GetAttributeValue(XMLAttrObjectName);
  813. oidString := elem.GetAttributeValue(XMLAttrOidName);
  814. savingCounterString := elem.GetAttributeValue(XMLAttrSavingCounter);
  815. isRootString := elem.GetAttributeValue(XMLAttrIsRootName);
  816. IF ((moduleName # NIL) & (objectName # NIL) & (oidString # NIL) & (savingCounterString # NIL)) THEN
  817. Strings.StrToInt(oidString^, oid); Strings.StrToInt(savingCounterString^, savingCounter);
  818. IF ((isRootString # NIL) & (isRootString^ = "true")) THEN
  819. isRoot := TRUE
  820. ELSE
  821. isRoot := FALSE
  822. END;
  823. IF (oid >= oidCounter) THEN
  824. oidCounter := oid + 1
  825. END;
  826. desc := FindRegisteredDescriptor(moduleName^, objectName^);
  827. (* savingCounter and isRoot etc. is only set in CreatePersistentObject if the object occurs the first time.
  828. * Always overwriting this information would lead to inconsistent states since there could be
  829. * stale informations in the log file. *)
  830. CreatePersistentObject
  831. ELSE
  832. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  833. KernelLog.String("': There are instances with missing attributes in the snapshot or log file.");
  834. KernelLog.Ln;
  835. UnlockLoggingFile;
  836. UnlockSnapShotFile;
  837. UnlockPersistentObjList;
  838. HALT(9999)
  839. END
  840. END
  841. END
  842. END
  843. END AllocatePersistentObjects;
  844. BEGIN
  845. LockPersistentObjList;
  846. LockSnapShotFile;
  847. LockLoggingFile;
  848. (* two phases: first create all persistent object instances, then invoke the internalization methods.
  849. This allows that the persistent can have references to other persistent object instances. *)
  850. (* first phase: create the persistent object instances. First consider all objects in the snapshot file then
  851. * the new objects only reported in the log file. *)
  852. snapShotFile := Files.Old(SnapShotFileName^);
  853. IF (snapShotFile # NIL) THEN
  854. snapShotDoc := GetXMLDocument(snapShotFile);
  855. IF (snapShotDoc # NIL) THEN
  856. snapShotRoot := snapShotDoc.GetRoot();
  857. snapShotRootName := snapShotRoot.GetName();
  858. IF (snapShotRootName^ = XMLRootElemName) THEN
  859. oidCounterString := snapShotRoot.GetAttributeValue(XMLOidCounterAttrName);
  860. IF (oidCounterString # NIL) THEN
  861. Strings.StrToInt(oidCounterString^, oidCounter);
  862. AllocatePersistentObjects(snapShotRoot)
  863. ELSE
  864. snapShotRoot := NIL;
  865. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  866. KernelLog.String("': In the snapshot file '"); KernelLog.String(SnapShotFileName^);
  867. KernelLog.String("' the root '"); KernelLog.String(XMLRootElemName);
  868. KernelLog.String("' must have an attribute named'"); KernelLog.String(XMLOidCounterAttrName);
  869. KernelLog.String("'."); KernelLog.Ln
  870. END
  871. ELSE
  872. snapShotRoot := NIL;
  873. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  874. KernelLog.String("': In the snapshot file '"); KernelLog.String(SnapShotFileName^);
  875. KernelLog.String("' must be a root defined as '"); KernelLog.String(XMLRootElemName);
  876. KernelLog.String("'."); KernelLog.Ln
  877. END
  878. ELSE (* error message already handled by GetXMLDocument *)
  879. UnlockLoggingFile;
  880. UnlockSnapShotFile;
  881. UnlockPersistentObjList;
  882. HALT(9999)
  883. END
  884. END;
  885. logFile := Files.Old(LogFileName^);
  886. IF (logFile # NIL) THEN
  887. logDoc := GetXMLDocument(logFile);
  888. IF (logDoc # NIL) THEN
  889. logRoot := logDoc.GetRoot();
  890. logRootName := logRoot.GetName();
  891. IF (logRootName^ = XMLLogRootElemName) THEN
  892. AllocatePersistentObjects(logRoot)
  893. ELSE
  894. logRoot := NIL;
  895. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  896. KernelLog.String("': In the log file '"); KernelLog.String(LogFileName^);
  897. KernelLog.String("' must be a root defined as '"); KernelLog.String(XMLLogRootElemName);
  898. KernelLog.String("'."); KernelLog.Ln
  899. END
  900. ELSE (* error message already handled by GetXMLDocument *)
  901. UnlockLoggingFile;
  902. UnlockSnapShotFile;
  903. UnlockPersistentObjList;
  904. HALT(9999)
  905. END
  906. END;
  907. (* second phase: internalize persistent object state *)
  908. IF (snapShotRoot # NIL) THEN
  909. enum := snapShotRoot.GetContents();
  910. WHILE (enum.HasMoreElements()) DO
  911. p := enum.GetNext();
  912. IF (p IS XML.Element) THEN
  913. elem := p(XML.Element);
  914. elemName := elem.GetName();
  915. IF (elemName^ = XMLInstanceElemName) THEN
  916. oidString := elem.GetAttributeValue(XMLAttrOidName);
  917. IF (oidString # NIL) THEN
  918. Strings.StrToInt(oidString^, oid);
  919. (* the savingCounter and isRoot are consistent, since the object was created by the information
  920. * of the snapshot file and savingCounter and isRoot were not overwritten by the log file until now *)
  921. RestorePersistentObject
  922. ELSE
  923. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  924. KernelLog.String("': There are object instances with missing oid in the snapshot file.");
  925. KernelLog.Ln
  926. END
  927. END
  928. END
  929. END;
  930. IF (DEBUG) THEN
  931. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  932. KernelLog.String("': Recovery from snapshot done."); KernelLog.Ln
  933. END
  934. END;
  935. IF (logRoot # NIL) THEN
  936. enum := logRoot.GetContents();
  937. WHILE (enum.HasMoreElements()) DO
  938. p := enum.GetNext();
  939. IF (p IS XML.Element) THEN
  940. elem := p(XML.Element);
  941. elemName := elem.GetName();
  942. IF ((elemName^ = XMLInstanceElemName) OR (elemName^ = XMLLogDelInstElemName)) THEN
  943. oidString := elem.GetAttributeValue(XMLAttrOidName);
  944. savingCounterString := elem.GetAttributeValue(XMLAttrSavingCounter);
  945. IF ((oidString # NIL) & (savingCounterString # NIL)) THEN
  946. Strings.StrToInt(oidString^, oid); Strings.StrToInt(savingCounterString^, savingCounter);
  947. objWrapper := GetRegisteredWrapperByOid(oid); (* objWrapper # NIL since they were previously created *)
  948. IF ((objWrapper # NIL) & (elemName^ = XMLInstanceElemName)) THEN
  949. isRootString := elem.GetAttributeValue(XMLAttrIsRootName);
  950. IF ((isRootString # NIL) & (isRootString^ = "true")) THEN
  951. isRoot := TRUE
  952. ELSE
  953. isRoot := FALSE
  954. END;
  955. IF (savingCounter >= objWrapper.savingCounter) THEN (* only update if newer information *)
  956. objWrapper.savingCounter := savingCounter;
  957. objWrapper.isRoot := isRoot;
  958. RestorePersistentObject
  959. END
  960. ELSIF ((objWrapper # NIL) & (elemName^ = XMLLogDelInstElemName)) THEN
  961. IF (savingCounter >= objWrapper.savingCounter) THEN (* only update if newer information *)
  962. objWrapper.isRoot := FALSE
  963. (* the object doesn't belong anymore to the root set, and could be removed later by
  964. * the garbage collector of the prevalence system *)
  965. END
  966. ELSE
  967. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  968. KernelLog.String("': Recovery phase: Object with oid '"); KernelLog.Int(oid, 0);
  969. KernelLog.String("' is not present."); KernelLog.Ln
  970. END
  971. ELSE
  972. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  973. KernelLog.String("': There are object instances with missing oid or saving counter in the log file.");
  974. KernelLog.Ln
  975. END
  976. END
  977. END
  978. END;
  979. IF (DEBUG) THEN
  980. KernelLog.String("Prevalence System '"); KernelLog.String(SystemName^);
  981. KernelLog.String("': Recovery from log file done."); KernelLog.Ln
  982. END
  983. END;
  984. UnlockLoggingFile;
  985. UnlockSnapShotFile;
  986. UnlockPersistentObjList
  987. END RestoreAllObjects;
  988. PROCEDURE GetRegisteredWrapperByOid(oid: LONGINT) : PersistentObjectWrapper;
  989. VAR i: LONGINT; p: ANY; wrapper: PersistentObjectWrapper;
  990. BEGIN
  991. persistentObjectList.Lock;
  992. FOR i := 0 TO persistentObjectList.GetCount()-1 DO
  993. p := persistentObjectList.GetItem(i); wrapper := p(PersistentObjectWrapper);
  994. (* wrapper # NIL & wrapper.instance # NIL *)
  995. IF (wrapper.instance.oid = oid) THEN
  996. persistentObjectList.Unlock;
  997. RETURN wrapper
  998. END
  999. END;
  1000. persistentObjectList.Unlock;
  1001. RETURN NIL
  1002. END GetRegisteredWrapperByOid;
  1003. PROCEDURE GetRegisteredWrapper(obj: PersistentObject) : PersistentObjectWrapper;
  1004. VAR i: LONGINT; p: ANY; wrapper: PersistentObjectWrapper;
  1005. BEGIN
  1006. IF (obj # NIL) THEN
  1007. persistentObjectList.Lock;
  1008. FOR i := 0 TO persistentObjectList.GetCount()-1 DO
  1009. p := persistentObjectList.GetItem(i); wrapper := p(PersistentObjectWrapper); (* wrapper # NIL *)
  1010. IF (wrapper.instance = obj) THEN
  1011. persistentObjectList.Unlock;
  1012. RETURN wrapper
  1013. END
  1014. END;
  1015. persistentObjectList.Unlock
  1016. END;
  1017. RETURN NIL
  1018. END GetRegisteredWrapper;
  1019. END PrevalenceSystem;
  1020. VAR
  1021. prevSystemList: TFClasses.List; (* List of Prevelence System *)
  1022. standardPrevalenceSystem*: PrevalenceSystem;
  1023. persistentObjectDescs: TFClasses.List; (* List of PersistentObjectDescriptor *)
  1024. snapShotMgr: SnapShotManager; (* singleton *)
  1025. (* error handling mechanism for XML Parser and Scanner *)
  1026. xmlParserErrorMsg: ARRAY 1024 OF CHAR;
  1027. xmlParserErrorOccurred: BOOLEAN;
  1028. lockParsingScanning: BOOLEAN;
  1029. lockPrevSystemList: BOOLEAN;
  1030. PROCEDURE GetPrevalenceSystem*(CONST name: ARRAY OF CHAR) : PrevalenceSystem;
  1031. VAR i: LONGINT; p: ANY; prevSys: PrevalenceSystem;
  1032. BEGIN
  1033. prevSystemList.Lock;
  1034. FOR i := 0 TO prevSystemList.GetCount()-1 DO
  1035. p := prevSystemList.GetItem(i); prevSys := p(PrevalenceSystem);
  1036. IF (prevSys.SystemName^ = name) THEN
  1037. prevSystemList.Unlock;
  1038. RETURN prevSys
  1039. END
  1040. END;
  1041. prevSystemList.Unlock;
  1042. RETURN NIL
  1043. END GetPrevalenceSystem;
  1044. (** operations on the standard prevalence system *)
  1045. (** each persistent object has to be registered in the standard prevalence system to make sure that its descriptor is known.
  1046. * This does not affect that the object will be collected as garbage if it is not reachable through a root persistent object *)
  1047. PROCEDURE AddPersistentObject*(obj: PersistentObject; desc: PersistentObjectDescriptor);
  1048. BEGIN
  1049. standardPrevalenceSystem.AddPersistentObject(obj, desc)
  1050. END AddPersistentObject;
  1051. (** add object to the root set of the standard prevalence system. This objects must be manually removed from the prevalence system,
  1052. * All objects reached by a root persistent object are also persistent *)
  1053. PROCEDURE AddPersistentObjectToRootSet*(obj: PersistentObject; desc: PersistentObjectDescriptor);
  1054. BEGIN
  1055. standardPrevalenceSystem.AddPersistentObjectToRootSet(obj, desc)
  1056. END AddPersistentObjectToRootSet;
  1057. (** the object will be marked to be no more belonging to the root set of the standard prevalence system
  1058. * and all persistent objects only reachable by this object will be removed in the next garbage collection phase *)
  1059. PROCEDURE RemovePersistentRootObject*(obj: PersistentObject);
  1060. BEGIN
  1061. standardPrevalenceSystem.RemovePersistentRootObject(obj)
  1062. END RemovePersistentRootObject;
  1063. PROCEDURE GetPersistentObject*(oid: LONGINT): PersistentObject;
  1064. BEGIN
  1065. RETURN standardPrevalenceSystem.GetPersistentObject(oid)
  1066. END GetPersistentObject;
  1067. PROCEDURE GetDescriptorByObject*(obj: PersistentObject) : PersistentObjectDescriptor;
  1068. BEGIN
  1069. RETURN standardPrevalenceSystem.GetDescriptorByObject(obj)
  1070. END GetDescriptorByObject;
  1071. PROCEDURE FindPersistentObjects*(pred: FilterPredicate) : PersistentObjectList;
  1072. BEGIN
  1073. RETURN standardPrevalenceSystem.FindPersistentObjects(pred)
  1074. END FindPersistentObjects;
  1075. (** end of operations on the standard prevalence system *)
  1076. PROCEDURE LockPrevSystemList;
  1077. BEGIN {EXCLUSIVE}
  1078. AWAIT(~lockPrevSystemList);
  1079. lockPrevSystemList := TRUE
  1080. END LockPrevSystemList;
  1081. PROCEDURE UnlockPrevSystemList;
  1082. BEGIN {EXCLUSIVE}
  1083. lockPrevSystemList := FALSE
  1084. END UnlockPrevSystemList;
  1085. PROCEDURE LockParsingScanning;
  1086. BEGIN {EXCLUSIVE}
  1087. AWAIT(~lockParsingScanning);
  1088. lockParsingScanning := TRUE
  1089. END LockParsingScanning;
  1090. PROCEDURE UnlockParsingScanning;
  1091. BEGIN {EXCLUSIVE}
  1092. lockParsingScanning := FALSE
  1093. END UnlockParsingScanning;
  1094. PROCEDURE ReportXMLParserScannerError(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR); (* Error handler for the XML parser *)
  1095. VAR w: Streams.StringWriter;
  1096. BEGIN
  1097. xmlParserErrorOccurred := TRUE;
  1098. NEW(w, LEN(xmlParserErrorMsg));
  1099. w.String(msg); w.String(" pos "); w.Int(pos, 0);
  1100. w.String("line "); w.Int(line, 0);
  1101. w.String("row "); w.Int(row, 0); w.Ln;
  1102. w.Get(xmlParserErrorMsg)
  1103. END ReportXMLParserScannerError;
  1104. PROCEDURE IsModuleLoaded(CONST modName: ARRAY OF CHAR) : BOOLEAN;
  1105. VAR module: Modules.Module;
  1106. BEGIN
  1107. module := Modules.ModuleByName(modName);
  1108. RETURN (module # NIL)
  1109. END IsModuleLoaded;
  1110. PROCEDURE FindRegisteredDescriptor(CONST moduleName, objectName: ARRAY OF CHAR) : PersistentObjectDescriptor;
  1111. VAR p: ANY; i: LONGINT; desc: PersistentObjectDescriptor;
  1112. BEGIN
  1113. persistentObjectDescs.Lock;
  1114. FOR i := 0 TO persistentObjectDescs.GetCount()-1 DO
  1115. p := persistentObjectDescs.GetItem(i); desc := p(PersistentObjectDescriptor);
  1116. IF ((desc.moduleName^ = moduleName) & (desc.objectName^ = objectName)) THEN
  1117. persistentObjectDescs.Unlock;
  1118. RETURN desc
  1119. END
  1120. END;
  1121. persistentObjectDescs.Unlock;
  1122. RETURN NIL
  1123. END FindRegisteredDescriptor;
  1124. PROCEDURE RegisterDescriptor(desc: PersistentObjectDescriptor);
  1125. VAR pos: LONGINT;
  1126. BEGIN {EXCLUSIVE}
  1127. IF (desc # NIL) THEN
  1128. persistentObjectDescs.Lock;
  1129. pos := persistentObjectDescs.IndexOf(desc);
  1130. persistentObjectDescs.Unlock;
  1131. IF (pos = -1) THEN (* not registered yet *)
  1132. persistentObjectDescs.Add(desc)
  1133. END
  1134. END
  1135. END RegisterDescriptor;
  1136. PROCEDURE ReadRegisteredModules;
  1137. VAR elem, child: XML.Element; enum: XMLObjects.Enumerator; p: ANY; childName, moduleName: Strings.String;
  1138. attr: XML.Attribute;
  1139. BEGIN
  1140. IF (Configuration.config # NIL) THEN
  1141. elem := Configuration.config.GetRoot();
  1142. elem := Configuration.GetNamedElement(elem, "Section", ConfigurationSupperSectionName);
  1143. IF (elem # NIL) THEN
  1144. elem := Configuration.GetNamedElement(elem, "Section", ConfigurationSubSectionName);
  1145. IF (elem # NIL) THEN
  1146. enum := elem.GetContents();
  1147. WHILE (enum.HasMoreElements()) DO
  1148. p := enum.GetNext();
  1149. IF (p IS XML.Element) THEN
  1150. child := p(XML.Element); childName := child.GetName();
  1151. IF (childName^ = "Setting") THEN
  1152. attr := child.GetAttribute("value");
  1153. IF (attr # NIL) THEN
  1154. moduleName := attr.GetValue();
  1155. RegisterModuleByName(moduleName)
  1156. END
  1157. END
  1158. END
  1159. END
  1160. ELSE
  1161. KernelLog.String("Prevalence System: In Configuration.XML under '");
  1162. KernelLog.String(ConfigurationSupperSectionName); KernelLog.String("' is no section '");
  1163. KernelLog.String(ConfigurationSubSectionName); KernelLog.String(" defined."); KernelLog.Ln
  1164. END
  1165. ELSE
  1166. KernelLog.String("Prevalence System: In Configuration.XML is no section '");
  1167. KernelLog.String(ConfigurationSupperSectionName); KernelLog.String("' defined."); KernelLog.Ln
  1168. END
  1169. ELSE
  1170. KernelLog.String("Prevalence System: Cannot open Configuration.XML"); KernelLog.Ln
  1171. END
  1172. END ReadRegisteredModules;
  1173. PROCEDURE RegisterModuleByName(moduleName: Strings.String);
  1174. VAR module: Modules.Module; factory : PersistentObjectDescSetFactory; i: LONGINT; res: WORD;
  1175. msg: ARRAY 1024 OF CHAR; desc: PersistentObjectDescriptor;
  1176. descList: PersistentObjectDescSet;
  1177. BEGIN
  1178. (* load the module if not already loaded *)
  1179. module := Modules.ThisModule(moduleName^, res, msg);
  1180. IF ((res = 0) & (module # NIL)) THEN
  1181. GETPROCEDURE(moduleName^, ProcNameGetDescriptors, factory);
  1182. IF (factory # NIL) THEN
  1183. descList := factory();
  1184. IF (descList # NIL) THEN (* register all present descriptors *)
  1185. FOR i := 0 TO descList.GetCount()-1 DO
  1186. desc := descList.GetItem(i);
  1187. RegisterDescriptor(desc)
  1188. END
  1189. ELSE
  1190. KernelLog.String("System pervalence: Wrong result type from procedure '");
  1191. KernelLog.String(ProcNameGetDescriptors); KernelLog.String("' in module '");
  1192. KernelLog.String(moduleName^); KernelLog.String("'"); KernelLog.Ln
  1193. END
  1194. ELSE
  1195. KernelLog.String("System prevalence: Procedure '"); KernelLog.String(ProcNameGetDescriptors);
  1196. KernelLog.String("' in module '"); KernelLog.String(moduleName^); KernelLog.String("' is not present."); KernelLog.Ln
  1197. END
  1198. ELSE
  1199. KernelLog.String("System prevalence: Module '"); KernelLog.String(moduleName^);
  1200. KernelLog.String("' is not present."); KernelLog.Ln;
  1201. KernelLog.String(msg); KernelLog.Ln
  1202. END
  1203. END RegisterModuleByName;
  1204. PROCEDURE Terminator;
  1205. VAR counter: LONGINT;
  1206. BEGIN
  1207. IF (snapShotMgr # NIL) THEN
  1208. snapShotMgr.alive := FALSE;
  1209. snapShotMgr.timer.Wakeup;
  1210. counter := 0;
  1211. WHILE ((~snapShotMgr.terminated) & (counter < TermTimeout)) DO INC(counter) END
  1212. (* busy wait until snapShotMgr has stopped, avoid permanent system blocking by a timeout *)
  1213. END
  1214. END Terminator;
  1215. BEGIN
  1216. NEW(persistentObjectDescs); NEW(prevSystemList);
  1217. lockParsingScanning := FALSE;
  1218. (* reconstruct the prevalence systems *)
  1219. ReadRegisteredModules;
  1220. NEW(standardPrevalenceSystem, StandardPrevSystemName, StandardSnapShotFileName, StandardLogFileName);
  1221. NEW(snapShotMgr);
  1222. Modules.InstallTermHandler(Terminator)
  1223. END PrevalenceSystem.