KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jts > CosTransactions > CoordinatorLog


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * Copyright 2004-2005 Sun Microsystems, Inc. All rights reserved.
26  * Use is subject to license terms.
27  */

28 //----------------------------------------------------------------------------
29
//
30
// Module: CoordinatorLog.java
31
//
32
// Description: Coordinator state logging.
33
//
34
// Product: com.sun.jts.CosTransactions
35
//
36
// Author: Simon Holdsworth
37
//
38
// Date: March, 1997
39
//
40
// Copyright (c): 1995-1997 IBM Corp.
41
//
42
// The source code for this program is not published or otherwise divested
43
// of its trade secrets, irrespective of what has been deposited with the
44
// U.S. Copyright Office.
45
//
46
// This software contains confidential and proprietary information of
47
// IBM Corp.
48
//----------------------------------------------------------------------------
49

50 package com.sun.jts.CosTransactions;
51
52 // Import required classes.
53

54 import java.util.*;
55 import java.io.*;
56
57 import org.omg.CORBA.*;
58
59 import java.io.DataOutputStream JavaDoc;
60 import java.io.DataInputStream JavaDoc;
61 import java.util.logging.Logger JavaDoc;
62 import java.util.logging.Level JavaDoc;
63 import com.sun.logging.LogDomains;
64 import com.sun.jts.utils.LogFormatter;
65
66 /**The CoordinatorLog interface provides operations to record transaction-
67  * specific information that needs to be persistently stored at a particular
68  * point in time, and subsequently restored.
69  * <p>
70  * The CoordinatorLog contains an attribute value which is the local transaction
71  * identifier associated with the transaction operating on the log. The
72  * CoordinatorLog maintains the LSN of the last log record written for the
73  * transaction, and a flag indicating whether rewrite is required for a
74  * keypoint.
75  * <p>
76  * As an instance of this class may be accessed from multiple threads within
77  * a process, serialisation for thread-safety and locking during keypoint is
78  * necessary.
79  *
80  * @version 0.01
81  *
82  * @author Simon Holdsworth, IBM Corporation
83  *
84  * @see
85 */

86 //----------------------------------------------------------------------------
87
// CHANGE HISTORY
88
//
89
// Version By Change Description
90
// 0.01 SAJH Initial implementation.
91
//------------------------------------------------------------------------------
92

93 class CoordinatorLog extends java.lang.Object JavaDoc implements LogUpcallTarget {
94     private static final int LOG_DEF_KEY_TRIGGER = 100;
95     private static final int LOG_THRESHOLD = 10000;
96     private static final int STRING_TO_REF_RETRIES = 20;
97     private static final String JavaDoc defaultstring = "DEFAULT_LOG";
98
99     /**
100     // Since muliple logs have to coexist as part of delegated recovery
101     // support, static data can not be maintained. Now this data is stored
102     // per log location
103     private static LogFile logFile = null;
104     private static Log log = null;
105     private static Hashtable activeLogs = new Hashtable();
106     private static Hashtable keypointLogs = new Hashtable();
107     private static int tranCount = 0;
108     private static int keypointTrigger = 100;
109     private static boolean keypointInProgress = false;
110     private static java.lang.Object keypointLock = new java.lang.Object();
111     private static java.lang.Object keypointStateLock = new java.lang.Object();
112    **/

113     private static int keypointTrigger = 100;
114     private static Hashtable logStateHoldertable = new Hashtable();
115
116     private Hashtable sectionMapping = null;
117     private boolean rewriteRequired = false;
118     private boolean writeDone = false;
119
120     private String JavaDoc logPath = null;
121
122     /*
123         Logger to log transaction messages
124     */

125     static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.TRANSACTION_LOGGER);
126     
127     /**The local transaction identifier for the transaction this object is logging.
128      */

129     Long JavaDoc localTID = null;
130     CoordinatorLogStateHolder logStateHolder = null;
131     private static CoordinatorLogStateHolder defaultLogStateHolder = getStateHolder(defaultstring);
132
133     // Static variables to handle byte array formatting.
134

135     private ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(2000);
136     private DataOutputStream JavaDoc dataOutput = new DataOutputStream JavaDoc(byteOutput);
137
138    
139     // All the methods which take "String logPath" as parameter are same as the
140
// ones with out that parameter. These methods are added for delegated
141
// recovery support
142
/**
143      * Get the state for the given log location.
144      * If the state does not exists, creates the state and retuns, otherwise existing
145      * state is returned.
146      *
147      * @param str log location.
148      *
149      * @return state for the given log location.
150      *
151      * @see
152      */

153     static private CoordinatorLogStateHolder getStateHolder(String JavaDoc str) {
154         synchronized (logStateHoldertable) {
155             CoordinatorLogStateHolder logStateHolder = (CoordinatorLogStateHolder)logStateHoldertable.get(str);
156             if (logStateHolder == null) {
157                 logStateHolder = new CoordinatorLogStateHolder();
158                  logStateHolder.logFile = null;
159                  logStateHolder.log = null;
160                  logStateHolder.activeLogs = new Hashtable();
161                  logStateHolder.keypointLogs = new Hashtable();
162                  logStateHolder.tranCount = 0;
163                  logStateHolder.keypointInProgress = false;
164                  // logStateHolder.keypointLock = new java.lang.Object();
165
logStateHolder.keypointLock = new RWLock();
166                  logStateHolder.keypointStateLock = new java.lang.Object JavaDoc();
167                  logStateHoldertable.put(str,logStateHolder);
168             }
169             return logStateHolder;
170         }
171     }
172
173     /**Default CoordinatorLog constructor.
174      *
175      * @param
176      *
177      * @return
178      *
179      * @see
180      */

181     CoordinatorLog() {
182
183         sectionMapping = new Hashtable();
184         logStateHolder = defaultLogStateHolder;
185         
186
187         // Do not inform the metaclass about the existence of this object yet, as it
188
// does not have a transaction identifier.
189

190     }
191
192     CoordinatorLog(String JavaDoc logPath) {
193
194         sectionMapping = new Hashtable();
195         logStateHolder = getStateHolder(logPath);
196         this.logPath = logPath;
197         
198
199         // Do not inform the metaclass about the existence of this object yet, as it
200
// does not have a transaction identifier.
201

202     }
203
204     /**Default CoordinatorLog destructor.
205      *
206      * @param
207      *
208      * @return
209      *
210      * @see
211      */

212     synchronized public void finalize() {
213
214         // Clear up the section mapping.
215

216         if( sectionMapping != null ) {
217             Enumeration sections = sectionMapping.elements();
218         // the traditional way of iterating through the enumeration
219
// using sections.hasMoreElements was showing up as a
220
// hot spot during performance tests. Arun 9/27/99
221
int sz = sectionMapping.size();
222         while (sz-- > 0) {
223                 CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
224                 section.reUse();
225             }
226             sectionMapping.clear();
227             sectionMapping = null;
228         }
229     }
230
231     /**
232      * reUse method is called explicitly to clean up
233      * and return this instance to the pool
234      *
235      * Note: the implementation of the cache does not ensure
236      * that when an object is re-used there are no
237      * outstanding references to that object. However, the
238      * risk involved is minimal since reUse() replaces the
239      * existing call to finalize(). The existing call to
240      * finalize also does not ensure that there are no
241      * outstanding references to the object being finalized.
242      *
243      *
244      * @param
245      *
246      * @return
247      *
248      * @see
249      */

250     synchronized private void reUse() { // Arun 9/27/99
251

252         // Clear up the section mapping.
253

254         if( sectionMapping != null ) {
255             Enumeration sections = sectionMapping.elements();
256         int sz = sectionMapping.size();
257         while (sz-- > 0) {
258                 CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
259                 section.reUse();
260             }
261             sectionMapping.clear();
262         }
263         rewriteRequired = false;
264         writeDone = false;
265         localTID = null;
266
267         byteOutput.reset();
268
269     // cache the coordinator log in the coordinator log pool
270
CoordinatorLogPool.putCoordinatorLog(this);
271
272     }
273
274     synchronized private void reUse(String JavaDoc logPath) {
275
276         // Clear up the section mapping.
277

278         if( sectionMapping != null ) {
279             Enumeration sections = sectionMapping.elements();
280         int sz = sectionMapping.size();
281         while (sz-- > 0) {
282                 CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
283                 section.reUse();
284             }
285             sectionMapping.clear();
286         }
287         rewriteRequired = false;
288         writeDone = false;
289         localTID = null;
290
291         byteOutput.reset();
292
293     // cache the coordinator log in the coordinator log pool
294
CoordinatorLogPool.putCoordinatorLog(this, logPath);
295
296     }
297
298     /**Creates and initialises a new CoordinatorLog object, with the given local
299      * transaction identifier.
300      * <p>
301      * If the local transaction identifier is non-NULL,
302      * the CoordinatorLog adds itself to the static list of instances.
303      *
304      * @param localTID The local transaction identifier.
305      *
306      * @return
307      *
308      * @see
309      */

310     CoordinatorLog( Long JavaDoc localTID ) {
311
312         // Set up the local transaction identifier; if it is not NULL, inform the
313
// metaclass of the object's existence.
314

315         this.localTID = localTID;
316         if( localTID.longValue() != 0 )
317             addLog(localTID,this);
318
319     }
320
321     /**
322      * Creates a subsection in the CoordinatorLog in which to store related
323      * objects and data.
324      * <p>
325      * The object that is returned is used to identify the section on subsequent
326      * calls.
327      * <p>
328      * If the section has already been created, the object for the existing
329      * section is returned.
330      *
331      * @param sectionName The name of the section.
332      *
333      * @return An object representing the section.
334      *
335      * @see
336      */

337     synchronized java.lang.Object JavaDoc createSection( String JavaDoc sectionName ) {
338
339         CoordinatorLogSection result = null;
340
341         // Check whether the given name already has a corresponding section.
342

343         result = (CoordinatorLogSection) sectionMapping.get(sectionName);
344         if (result == null) {
345             int nameLength = sectionName.length();
346
347             // Create a new section.
348
// If a section info structure cannot be allocated, return.
349
// Note that the section name is added to the end of the section
350
// info structure to reduce the number of SOMMalloc calls.
351

352         // get a new section object from the cache Arun 9/27/99
353
result = SectionPool.getCoordinatorLogSection(sectionName);
354             if( result == null ) {
355             }
356
357             // Copy in the name and set initial values of the other variables.
358

359             else {
360
361                 // Add the new section information to the map.
362

363                 sectionMapping.put(sectionName,result);
364             }
365         }
366
367         return result;
368     }
369
370     /**Adds the given object to the sequence of those in the given section.
371      * <p>
372      * The objects are stored in the order that they are added to the sequence.
373      * No checking is done for duplicates.
374      *
375      * @param sectionObj The object representing the section.
376      * @param obj The object to be added.
377      *
378      * @return Indicates success of the operation.
379      *
380      * @see
381      */

382
383     synchronized boolean addObject( java.lang.Object JavaDoc sectionObj,
384                                     org.omg.CORBA.Object JavaDoc obj ) {
385
386         boolean result = true;
387
388         // Determine if section is valid
389

390         if( sectionObj != null ) {
391             CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;
392
393             // Add header length to unwritten data length if section has currently has no
394
// unwritten information.
395

396             section.unwrittenEmpty = false; // Arun 9/27/99
397

398             if( section.unwrittenObjects == null )
399                 section.unwrittenObjects = new Vector(10,10);
400
401             // Convert the object reference to string value
402

403             String JavaDoc objRefStr = null;
404             try {
405                 objRefStr = Configuration.getORB().object_to_string(obj);
406
407                 // Add object reference to section and update counts
408

409                 section.unwrittenObjects.addElement(objRefStr);
410
411                 //$Write logrecord if threshold is exceeded
412
//$
413
//$ if( unwrittenLength >= LOG_THRESHOLD )
414
//$ try
415
//$ { formatLogRecords(false); }
416
//$ catch( IOException exc )
417
//$ {
418
//$ if( trc != null ) trc.error(ERR_WRITE).data(exc).write();
419
//$ result = false;
420
//$ }
421
} catch( Throwable JavaDoc exc ) {
422                 result = false;
423             }
424         } else {
425             result = false;
426         }
427
428         return result;
429     }
430
431     /**Adds the given opaque data structure to the sequence of those in the
432      * given section.
433      * <p>
434      * The data structures are stored in the order that they are added to the
435      * sequence. No checking is done for duplicates.
436      *
437      * @param sectionObj The object representing the section.
438      * @param data The data to be added.
439      *
440      * @return Indicates success of the operation.
441      *
442      * @see
443      */

444
445     synchronized boolean addData( java.lang.Object JavaDoc sectionObj,
446                                   byte[] data ) {
447
448         boolean result = true;
449         byte[] dataCopy;
450
451         // Determine if section is valid
452

453         if( sectionObj != null ) {
454             CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;
455
456             // Add header length to unwritten data length if section has currently has no
457
// unwritten information.
458

459             section.unwrittenEmpty = false; // Arun 9/27/99
460

461             if( section.unwrittenData == null )
462                 section.unwrittenData = new Vector(4,4);
463
464             // Make a copy of the data to add to the unwritten data queue.
465

466             dataCopy = new byte[data.length];
467             System.arraycopy(data,0,dataCopy,0,data.length);
468
469             // Add data item (sequence of octets) to section and update counts
470

471             section.unwrittenData.addElement(dataCopy);
472
473             //$Write logrecord if threshold is exceeded
474

475             //$ if( unwrittenLength >= LOG_THRESHOLD )
476
//$ try
477
//$ { formatLogRecords(false); }
478
//$ catch( IOException exc )
479
//$ {
480
//$ if( trc != null ) trc.error(ERR_WRITE).data(exc).write();
481
//$ result = false;
482
//$ }
483
} else {
484             result = false;
485         }
486
487         return result;
488     }
489
490     /**Write the contents of the CoordinatorLog to persistent storage.
491      * <p>
492      * If the force parameter is set, this requires that all information defined
493      * to the CoordinatorLog that has not already been written be recorded before
494      * the operation returns.
495      * <p>
496      * If rewrite is required, all information whether previously written or not
497      * is recorded.
498      * <p>
499      * The log record should include the LSN of the previous record
500      * written for the same transaction, if any, otherwise it is NULL. Further
501      * information may be added to the CoordinatorLog after it has been forced,
502      * and will be separately written in a subsequent log record, whose LSN will
503      * point to the current one.
504      * <p>
505      * This operation discharges the CoordinatorLog's requirement to rewrite. The
506      * keypoint lock must be obtained from the metaclass before checking whether
507      * a rewrite is required, and released after the write is complete.
508      *
509      * @param force Indicates whether the log data should be forced before this
510      * method returns.
511      *
512      * @return Indicates success of the operation.
513      *
514      * @see
515      */

516     boolean write( boolean force ) {
517
518         // Format the log records with a forced write.
519

520         boolean result = true;
521         try {
522             result = formatLogRecords(force);
523         } catch( IOException exc ) {
524             result = false;
525         }
526
527         return result;
528     }
529
530     /**Informs the CoordinatorLog object that it must rewrite its entire state
531      * the next time it writes a log record.
532      * <p>
533      * If the CoordinatorLog has state that has previously been written, it records
534      * the requirement to rewrite, otherwise it does not record the requirement.
535      *
536      * @param
537      *
538      * @return Indicates success of the operation.
539      *
540      * @see
541      */

542     private synchronized boolean requireRewrite() {
543         boolean result = true;
544
545         // Record the fact that a rewrite is required if a write has been done.
546

547         if( writeDone )
548             rewriteRequired = true;
549
550         return result;
551     }
552
553     /**Rewrites the contents of the CoordinatorLog to persistent storage.
554      * <p>
555      * This requires that all information defined to the CoordinatorLog that has
556      * already been written be re-written (unforced) to the log.
557      * <p>
558      * The CoordinatorLog also writes any unwritten state at this point.
559      * <p>
560      * The log record will contain a NULL LSN to indicate that no previous records
561      * for this transaction should be used for recovery. If no state has previously
562      * been written, the CoordinatorLog does nothing at this point and waits for
563      * a subsequent force operation.
564      * <p>
565      * This operation discharges the CoordinatorLog's requirement to rewrite.
566      *
567      * @param
568      *
569      * @return Indicates success of the operation.
570      *
571      * @see
572      */

573
574     private boolean rewrite() {
575
576         boolean result = true;
577
578         // If a rewrite is required, format a log record with all the CoordinatorLog
579
// data, with a non-forced write.
580

581         if( rewriteRequired )
582             try {
583                 result = formatLogRecords(false);
584             } catch( IOException exc ) {
585                 result = false;
586             }
587
588         return result;
589     }
590
591     /**
592      * Requests that the object reconstructs its state from the given stream.
593      * <p>
594      * There may be more than one if the CoordinatorLog elects to write to the
595      * log before it is asked to force the transaction state.
596      * <p>
597      * This operation is invoked when there are log records that need to
598      * be recovered. The CoordinatorLog should reconstruct the sequences of
599      * objects and data from each of the sections so that they can be queried by
600      * the callers that set them up.
601      *
602      * @param data The data to be used to create the CoordinatorLog object.
603      *
604      * @return Indicates success of the operation.
605      *
606      * @see
607      */

608     private boolean reconstruct( DataInputStream JavaDoc dataInput )
609         throws IOException {
610
611         boolean result = true;
612
613         // Read in the number of sections.
614

615         int numSections = dataInput.readUnsignedShort();
616
617
618         // Reconstruct each of the sections in the log record
619

620         while( --numSections >= 0 ) {
621
622             // Get the section name, number of objects and number of data items from the
623
// log record passed in.
624

625             int length = dataInput.readUnsignedShort();
626
627             // If the section name length is zero, then it contains no data, so skip it.
628

629             if( length > 0 ) {
630
631                 int numObjects = dataInput.readUnsignedShort();
632                 int numData = dataInput.readUnsignedShort();
633
634                 // Make a copy of the section name.
635

636                 byte[] stringData = new byte[length];
637                 dataInput.read(stringData);
638                 String JavaDoc sectionName = new String JavaDoc(stringData);
639
640                 // Create a section in the CoordinatorLog
641

642                 CoordinatorLogSection section = (CoordinatorLogSection) createSection(sectionName);
643
644                 // Add each object reference from the log record to the section.
645

646                 // BUGFIX(Ram J) added (writtenObject == null) check, so that
647
// the previously collected objects are not discarded.
648
if (numObjects > 0 && section.writtenObjects == null) {
649                     section.writtenObjects = new Vector(numObjects, 10);
650                 }
651
652                 for( int i = 0; i < numObjects; i++ ) {
653
654                     // Get the size of the object reference and allocate a buffer to make a copy
655
// of it.
656

657                     length = dataInput.readUnsignedShort();
658                     stringData = new byte[length];
659                     dataInput.read(stringData);
660                     String JavaDoc objRefStr = new String JavaDoc(stringData);
661
662                     // Add the object reference to the list of written objects.
663

664                     section.writtenObjects.addElement(objRefStr);
665                 }
666
667                 // Add each data item from the log record to the section.
668

669                 // BUGFIX(Ram J) added (writtenData == null) check, so that
670
// the previously collected data are not discarded.
671
if (numData > 0 && section.writtenData == null) {
672                     section.writtenData = new Vector(numData, 4);
673                 }
674
675                 for( int i = 0; i < numData; i++ ) {
676
677                     // Get the size of the data item and allocate a buffer to make a copy of it.
678

679                     length = dataInput.readUnsignedShort();
680                     byte[] dataItem = new byte[length];
681
682                     // Copy the data item into the storage allocated, and add that to the list
683
// of written data items.
684

685                     dataInput.read(dataItem);
686                     section.writtenData.addElement(dataItem);
687                 }
688             }
689         }
690
691         return result;
692     }
693
694     /**Returns a sequence containing all of the objects in the given section.
695      *
696      * @param sectionObj The object representing the section.
697      *
698      * @return The objects.
699      *
700      * @see
701      */

702     java.lang.Object JavaDoc[] getObjects( java.lang.Object JavaDoc sectionObj ) {
703         java.lang.Object JavaDoc[] result = null;
704
705         // Check that the section identifier is valid.
706
// Browse through the Queue of stringified object references, converting each
707
// to an actual object reference and adding it to the sequence returned from
708
// this method.
709

710         if( sectionObj != null ) {
711
712             CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;
713
714             int unwrittenSize = 0;
715             if( section.unwrittenObjects != null )
716                 unwrittenSize = section.unwrittenObjects.size();
717
718             int writtenSize = 0;
719             if( section.writtenObjects != null )
720                 writtenSize = section.writtenObjects.size();
721
722             result = new java.lang.Object JavaDoc[unwrittenSize + writtenSize];
723             int currObject = 0;
724
725             // Obtain the reference of the ORB.
726

727             ORB orb = Configuration.getORB();
728
729             // Go through the written objects.
730

731             for( int i = 0; i < writtenSize; i++ ) {
732
733                 org.omg.CORBA.Object JavaDoc obj = null;
734                 String JavaDoc refStr = (String JavaDoc)section.writtenObjects.elementAt(i);
735
736                 // Try ten times to convert the reference to a string.
737

738                 int retries = STRING_TO_REF_RETRIES;
739                 boolean discard = false;
740                 while( obj == null && retries-- > 0 && !discard ) {
741                     try {
742                         obj = orb.string_to_object(refStr);
743                     } catch( MARSHAL exc ) {
744                         // The MARSHAL exception indicates that the ImplHelper for the object has not been
745
// started, so try again after two seconds.
746

747                         try {
748                             Thread.sleep(2000);
749                         } catch( InterruptedException JavaDoc ex2 ) {
750                             _logger.log(Level.WARNING,
751                                     "jts.wait_for_resync_complete_interrupted");
752                             String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
753                                         "jts.wait_for_resync_complete_interrupted");
754                             throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
755                         }
756                     } catch( Throwable JavaDoc exc ) {
757                         // Any other exception indicates that the reference is invalid, so just discard it.
758

759                         discard = true;
760                     }
761                 }
762
763                 // Add the valid object to the list.
764

765                 if( !discard ){
766                     if( obj != null ){
767                         result[currObject++] = obj;
768                     }
769                     else {
770                         _logger.log(Level.SEVERE,
771                         "jts.unable_to_convert_object_reference_to_string_in_recovery");
772                          
773                           String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
774                         "jts.unable_to_convert_object_reference_to_string_in_recovery");
775                         
776                         throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
777                     }
778                 }
779             }
780
781             // Now get the unwritten objects. We do not need to do all the above error
782
// checking as these objects have not been recovered from the log.
783

784             for( int i = 0; i < unwrittenSize; i++ ) {
785                 try {
786
787                     // Add the valid object to the list.
788

789                     org.omg.CORBA.Object JavaDoc obj = orb.string_to_object((String JavaDoc)section.unwrittenObjects.elementAt(i));
790                     result[currObject++] = obj;
791                 } catch( Throwable JavaDoc exc ) {
792                     // If the object resulting from the string is invalid, then don't add it to
793
// the list.
794
}
795             }
796         }
797
798         return result;
799     }
800
801     /**Returns a sequence containing all of the opaque data in the given section.
802      *
803      * @param sectionObj The object representing the section.
804      *
805      * @return The data.
806      *
807      * @see
808      */

809
810     byte[][] getData( java.lang.Object JavaDoc sectionObj ) {
811
812         byte[][] result = null;
813
814         // Check that the section identifier is valid.
815
// Browse through the Queues of data items, adding each to the sequence
816
// returned from this method.
817

818         if( sectionObj != null ) {
819             CoordinatorLogSection section = (CoordinatorLogSection)sectionObj;
820
821             int unwrittenSize = 0;
822             if( section.unwrittenData != null )
823                 unwrittenSize = section.unwrittenData.size();
824
825             int writtenSize = 0;
826             if( section.writtenData != null )
827                 writtenSize = section.writtenData.size();
828
829             result = new byte[unwrittenSize+writtenSize][];
830
831             if( unwrittenSize > 0 )
832                 section.unwrittenData.copyInto(result);
833
834             for( int i = 0; i < writtenSize; i++ )
835                 result[unwrittenSize++] = (byte[])section.writtenData.elementAt(i);
836         }
837
838         return result;
839     }
840
841
842     /**Sets the local identifier for the CoordinatorLog object.
843      * <p>
844      * If the local identifier was previously 0, the CoordinatorLog object is
845      * added to the static list.
846      *
847      * @param localTID The new local identifier.
848      *
849      * @return
850      *
851      * @see
852      */

853     synchronized void setLocalTID( Long JavaDoc localTID ) {
854
855         // Check whether the local identifier is currently NULL.
856

857         boolean addToMetaclass = (localTID.longValue() != 0 && (this.localTID == null || this.localTID.longValue() == 0));
858
859         // Set the local identifier, and add the object to the metaclass if required.
860

861         this.localTID = localTID;
862         if( addToMetaclass )
863             addLog(localTID,this);
864
865     }
866
867     synchronized void setLocalTID( Long JavaDoc localTID, String JavaDoc logPath ) {
868
869         // Check whether the local identifier is currently NULL.
870

871         boolean addToMetaclass = (localTID.longValue() != 0 && (this.localTID == null || this.localTID.longValue() == 0));
872
873         // Set the local identifier, and add the object to the metaclass if required.
874

875         this.localTID = localTID;
876         if( addToMetaclass )
877             addLog(localTID,this, logPath);
878
879     }
880
881     /**Formats the information in a single section of the Coordinatorlog into a
882      * stream.
883      * <p>
884      * This internal method does not need to be synchronized.
885      * If the rewrite flag is not set, only information that has not already been
886      * written is formatted, otherwise all information is formatted.
887      *
888      * @param section The section.
889      * @param rewrite Indicates if the record is being rewritten.
890      * @param dataOutput The stream to which to data is output.
891      *
892      * @return
893      *
894      * @exception IOException The format failed.
895      *
896      * @see
897      */

898     private void formatSection( CoordinatorLogSection section,
899                                 boolean rewrite,
900                                 DataOutputStream JavaDoc dataOutput )
901         throws IOException {
902         // No formatting is done if the section is empty, and if rewrite is required,
903
// the written section is also empty.
904
// Note that we still need to write something out to satisfy the number of
905
// sections originally written, so we write out a name length of zero.
906

907         if( section.unwrittenEmpty &&
908             (!rewrite || section.writtenEmpty) ) {
909             dataOutput.writeShort(0);
910             return;
911         }
912
913         // Place length of section name into buffer.
914

915         dataOutput.writeShort(section.sectionName.length());
916
917         // Place count of number of object references into buffer, including written
918
// object references if rewrite is required.
919

920         int unwrittenObjectsSize = 0;
921         int writtenObjectsSize = 0;
922         if( section.unwrittenObjects != null )
923             unwrittenObjectsSize = section.unwrittenObjects.size();
924         if( rewrite &&
925             section.writtenObjects != null )
926             writtenObjectsSize = section.writtenObjects.size();
927
928         dataOutput.writeShort(unwrittenObjectsSize + writtenObjectsSize);
929
930         // Place count of number of data items into buffer, including written data
931
// items if rewrite is required.
932

933         int unwrittenDataSize = 0;
934         int writtenDataSize = 0;
935         if( section.unwrittenData != null )
936             unwrittenDataSize = section.unwrittenData.size();
937         if( rewrite &&
938             section.writtenData != null )
939             writtenDataSize = section.writtenData.size();
940
941         dataOutput.writeShort(unwrittenDataSize + writtenDataSize);
942
943         // Copy the section name into the buffer.
944

945         dataOutput.writeBytes(section.sectionName);
946
947         // If rewrite is required, first write the already-written object references
948

949         for( int i = 0; i < writtenObjectsSize; i++ ) {
950             String JavaDoc objRefStr = (String JavaDoc)section.writtenObjects.elementAt(i);
951             dataOutput.writeShort(objRefStr.length());
952             dataOutput.writeBytes(objRefStr);
953         }
954
955         // Next place length of each stringified object reference and the stringified
956
// object reference into the buffer. Move each from unwritten to written queue
957

958         for( int i = 0; i < unwrittenObjectsSize; i++ ) {
959             String JavaDoc objRefStr = (String JavaDoc)section.unwrittenObjects.elementAt(i);
960             dataOutput.writeShort(objRefStr.length());
961             dataOutput.writeBytes(objRefStr);
962
963             if( section.writtenObjects == null )
964                 section.writtenObjects = new Vector(unwrittenObjectsSize,10);
965
966             section.writtenObjects.addElement(objRefStr);
967         }
968
969         if( unwrittenObjectsSize > 0 )
970             section.unwrittenObjects.removeAllElements();
971
972         // Now we process the data items.
973
// If rewrite is required, first write the already-written data items.
974

975         for( int i = 0; i < writtenDataSize; i++ ) {
976             byte[] dataItem = (byte[])section.writtenData.elementAt(i);
977             dataOutput.writeShort(dataItem.length);
978             dataOutput.write(dataItem);
979         }
980
981         // Next place length of each stringified object reference and the stringified
982
// object reference into the buffer. Move each from unwritten to written queue
983

984         for( int i = 0; i < unwrittenDataSize; i++ ) {
985             byte[] dataItem = (byte[])section.unwrittenData.elementAt(i);
986             dataOutput.writeShort(dataItem.length);
987             dataOutput.write(dataItem);
988
989             if( section.writtenData == null )
990                 section.writtenData = new Vector(unwrittenDataSize,4);
991
992             section.writtenData.addElement(dataItem);
993         }
994         if( unwrittenDataSize > 0 )
995             section.unwrittenData.removeAllElements();
996
997         // Set unwritten_empty to TRUE and written_empty to FALSE since everything //
998
// has moved from the unwritten to the written queues. //
999

1000        section.unwrittenEmpty = true;
1001        section.writtenEmpty = false;
1002
1003    }
1004
1005    /**Formats the information in all sections of the CoordinatorLog.
1006     * <p>
1007     * The formatted information is written to the log.
1008     * <p>
1009     * This internal method does not need to be synchronized.
1010     * If the rewrite flag is not set, only information that has not already been
1011     * written is formatted, otherwise all information is formatted.
1012     *
1013     * @param forced Forced/unforced write indicator.
1014     *
1015     * @return Indicates success of the operation.
1016     *
1017     * @exception IOException The format failed.
1018     *
1019     * @see
1020     */

1021    private boolean formatLogRecords( boolean forced )
1022    throws IOException {
1023
1024        // If there is no LogFile for this transaction, and one cannot be obtained
1025
// from the metaclass, then no formatting can be done.
1026

1027        if (logPath == null)
1028            openLog();
1029        else
1030            openLog(logPath);
1031        if( logStateHolder.logFile == null ) {
1032            return false;
1033        }
1034
1035        // In order to check whether rewrite is required, we must first obtain the
1036
// keypoint lock to ensure that the metaclass is not in the process of
1037
// informing us that a rewrite is required.
1038
//$We must not wait for the keypoint lock while holding our own lock so
1039
//$release it now.
1040

1041        boolean result = false;
1042        try {
1043            logStateHolder.keypointLock.acquireReadLock();
1044            // Once we have the keypoint lock, it is OK to obtain our own.
1045

1046            synchronized( this ) {
1047
1048                // Place the tid in the buffer.
1049

1050                byteOutput.reset();
1051                dataOutput.writeLong(localTID.longValue());
1052
1053                // Write out the number of sections.
1054

1055                dataOutput.writeShort(sectionMapping.size());
1056
1057                // Format log section within map and add the information to buffer. Browse
1058
// through the CoordinatorLog filling in the buffer for each entry.
1059

1060                Enumeration sections = sectionMapping.elements();
1061        int sz = sectionMapping.size(); // Arun 9/27/99
1062
while (sz-- > 0) { // Arun 9/27/99
1063
formatSection((CoordinatorLogSection)sections.nextElement(),
1064                        rewriteRequired,dataOutput);
1065        }
1066
1067                // Write the buffer to the LogFile.
1068

1069                result = logStateHolder.logFile.write( forced ? LogFile.FORCED : LogFile.UNFORCED,
1070                                        byteOutput.toByteArray(),
1071                                        rewriteRequired ? LogFile.REWRITE : LogFile.NORMAL,
1072                                        null );
1073
1074                rewriteRequired = false;
1075                writeDone = true;
1076            }
1077        } finally {
1078            logStateHolder.keypointLock.releaseReadLock();
1079        }
1080
1081        return result;
1082    }
1083
1084    /**Provides static initialisation of the CoordinatorLog class.
1085     *
1086     * @param
1087     *
1088     * @return
1089     *
1090     * @see
1091     */

1092    static {
1093
1094        // Get the value of the keypoint trigger from the environment.
1095

1096        String JavaDoc keypointCountEnv = Configuration.getPropertyValue(Configuration.KEYPOINT_COUNT);
1097        keypointTrigger = LOG_DEF_KEY_TRIGGER;
1098        if( keypointCountEnv != null )
1099            try {
1100                keypointTrigger = Integer.parseInt(keypointCountEnv);
1101            } catch( Throwable JavaDoc e ) {}
1102
1103    }
1104
1105    /**Opens the log file for all CoordinatorLogs in this process.
1106     * <p>
1107     * If the log has already been opened, the operation uses the opened LogFile.
1108     *
1109     * @param
1110     *
1111     * @return Indicates success of the operation.
1112     *
1113     * @see
1114     */

1115    private static boolean openLog() {
1116        boolean result = false;
1117        String JavaDoc logName;
1118        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1119
1120        // If the log has been opened, there is nothing to do.
1121

1122        if( logStateHolder.log == null ) {
1123            logStateHolder.log = new Log();
1124            if( !logStateHolder.log.initialise() ) {
1125                logStateHolder.log = null;
1126                _logger.log(Level.SEVERE,"jts.cannot_initialise_log");
1127                String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1128                            "jts.cannot_initialise_log");
1129                throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1130            }
1131        }
1132
1133
1134        // Open the Log and set the logfile object reference. If there is no
1135
// ImplementationDef object available, then we cannot determine the log file
1136

1137
1138        // name, so the log cannot be opened.
1139
// Note that this does not preclude the log file being opened at some later
1140
// time.
1141

1142        String JavaDoc serverName = null;
1143        if( logStateHolder.log != null &&
1144            logStateHolder.logFile == null &&
1145            (serverName = Configuration.getServerName()) != null ) {
1146
1147        // get a coordinator log object from cache instead
1148
// of instantiating a new one Arun 9/27/99
1149
logStateHolder.logFile = logStateHolder.log.open(serverName,
1150                   CoordinatorLogPool.getCoordinatorLog());
1151
1152            if( logStateHolder.logFile == null ) {
1153                _logger.log(Level.SEVERE,"jts.cannot_open_log_file",serverName);
1154                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1155                                        "jts.cannot_open_log_file");
1156                 throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1157            } else
1158                Configuration.setLogFile(logStateHolder.logFile);
1159        }
1160
1161        result = (logStateHolder.log != null && logStateHolder.logFile != null);
1162
1163        return result;
1164    }
1165
1166    /**Opens the log file for all CoordinatorLogs in this process.
1167     * <p>
1168     * If the log has already been opened, the operation uses the opened LogFile.
1169     *
1170     * @param
1171     *
1172     * @return Indicates success of the operation.
1173     *
1174     * @see
1175     */

1176    private static boolean openLog(String JavaDoc logPath) {
1177        boolean result = false;
1178        String JavaDoc logName;
1179        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1180
1181        // If the log has been opened, there is nothing to do.
1182

1183        if( logStateHolder.log == null ) {
1184            logStateHolder.log = new Log(logPath);
1185            if( !logStateHolder.log.initialise() ) {
1186                logStateHolder.log = null;
1187                _logger.log(Level.SEVERE,"jts.cannot_initialise_log");
1188                String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1189                            "jts.cannot_initialise_log");
1190                throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1191            }
1192        }
1193
1194
1195        // Open the Log and set the logfile object reference. If there is no
1196
// ImplementationDef object available, then we cannot determine the log file
1197

1198
1199        // name, so the log cannot be opened.
1200
// Note that this does not preclude the log file being opened at some later
1201
// time.
1202

1203        String JavaDoc serverName = null;
1204        if( logStateHolder.log != null &&
1205            logStateHolder.logFile == null &&
1206            (serverName = Configuration.getServerName(logPath)) != null ) {
1207
1208        // get a coordinator log object from cache instead
1209
// of instantiating a new one Arun 9/27/99
1210
logStateHolder.logFile = logStateHolder.log.open(serverName,
1211                   CoordinatorLogPool.getCoordinatorLog(logPath));
1212
1213            if( logStateHolder.logFile == null ) {
1214                _logger.log(Level.SEVERE,"jts.cannot_open_log_file",serverName);
1215                 String JavaDoc msg = LogFormatter.getLocalizedMessage(_logger,
1216                                        "jts.cannot_open_log_file");
1217                 throw new org.omg.CORBA.INTERNAL JavaDoc(msg);
1218            } else
1219                Configuration.setLogFile(logPath,logStateHolder.logFile);
1220        }
1221
1222        result = (logStateHolder.log != null && logStateHolder.logFile != null);
1223
1224        return result;
1225    }
1226
1227    /**Process the log to build a sequence of CoordinatorLog objects which
1228     * represent all logged transactions.
1229     *
1230     * @param
1231     *
1232     * @return The CoordinatorLog objects, or null if there are none.
1233     *
1234     * @see
1235     */

1236    synchronized static Enumeration getLogged() {
1237
1238        Vector logRecords = null;
1239        Enumeration coordLogs = null;
1240
1241        // Initialise the Log. If the log cannot be opened, return an empty
1242
// sequence, with whatever exception the open returned.
1243

1244        if( openLog() ) {
1245             CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1246
1247            // Get the log records returned from the log and browse through them. Take
1248
// Take the sequence of log records returned from the LogFile and convert
1249
// them into the sequence of CoordinatorLog objects that are returned from
1250
// this method.
1251

1252            logRecords = logStateHolder.logFile.getLogRecords();
1253            for( int i = 0; i < logRecords.size(); i++ ) {
1254
1255                // Get tid value from the log record. Get the CoordinatorLog reference if
1256
// it exists in map, else create a new CoordinatorLog object; it will
1257
// added to the map when we set the transaction id.
1258

1259                byte[] buffer = (byte[])logRecords.elementAt(i);
1260                ByteArrayInputStream byteInput = new ByteArrayInputStream(buffer);
1261                DataInputStream JavaDoc dataInput = new DataInputStream JavaDoc(byteInput);
1262
1263                try {
1264                    Long JavaDoc localTID = new Long JavaDoc(dataInput.readLong());
1265                    CoordinatorLog coordLog = (CoordinatorLog)logStateHolder.activeLogs.get(localTID);
1266                    if( coordLog == null ) {
1267
1268                    // get a coordinator log object from cache instead
1269
// of instantiating a new one Arun 9/27/99
1270
coordLog = CoordinatorLogPool.getCoordinatorLog();
1271
1272                        coordLog.setLocalTID(localTID);
1273                    }
1274
1275                    // Reconstruct the CoordinatorLog information from the log record.
1276

1277                    coordLog.reconstruct(dataInput);
1278                } catch( IOException exc ) {
1279                }
1280            }
1281
1282            // Return a copy of the list of active CoordinatorLog objects.
1283

1284            coordLogs = logStateHolder.activeLogs.elements();
1285        }
1286
1287        // If the log could not be opened, return an empty Enumeration.
1288

1289        else
1290            coordLogs = new Hashtable().elements();
1291
1292
1293        return coordLogs;
1294    }
1295
1296    /**Process the log to build a sequence of CoordinatorLog objects which
1297     * represent all logged transactions.
1298     *
1299     * @param
1300     *
1301     * @return The CoordinatorLog objects, or null if there are none.
1302     *
1303     * @see
1304     */

1305    synchronized static Enumeration getLogged(String JavaDoc logPath) {
1306
1307        Vector logRecords = null;
1308        Enumeration coordLogs = null;
1309
1310        // Initialise the Log. If the log cannot be opened, return an empty
1311
// sequence, with whatever exception the open returned.
1312

1313        if( openLog(logPath) ) {
1314             CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1315
1316            // Get the log records returned from the log and browse through them. Take
1317
// Take the sequence of log records returned from the LogFile and convert
1318
// them into the sequence of CoordinatorLog objects that are returned from
1319
// this method.
1320

1321            logRecords = logStateHolder.logFile.getLogRecords();
1322            for( int i = 0; i < logRecords.size(); i++ ) {
1323
1324                // Get tid value from the log record. Get the CoordinatorLog reference if
1325
// it exists in map, else create a new CoordinatorLog object; it will
1326
// added to the map when we set the transaction id.
1327

1328                byte[] buffer = (byte[])logRecords.elementAt(i);
1329                ByteArrayInputStream byteInput = new ByteArrayInputStream(buffer);
1330                DataInputStream JavaDoc dataInput = new DataInputStream JavaDoc(byteInput);
1331
1332                try {
1333                    Long JavaDoc localTID = new Long JavaDoc(dataInput.readLong());
1334                    CoordinatorLog coordLog = (CoordinatorLog)logStateHolder.activeLogs.get(localTID);
1335                    if( coordLog == null ) {
1336
1337                    // get a coordinator log object from cache instead
1338
// of instantiating a new one Arun 9/27/99
1339
coordLog = CoordinatorLogPool.getCoordinatorLog(logPath);
1340
1341                        coordLog.setLocalTID(localTID, logPath);
1342                    }
1343
1344                    // Reconstruct the CoordinatorLog information from the log record.
1345

1346                    coordLog.reconstruct(dataInput);
1347                } catch( IOException exc ) {
1348                }
1349            }
1350
1351            // Return a copy of the list of active CoordinatorLog objects.
1352

1353            coordLogs = logStateHolder.activeLogs.elements();
1354        }
1355
1356        // If the log could not be opened, return an empty Enumeration.
1357

1358        else
1359            coordLogs = new Hashtable().elements();
1360
1361
1362        return coordLogs;
1363    }
1364
1365
1366    /**Remembers the mapping between the local transaction identifier and the
1367     * CoordinatorLog object.
1368     *
1369     * @param localTID The local transaction identifier.
1370     * @param clog The CoordinatorLog object.
1371     *
1372     * @return Indicates success of the operation.
1373     *
1374     * @see
1375     */

1376    private static boolean addLog(Long JavaDoc localTID,
1377                                               CoordinatorLog clog ) {
1378       CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1379
1380        boolean result = true;
1381
1382        logStateHolder.activeLogs.put(localTID,clog);
1383
1384        return result;
1385    }
1386
1387    private static boolean addLog(Long JavaDoc localTID,
1388                                               CoordinatorLog clog, String JavaDoc logPath ) {
1389       CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1390
1391        boolean result = true;
1392
1393        logStateHolder.activeLogs.put(localTID,clog);
1394
1395        return result;
1396    }
1397
1398    /**Removes the CoordinatorLog object from the map, and destroys it.
1399     *
1400     * @param localTID The local transaction identifier.
1401     *
1402     * @return Indicates success of the operation.
1403     *
1404     * @see
1405     */

1406    synchronized static boolean removeLog( Long JavaDoc localTID ) {
1407
1408        boolean result = true;
1409        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1410
1411        // Remove the given CoordinatorLog and local identifier from the map.
1412
// If the CoordinatorLog could be removed, we need to check whether a
1413
// keypoint is in progress, and if so, prevent the CoordinatorLog from being
1414
// called during the keypoint.
1415

1416        CoordinatorLog clog = (CoordinatorLog)logStateHolder.activeLogs.remove(localTID);
1417        if( clog != null ) {
1418
1419            // Obtaining the keypoint state lock prevents us from doing this while the
1420
// keypoint method is using the map.
1421

1422            synchronized( logStateHolder.keypointStateLock ) {
1423                // If a keypoint is in progress, look up the entry for the transaction in the
1424
// map and replace the value with a NULL entry.
1425

1426                if( logStateHolder.keypointInProgress && logStateHolder.keypointLogs != null )
1427                    logStateHolder.keypointLogs.put(localTID,null);
1428            }
1429
1430            // If the transaction is read-only, then do not increment the transaction count.
1431

1432            if( clog.writeDone )
1433                logStateHolder.tranCount++;
1434
1435            // return the CoordinatorLog object to the pool to be reused.
1436
// Arun 9/27/99
1437
clog.reUse();
1438
1439
1440            // Check whether a keypoint is required. This is based solely on the number
1441
// of (non-readonly) transactions since the last keypoint.
1442

1443            if( logStateHolder.tranCount >= keypointTrigger ) {
1444                logStateHolder.tranCount = 0;
1445                keypoint();
1446            }
1447        }
1448
1449
1450        return result;
1451    }
1452
1453    synchronized static boolean removeLog( Long JavaDoc localTID , String JavaDoc logPath) {
1454
1455        boolean result = true;
1456        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1457
1458        // Remove the given CoordinatorLog and local identifier from the map.
1459
// If the CoordinatorLog could be removed, we need to check whether a
1460
// keypoint is in progress, and if so, prevent the CoordinatorLog from being
1461
// called during the keypoint.
1462

1463        CoordinatorLog clog = (CoordinatorLog)logStateHolder.activeLogs.remove(localTID);
1464        if( clog != null ) {
1465
1466            // Obtaining the keypoint state lock prevents us from doing this while the
1467
// keypoint method is using the map.
1468

1469            synchronized( logStateHolder.keypointStateLock ) {
1470                // If a keypoint is in progress, look up the entry for the transaction in the
1471
// map and replace the value with a NULL entry.
1472

1473                if( logStateHolder.keypointInProgress && logStateHolder.keypointLogs != null )
1474                    logStateHolder.keypointLogs.put(localTID,null);
1475            }
1476
1477            // If the transaction is read-only, then do not increment the transaction count.
1478

1479            if( clog.writeDone )
1480                logStateHolder.tranCount++;
1481
1482            // return the CoordinatorLog object to the pool to be reused.
1483
// Arun 9/27/99
1484
clog.reUse(logPath);
1485
1486
1487            // Check whether a keypoint is required. This is based solely on the number
1488
// of (non-readonly) transactions since the last keypoint.
1489

1490            if( logStateHolder.tranCount >= keypointTrigger ) {
1491                logStateHolder.tranCount = 0;
1492                keypoint(logPath);
1493            }
1494        }
1495
1496
1497        return result;
1498     }
1499
1500    /**Performs a keypoint operation to allow old information in the log to be
1501     * discarded.
1502     * <p>
1503     * This operation is not synchronized as we do not want the latter part of the
1504     * operation to block other logging operations. The start of the keypoint is
1505     * in a separate method which is synchronized.
1506     *
1507     * @param
1508     *
1509     * @return
1510     *
1511     * @see
1512     */

1513    static void keypoint() {
1514        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1515
1516        byte[] keypointEndRecord = {
1517            (byte) 'K',
1518            (byte) 'E',
1519            (byte) 'Y',
1520            (byte) 'E',
1521            (byte) 'N',
1522            (byte) 'D'};
1523
1524        LogLSN previousLSN = new LogLSN();
1525        LogLSN keypointStartLSN = new LogLSN();
1526        boolean keypointRequired = false;
1527
1528        // Obtain the global keypoint lock to prevent any activity until the keypoint
1529
// start has been recorded.
1530
// Once the keypoint start has been completed, we can release the
1531
// keypoint lock. This will allow waiting CoordinatorLog writes to complete.
1532

1533        try {
1534            logStateHolder.keypointLock.acquireWriteLock();
1535            keypointRequired = startKeypoint(keypointStartLSN);
1536        } finally {
1537            logStateHolder.keypointLock.releaseWriteLock();
1538        }
1539
1540        // If no keypoint start record was written, then just return.
1541

1542        if( keypointStartLSN.isNULL() ) {
1543            return;
1544        }
1545
1546        // Once all of the CoordinatorLog objects have been unlocked, we must make
1547
// sure each of them has been rewritten before the keypoint end record is
1548
// written. Note that it is possible that one or more of the CoordinatorLog
1549
// objects in this list has already been deleted. We must be careful
1550
// to make sure that we do not invoke a method on a deleted object.
1551

1552        if( keypointRequired ) {
1553            Enumeration keypointLocalTIDs = logStateHolder.keypointLogs.keys();
1554            while( keypointLocalTIDs.hasMoreElements() )
1555
1556                // Obtain the keypoint state lock before obtaining the value from the map, as the
1557
// remove operation might be changing the value to NULL. Note that the
1558
// remove operation only changes the value of an entry in this map, it does
1559
// not change the number of entries in the map, so we do not need to hold the
1560
// mutex for the browse.
1561

1562                synchronized( logStateHolder.keypointStateLock ) {
1563                    CoordinatorLog currentLog = (CoordinatorLog)logStateHolder.keypointLogs.get(keypointLocalTIDs.nextElement());
1564
1565                    // Get the value out of the map, and if not NULL, tell it to rewrite itself.
1566

1567                    if( currentLog != null )
1568                        currentLog.rewrite();
1569                }
1570        }
1571
1572        // Now we know all CoordinatorLog objects have either independently rewritten
1573
// themselves, or we have done it explicitly. A keypoint end record is
1574
// written to indicate that the keypoint is complete.
1575

1576        logStateHolder.logFile.write(LogFile.UNFORCED,
1577                      keypointEndRecord,
1578                      LogFile.KEYPOINT_END,
1579                      previousLSN);
1580
1581        // All that is left to do is to inform the LogFile that the records before
1582
// the keypoint start record are no longer required.
1583
// Checkpoint the log. This allows the log to discard previous entries that
1584
// are no longer required.
1585

1586        logStateHolder.logFile.checkpoint(keypointStartLSN);
1587
1588        // Clear the keypoint in progress flag, empty the map of CoordinatorLog
1589
// objects being keypointed, release muteces and return.
1590

1591        logStateHolder.keypointInProgress = false;
1592        logStateHolder.keypointLogs.clear();
1593
1594    }
1595    static void keypoint(String JavaDoc logPath) {
1596        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1597
1598        byte[] keypointEndRecord = {
1599            (byte) 'K',
1600            (byte) 'E',
1601            (byte) 'Y',
1602            (byte) 'E',
1603            (byte) 'N',
1604            (byte) 'D'};
1605
1606        LogLSN previousLSN = new LogLSN();
1607        LogLSN keypointStartLSN = new LogLSN();
1608        boolean keypointRequired = false;
1609
1610        // Obtain the global keypoint lock to prevent any activity until the keypoint
1611
// start has been recorded.
1612
// Once the keypoint start has been completed, we can release the
1613
// keypoint lock. This will allow waiting CoordinatorLog writes to complete.
1614

1615        try {
1616            logStateHolder.keypointLock.acquireWriteLock();
1617            keypointRequired = startKeypoint(keypointStartLSN, logPath);
1618        } finally {
1619           logStateHolder.keypointLock.releaseWriteLock();
1620        }
1621
1622        // If no keypoint start record was written, then just return.
1623

1624        if( keypointStartLSN.isNULL() ) {
1625            return;
1626        }
1627
1628        // Once all of the CoordinatorLog objects have been unlocked, we must make
1629
// sure each of them has been rewritten before the keypoint end record is
1630
// written. Note that it is possible that one or more of the CoordinatorLog
1631
// objects in this list has already been deleted. We must be careful
1632
// to make sure that we do not invoke a method on a deleted object.
1633

1634        if( keypointRequired ) {
1635            Enumeration keypointLocalTIDs = logStateHolder.keypointLogs.keys();
1636            while( keypointLocalTIDs.hasMoreElements() )
1637
1638                // Obtain the keypoint state lock before obtaining the value from the map, as the
1639
// remove operation might be changing the value to NULL. Note that the
1640
// remove operation only changes the value of an entry in this map, it does
1641
// not change the number of entries in the map, so we do not need to hold the
1642
// mutex for the browse.
1643

1644                synchronized( logStateHolder.keypointStateLock ) {
1645                    CoordinatorLog currentLog = (CoordinatorLog)logStateHolder.keypointLogs.get(keypointLocalTIDs.nextElement());
1646
1647                    // Get the value out of the map, and if not NULL, tell it to rewrite itself.
1648

1649                    if( currentLog != null )
1650                        currentLog.rewrite();
1651                }
1652        }
1653
1654        // Now we know all CoordinatorLog objects have either independently rewritten
1655
// themselves, or we have done it explicitly. A keypoint end record is
1656
// written to indicate that the keypoint is complete.
1657

1658        logStateHolder.logFile.write(LogFile.UNFORCED,
1659                      keypointEndRecord,
1660                      LogFile.KEYPOINT_END,
1661                      previousLSN);
1662
1663        // All that is left to do is to inform the LogFile that the records before
1664
// the keypoint start record are no longer required.
1665
// Checkpoint the log. This allows the log to discard previous entries that
1666
// are no longer required.
1667

1668        logStateHolder.logFile.checkpoint(keypointStartLSN);
1669
1670        // Clear the keypoint in progress flag, empty the map of CoordinatorLog
1671
// objects being keypointed, release muteces and return.
1672

1673        logStateHolder.keypointInProgress = false;
1674        logStateHolder.keypointLogs.clear();
1675
1676    }
1677
1678    /**Handles a short-on-storage situation in the log by taking a keypoint.
1679
1680    /**Handles a short-on-storage situation in the log by taking a keypoint.
1681     *
1682     * @param reason The reason for the upcall.
1683     *
1684     * @return
1685     *
1686     * @see
1687     */

1688
1689    public void upcall( int reason ){
1690
1691        // Just perform a keypoint.
1692
if (logPath == null)
1693           CoordinatorLog.keypoint();
1694       else
1695           CoordinatorLog.keypoint(logPath);
1696
1697    }
1698
1699    /**Destroys the state of the CoordinatorLog class.
1700     *
1701     * @param
1702     *
1703     * @return
1704     *
1705     * @see
1706     */

1707
1708    synchronized static void finalizeAll(){
1709       CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1710
1711        boolean deleteFile = false;
1712
1713        // Obtain the keypoint state lock for this operation.
1714

1715        synchronized( logStateHolder.keypointStateLock ) {
1716
1717            // Close the LogFile.
1718

1719            if( logStateHolder.activeLogs != null ) {
1720
1721                // If there are no active log records sete delete_file to TRUE so that
1722
// LogFile_close will cause the logfile to be deleted
1723

1724                if( logStateHolder.activeLogs.size() == 0 )
1725                    deleteFile = true;
1726                logStateHolder.activeLogs.clear();
1727                logStateHolder.activeLogs = null;
1728            }
1729
1730            if( logStateHolder.logFile != null ) logStateHolder.logFile.close(deleteFile);
1731            logStateHolder.logFile = null;
1732
1733            // Discard the CoordinatorLog mappings.
1734

1735            if( logStateHolder.keypointLogs != null )
1736                logStateHolder.keypointLogs.clear();
1737            logStateHolder.keypointLogs = null;
1738        }
1739
1740        // Discard the locks.
1741

1742        logStateHolder.keypointStateLock = null;
1743        logStateHolder.keypointLock = null;
1744
1745    }
1746
1747    synchronized static void finalizeAll(String JavaDoc logPath){
1748       CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1749
1750        boolean deleteFile = false;
1751
1752        // Obtain the keypoint state lock for this operation.
1753

1754        synchronized( logStateHolder.keypointStateLock ) {
1755
1756            // Close the LogFile.
1757

1758            if( logStateHolder.activeLogs != null ) {
1759
1760                // If there are no active log records sete delete_file to TRUE so that
1761
// LogFile_close will cause the logfile to be deleted
1762

1763                if( logStateHolder.activeLogs.size() == 0 )
1764                    deleteFile = true;
1765                logStateHolder.activeLogs.clear();
1766                logStateHolder.activeLogs = null;
1767            }
1768
1769            if( logStateHolder.logFile != null ) logStateHolder.logFile.close(deleteFile);
1770            logStateHolder.logFile = null;
1771
1772            // Discard the CoordinatorLog mappings.
1773

1774            if( logStateHolder.keypointLogs != null )
1775                logStateHolder.keypointLogs.clear();
1776            logStateHolder.keypointLogs = null;
1777        }
1778
1779        // Discard the locks.
1780

1781        logStateHolder.keypointStateLock = null;
1782        logStateHolder.keypointLock = null;
1783
1784    }
1785
1786    /**Starts a keypoint.
1787     *
1788     * @param keypointStartLSN The LSN to hold the keypoint start LSN.
1789     *
1790     * @return Indicates whether keypoint is required.
1791     *
1792     * @see
1793     */

1794
1795    synchronized static boolean startKeypoint( LogLSN keypointStartLSN ) {
1796        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1797
1798        boolean keypointRequired = false;
1799
1800        // If a keypoint is in progress, return and do nothing.
1801

1802        if( logStateHolder.keypointInProgress ) {
1803            return false;
1804        }
1805        logStateHolder.keypointInProgress = true;
1806
1807        // Initialise the Log. If this fails, then return whatever exception the
1808
// open raised.
1809

1810        if( !openLog() ) {
1811            logStateHolder.keypointInProgress = false;
1812            return false;
1813        }
1814
1815        // If there are no known CoordinatorLog objects, then all that the keypoint
1816
// operation does is checkpoint the log at the head.
1817

1818        if( logStateHolder.activeLogs.size() == 0 )
1819            keypointRequired = false;
1820
1821        // Else go round all currently known CoordinatorLog objects and build a list
1822
// of them. New CoordinatorLog objects that are created during this time
1823
// will be suspended when they try to do an CoordinatorLog.addLog operation as
1824
// this thread has the lock.
1825

1826        else {
1827
1828            // Go through all current CoordinatorLog objects, telling them that they
1829
// must rewrite their state if necessary.
1830
// Each CoordinatorLog that exists at this time is copied to a separate list.
1831

1832            Enumeration clogs = logStateHolder.activeLogs.elements();
1833            while( clogs.hasMoreElements() ) {
1834                CoordinatorLog currentLog = (CoordinatorLog)clogs.nextElement();
1835                Long JavaDoc localTID = currentLog.localTID;
1836
1837                currentLog.requireRewrite();
1838                logStateHolder.keypointLogs.put(localTID,currentLog);
1839            }
1840            keypointRequired = logStateHolder.keypointLogs.size() > 0;
1841        }
1842
1843        // Write a keypoint start record now that we know no logging activity is
1844
// taking place.
1845

1846        byte[] keypointStartRecord = {(byte) 'K',
1847                                      (byte) 'E',
1848                                      (byte) 'Y',
1849                                      (byte) 'S',
1850                                      (byte) 'T',
1851                                      (byte) 'A',
1852                                      (byte) 'R',
1853                                      (byte) 'T'};
1854        logStateHolder.logFile.write(LogFile.UNFORCED,
1855                      keypointStartRecord,
1856                      LogFile.KEYPOINT_START,
1857                      keypointStartLSN);
1858
1859        return keypointRequired;
1860    }
1861
1862    synchronized static boolean startKeypoint( LogLSN keypointStartLSN, String JavaDoc logPath ) {
1863        CoordinatorLogStateHolder logStateHolder = getStateHolder(logPath);
1864
1865        boolean keypointRequired = false;
1866
1867        // If a keypoint is in progress, return and do nothing.
1868

1869        if( logStateHolder.keypointInProgress ) {
1870            return false;
1871        }
1872        logStateHolder.keypointInProgress = true;
1873
1874        // Initialise the Log. If this fails, then return whatever exception the
1875
// open raised.
1876

1877        if( !openLog(logPath) ) {
1878            logStateHolder.keypointInProgress = false;
1879            return false;
1880        }
1881
1882        // If there are no known CoordinatorLog objects, then all that the keypoint
1883
// operation does is checkpoint the log at the head.
1884

1885        if( logStateHolder.activeLogs.size() == 0 )
1886            keypointRequired = false;
1887
1888        // Else go round all currently known CoordinatorLog objects and build a list
1889
// of them. New CoordinatorLog objects that are created during this time
1890
// will be suspended when they try to do an CoordinatorLog.addLog operation as
1891
// this thread has the lock.
1892

1893        else {
1894
1895            // Go through all current CoordinatorLog objects, telling them that they
1896
// must rewrite their state if necessary.
1897
// Each CoordinatorLog that exists at this time is copied to a separate list.
1898

1899            Enumeration clogs = logStateHolder.activeLogs.elements();
1900            while( clogs.hasMoreElements() ) {
1901                CoordinatorLog currentLog = (CoordinatorLog)clogs.nextElement();
1902                Long JavaDoc localTID = currentLog.localTID;
1903
1904                currentLog.requireRewrite();
1905                logStateHolder.keypointLogs.put(localTID,currentLog);
1906            }
1907            keypointRequired = logStateHolder.keypointLogs.size() > 0;
1908        }
1909
1910        // Write a keypoint start record now that we know no logging activity is
1911
// taking place.
1912

1913        byte[] keypointStartRecord = {(byte) 'K',
1914                                      (byte) 'E',
1915                                      (byte) 'Y',
1916                                      (byte) 'S',
1917                                      (byte) 'T',
1918                                      (byte) 'A',
1919                                      (byte) 'R',
1920                                      (byte) 'T'};
1921        logStateHolder.logFile.write(LogFile.UNFORCED,
1922                      keypointStartRecord,
1923                      LogFile.KEYPOINT_START,
1924                      keypointStartLSN);
1925
1926        return keypointRequired;
1927    }
1928
1929    /**Dumps the state of the class.
1930     *
1931     * @param
1932     *
1933     * @return
1934     *
1935     * @see
1936     */

1937
1938    static void dumpClass() {
1939        // Dump the contained objects.
1940
CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1941
1942        logStateHolder.log.dump();
1943        logStateHolder.logFile.dump();
1944    }
1945
1946    /**Dumps the state of the object.
1947     *
1948     * @param
1949     *
1950     * @return
1951     *
1952     * @see
1953     */

1954
1955    void dump() {
1956        CoordinatorLogStateHolder logStateHolder = defaultLogStateHolder;
1957
1958        //$ somtrDUMP_OBJECT_HEADER;
1959

1960        // First dump the local transaction id.
1961

1962        // Dump each section in the CoordinatorLog object.
1963

1964        if( sectionMapping != null ) {
1965            //$ somtrDUMP_LIST_START;
1966

1967            Enumeration sections = sectionMapping.elements();
1968            while( sections.hasMoreElements() ) {
1969                CoordinatorLogSection section = (CoordinatorLogSection)sections.nextElement();
1970
1971                // Dump the section name.
1972

1973                //$ somtrDUMP_LIST_ELEMENT;
1974

1975                // Dump Written objects.
1976

1977                if( section.writtenObjects != null ) {
1978                    //$ somtrDUMP_LIST_START;
1979

1980                    Enumeration objects = section.writtenObjects.elements();
1981                    while( objects.hasMoreElements() ) {
1982                        String JavaDoc objStr = (String JavaDoc)objects.nextElement();
1983
1984                        //$ somtrDUMP_LIST_ELEMENT;
1985
}
1986
1987                    //$ somtrDUMP_LIST_END;
1988
}
1989
1990                // Dump unwritten objects.
1991

1992                if( section.unwrittenObjects != null ) {
1993                    //$ somtrDUMP_LIST_START;
1994

1995                    Enumeration objects = section.unwrittenObjects.elements();
1996                    while( objects.hasMoreElements() ) {
1997                        String JavaDoc objStr = (String JavaDoc)objects.nextElement();
1998
1999                        //$ somtrDUMP_LIST_ELEMENT;
2000
}
2001
2002                    //$ somtrDUMP_LIST_END;
2003
}
2004
2005                // Dump Written data.
2006

2007                if( section.writtenData != null ) {
2008                    //$ somtrDUMP_LIST_START;
2009

2010                    Enumeration data = section.writtenData.elements();
2011                    while( data.hasMoreElements() ) {
2012                        byte[] dataItem = (byte[])data.nextElement();
2013
2014                        //$ somtrDUMP_LIST_ELEMENT;
2015
}
2016
2017                    //$ somtrDUMP_LIST_END;
2018
}
2019
2020                // Dump unwritten data.
2021

2022                if( section.unwrittenData != null ) {
2023                    //$ somtrDUMP_LIST_START;
2024

2025                    Enumeration data = section.unwrittenData.elements();
2026                    while( data.hasMoreElements() ) {
2027                        byte[] dataItem = (byte[])data.nextElement();
2028
2029                        //$ somtrDUMP_LIST_ELEMENT;
2030
}
2031
2032                    //$ somtrDUMP_LIST_END;
2033
}
2034
2035
2036                // That is the end of the section.
2037

2038            }
2039
2040            //$ somtrDUMP_LIST_END;
2041
}
2042    }
2043    // START IASRI 4662745
2044
public static void setKeypointTrigger(int keypoint)
2045    {
2046        keypointTrigger = keypoint;
2047    }
2048    // END IASRI 4662745
2049

2050}
2051
2052/**The CoordinatorLogSection class stores information relevant to a section.
2053 *
2054 * @version 0.1
2055 *
2056 * @author Simon Holdsworth, IBM Corporation
2057 *
2058 * @see
2059*/

2060// CHANGE HISTORY
2061
//
2062
// Version By Change Description
2063
// 0.1 SAJH Initial implementation.
2064
//------------------------------------------------------------------------------
2065

2066class CoordinatorLogSection extends java.lang.Object JavaDoc {
2067    String JavaDoc sectionName = null;
2068    boolean unwrittenEmpty = true;
2069    boolean writtenEmpty = true;
2070    Vector unwrittenObjects = null;
2071    Vector unwrittenData = null;
2072    Vector writtenObjects = null;
2073    Vector writtenData = null;
2074    int headerLength = 0;
2075
2076    /**Creates a CoordinatorLogSection with the given name.
2077     *
2078     * @param sectionName The name of the section.
2079     *
2080     * @return
2081     *
2082     * @see
2083     */

2084    CoordinatorLogSection( String JavaDoc sectionName ) {
2085        this.sectionName = sectionName;
2086    }
2087
2088    /**Destroys the contents of a CoordinatorLogSection.
2089     *
2090     * @param
2091     *
2092     * @return
2093     *
2094     * @see
2095     */

2096    public void finalize() {
2097        if( unwrittenObjects != null )
2098            unwrittenObjects.removeAllElements();
2099
2100        if( unwrittenData != null )
2101            unwrittenData.removeAllElements();
2102
2103        if( writtenObjects != null )
2104            writtenObjects.removeAllElements();
2105
2106        if( writtenData != null )
2107            writtenData.removeAllElements();
2108
2109        sectionName = null;
2110
2111        unwrittenObjects = null;
2112        unwrittenData = null;
2113        writtenObjects = null;
2114        writtenData = null;
2115    }
2116
2117    /**Cleans up the CoordinatorLogSection and
2118     * returns it to the pool for re-use
2119     *
2120     * Note: the implementation of the cache does not ensure
2121     * that when an object is re-used there are no
2122     * outstanding references to that object. However, the
2123     * risk involved is minimal since reUse() replaces the
2124     * existing call to finalize(). The existing call to
2125     * finalize also does not ensure that there are no
2126     * outstanding references to the object being finalized.
2127     *
2128     * @param
2129     *
2130     * @return
2131     *
2132     * @see
2133     */

2134    synchronized void reUse() { // Arun 9/27/99
2135

2136        if( unwrittenObjects != null )
2137            unwrittenObjects.removeAllElements();
2138
2139        if( unwrittenData != null )
2140            unwrittenData.removeAllElements();
2141
2142        if( writtenObjects != null )
2143            writtenObjects.removeAllElements();
2144
2145        if( writtenData != null )
2146            writtenData.removeAllElements();
2147
2148        sectionName = null;
2149        unwrittenEmpty = true;
2150        writtenEmpty = true;
2151        headerLength = 0;
2152
2153    SectionPool.putCoordinatorLogSection(this);
2154    }
2155}
2156
2157/**
2158 * The SectionPool is used as a cache for CoordinatorLogSection objects.
2159 * This pool allows the re-use of these objects which are very expensive
2160 * to instantiate.
2161 *
2162 * The pool was added to improve performance of trnasaction logging
2163 *
2164 * @version 0.01
2165 *
2166 * @author Arun Krishnan
2167 *
2168 * @see
2169*/

2170
2171class SectionPool {
2172
2173    private Stack pool;
2174    private static final int MAXSTACKSIZE = 15;
2175
2176    static SectionPool SPool = new SectionPool();
2177
2178
2179    public SectionPool() {
2180    pool = new Stack();
2181    }
2182
2183    /**
2184     * Fetch a CoordinatorLogSection object from the cache. This method
2185     * should be called instead of "new CoordinatorLogSection()". If the
2186     * cache is empty this method will instantiate a new
2187     * CoordinatorLogSection object.
2188     *
2189     * @param String name the section name
2190     *
2191     * @return CoordinatorLogSection
2192     *
2193     */

2194    public static synchronized
2195       CoordinatorLogSection getCoordinatorLogSection(String JavaDoc name) {
2196
2197    CoordinatorLogSection cls;
2198    if (SPool.pool.empty()) {
2199        return new CoordinatorLogSection(name);
2200    }
2201    else {
2202        cls = (CoordinatorLogSection) SPool.pool.pop();
2203        cls.sectionName = name;
2204        return cls;
2205    }
2206    }
2207
2208    /**
2209     * Return a CoordinatorLogSection object to cache. Cache size is
2210     * limited to MAXSTACKSIZE by discarding objects when the cache
2211     * is already at max size.
2212     *
2213     * @param CoordinatorLogSection object to be returned to cache
2214     *
2215     */

2216    public static void putCoordinatorLogSection(CoordinatorLogSection cls) {
2217    if (SPool.pool.size() <= MAXSTACKSIZE) {
2218        SPool.pool.push(cls);
2219    }
2220    }
2221
2222}
2223
2224class CoordinatorLogStateHolder {
2225   LogFile logFile = null;
2226   Log log = null;
2227   Hashtable activeLogs = null;
2228   Hashtable keypointLogs = null;
2229   int tranCount = 0;
2230   boolean keypointInProgress = false;
2231   // java.lang.Object keypointLock = new java.lang.Object();
2232
RWLock keypointLock = null;
2233   java.lang.Object JavaDoc keypointStateLock = null;
2234}
2235
Popular Tags