History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/rmi/log/ReliableLog.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/rmi/log/ReliableLog.java+827−0
@@ -0,0 +1,827 @@
1/*
2 * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.rmi.log;
27
28import java.io.*;
29import java.lang.reflect.Constructor;
30import java.rmi.server.RMIClassLoader;
31import java.security.AccessController;
32import java.security.PrivilegedAction;
33import sun.security.action.GetBooleanAction;
34import sun.security.action.GetPropertyAction;
35
36/**
37 * This class is a simple implementation of a reliable Log. The
38 * client of a ReliableLog must provide a set of callbacks (via a
39 * LogHandler) that enables a ReliableLog to read and write
40 * checkpoints and log records. This implementation ensures that the
41 * current value of the data stored (via a ReliableLog) is recoverable
42 * after a system crash. <p>
43 *
44 * The secondary storage strategy is to record values in files using a
45 * representation of the caller's choosing. Two sorts of files are
46 * kept: snapshots and logs. At any instant, one snapshot is current.
47 * The log consists of a sequence of updates that have occurred since
48 * the current snapshot was taken. The current stable state is the
49 * value of the snapshot, as modified by the sequence of updates in
50 * the log. From time to time, the client of a ReliableLog instructs
51 * the package to make a new snapshot and clear the log. A ReliableLog
52 * arranges disk writes such that updates are stable (as long as the
53 * changes are force-written to disk) and atomic : no update is lost,
54 * and each update either is recorded completely in the log or not at
55 * all. Making a new snapshot is also atomic. <p>
56 *
57 * Normal use for maintaining the recoverable store is as follows: The
58 * client maintains the relevant data structure in virtual memory. As
59 * updates happen to the structure, the client informs the ReliableLog
60 * (all it "log") by calling log.update. Periodically, the client
61 * calls log.snapshot to provide the current value of the data
62 * structure. On restart, the client calls log.recover to obtain the
63 * latest snapshot and the following sequences of updates; the client
64 * applies the updates to the snapshot to obtain the state that
65 * existed before the crash. <p>
66 *
67 * The current logfile format is: <ol>
68 * <li> a format version number (two 4-octet integers, major and
69 * minor), followed by
70 * <li> a sequence of log records. Each log record contains, in
71 * order, <ol>
72 * <li> a 4-octet integer representing the length of the following log
73 * data,
74 * <li> the log data (variable length). </ol> </ol> <p>
75 *
76 * @see LogHandler
77 *
78 * @author Ann Wollrath
79 *
80 */
81public class ReliableLog {
82
83 public final static int PreferredMajorVersion = 0;
84 public final static int PreferredMinorVersion = 2;
85
86 // sun.rmi.log.debug=false
87 private boolean Debug = false;
88
89 private static String snapshotPrefix = "Snapshot.";
90 private static String logfilePrefix = "Logfile.";
91 private static String versionFile = "Version_Number";
92 private static String newVersionFile = "New_Version_Number";
93 private static int intBytes = 4;
94 private static long diskPageSize = 512;
95
96 private File dir; // base directory
97 private int version = 0; // current snapshot and log version
98 private String logName = null;
99 private LogFile log = null;
100 private long snapshotBytes = 0;
101 private long logBytes = 0;
102 private int logEntries = 0;
103 private long lastSnapshot = 0;
104 private long lastLog = 0;
105 //private long padBoundary = intBytes;
106 private LogHandler handler;
107 private final byte[] intBuf = new byte[4];
108
109 // format version numbers read from/written to this.log
110 private int majorFormatVersion = 0;
111 private int minorFormatVersion = 0;
112
113
114 /**
115 * Constructor for the log file. If the system property
116 * sun.rmi.log.class is non-null and the class specified by this
117 * property a) can be loaded, b) is a subclass of LogFile, and c) has a
118 * public two-arg constructor (String, String), ReliableLog uses the
119 * constructor to construct the LogFile.
120 **/
121 private static final Constructor<? extends LogFile>
122 logClassConstructor = getLogClassConstructor();
123
124 /**
125 * Creates a ReliableLog to handle checkpoints and logging in a
126 * stable storage directory.
127 *
128 * @param dirPath path to the stable storage directory
129 * @param logCl the closure object containing callbacks for logging and
130 * recovery
131 * @param pad ignored
132 * @exception IOException If a directory creation error has
133 * occurred or if initialSnapshot callback raises an exception or
134 * if an exception occurs during invocation of the handler's
135 * snapshot method or if other IOException occurs.
136 */
137 public ReliableLog(String dirPath,
138 LogHandler handler,
139 boolean pad)
140 throws IOException
141 {
142 super();
143 this.Debug = AccessController.doPrivileged(
144 new GetBooleanAction("sun.rmi.log.debug")).booleanValue();
145 dir = new File(dirPath);
146 if (!(dir.exists() && dir.isDirectory())) {
147 // create directory
148 if (!dir.mkdir()) {
149 throw new IOException("could not create directory for log: " +
150 dirPath);
151 }
152 }
153 //padBoundary = (pad ? diskPageSize : intBytes);
154 this.handler = handler;
155 lastSnapshot = 0;
156 lastLog = 0;
157 getVersion();
158 if (version == 0) {
159 try {
160 snapshot(handler.initialSnapshot());
161 } catch (IOException e) {
162 throw e;
163 } catch (Exception e) {
164 throw new IOException("initial snapshot failed with " +
165 "exception: " + e);
166 }
167 }
168 }
169
170 /**
171 * Creates a ReliableLog to handle checkpoints and logging in a
172 * stable storage directory.
173 *
174 * @param dirPath path to the stable storage directory
175 * @param logCl the closure object containing callbacks for logging and
176 * recovery
177 * @exception IOException If a directory creation error has
178 * occurred or if initialSnapshot callback raises an exception
179 */
180 public ReliableLog(String dirPath,
181 LogHandler handler)
182 throws IOException
183 {
184 this(dirPath, handler, false);
185 }
186
187 /* public methods */
188
189 /**
190 * Returns an object which is the value recorded in the current
191 * snapshot. This snapshot is recovered by calling the client
192 * supplied callback "recover" and then subsequently invoking
193 * the "readUpdate" callback to apply any logged updates to the state.
194 *
195 * @exception IOException If recovery fails due to serious log
196 * corruption, read update failure, or if an exception occurs
197 * during the recover callback
198 */
199 public synchronized Object recover()
200 throws IOException
201 {
202 if (Debug)
203 System.err.println("log.debug: recover()");
204
205 if (version == 0)
206 return null;
207
208 Object snapshot;
209 String fname = versionName(snapshotPrefix);
210 File snapshotFile = new File(fname);
211 InputStream in =
212 new BufferedInputStream(new FileInputStream(snapshotFile));
213
214 if (Debug)
215 System.err.println("log.debug: recovering from " + fname);
216
217 try {
218 try {
219 snapshot = handler.recover(in);
220
221 } catch (IOException e) {
222 throw e;
223 } catch (Exception e) {
224 if (Debug)
225 System.err.println("log.debug: recovery failed: " + e);
226 throw new IOException("log recover failed with " +
227 "exception: " + e);
228 }
229 snapshotBytes = snapshotFile.length();
230 } finally {
231 in.close();
232 }
233
234 return recoverUpdates(snapshot);
235 }
236
237 /**
238 * Records this update in the log file (does not force update to disk).
239 * The update is recorded by calling the client's "writeUpdate" callback.
240 * This method must not be called until this log's recover method has
241 * been invoked (and completed).
242 *
243 * @param value the object representing the update
244 * @exception IOException If an exception occurred during a
245 * writeUpdate callback or if other I/O error has occurred.
246 */
247 public synchronized void update(Object value) throws IOException {
248 update(value, true);
249 }
250
251 /**
252 * Records this update in the log file. The update is recorded by
253 * calling the client's writeUpdate callback. This method must not be
254 * called until this log's recover method has been invoked
255 * (and completed).
256 *
257 * @param value the object representing the update
258 * @param forceToDisk ignored; changes are always forced to disk
259 * @exception IOException If force-write to log failed or an
260 * exception occurred during the writeUpdate callback or if other
261 * I/O error occurs while updating the log.
262 */
263 public synchronized void update(Object value, boolean forceToDisk)
264 throws IOException
265 {
266 // avoid accessing a null log field.
267 if (log == null) {
268 throw new IOException("log is inaccessible, " +
269 "it may have been corrupted or closed");
270 }
271
272 /*
273 * If the entry length field spans a sector boundary, write
274 * the high order bit of the entry length, otherwise write zero for
275 * the entry length.
276 */
277 long entryStart = log.getFilePointer();
278 boolean spansBoundary = log.checkSpansBoundary(entryStart);
279 writeInt(log, spansBoundary? 1<<31 : 0);
280
281 /*
282 * Write update, and sync.
283 */
284 try {
285 handler.writeUpdate(new LogOutputStream(log), value);
286 } catch (IOException e) {
287 throw e;
288 } catch (Exception e) {
289 throw (IOException)
290 new IOException("write update failed").initCause(e);
291 }
292 log.sync();
293
294 long entryEnd = log.getFilePointer();
295 int updateLen = (int) ((entryEnd - entryStart) - intBytes);
296 log.seek(entryStart);
297
298 if (spansBoundary) {
299 /*
300 * If length field spans a sector boundary, then
301 * the next two steps are required (see 4652922):
302 *
303 * 1) Write actual length with high order bit set; sync.
304 * 2) Then clear high order bit of length; sync.
305 */
306 writeInt(log, updateLen | 1<<31);
307 log.sync();
308
309 log.seek(entryStart);
310 log.writeByte(updateLen >> 24);
311 log.sync();
312
313 } else {
314 /*
315 * Write actual length; sync.
316 */
317 writeInt(log, updateLen);
318 log.sync();
319 }
320
321 log.seek(entryEnd);
322 logBytes = entryEnd;
323 lastLog = System.currentTimeMillis();
324 logEntries++;
325 }
326
327 /**
328 * Returns the constructor for the log file if the system property
329 * sun.rmi.log.class is non-null and the class specified by the
330 * property a) can be loaded, b) is a subclass of LogFile, and c) has a
331 * public two-arg constructor (String, String); otherwise returns null.
332 **/
333 private static Constructor<? extends LogFile>
334 getLogClassConstructor() {
335
336 String logClassName = AccessController.doPrivileged(
337 new GetPropertyAction("sun.rmi.log.class"));
338 if (logClassName != null) {
339 try {
340 ClassLoader loader =
341 AccessController.doPrivileged(
342 new PrivilegedAction<ClassLoader>() {
343 public ClassLoader run() {
344 return ClassLoader.getSystemClassLoader();
345 }
346 });
347 Class cl = loader.loadClass(logClassName);
348 if (LogFile.class.isAssignableFrom(cl)) {
349 return cl.getConstructor(String.class, String.class);
350 }
351 } catch (Exception e) {
352 System.err.println("Exception occurred:");
353 e.printStackTrace();
354 }
355 }
356 return null;
357 }
358
359 /**
360 * Records this value as the current snapshot by invoking the client
361 * supplied "snapshot" callback and then empties the log.
362 *
363 * @param value the object representing the new snapshot
364 * @exception IOException If an exception occurred during the
365 * snapshot callback or if other I/O error has occurred during the
366 * snapshot process
367 */
368 public synchronized void snapshot(Object value)
369 throws IOException
370 {
371 int oldVersion = version;
372 incrVersion();
373
374 String fname = versionName(snapshotPrefix);
375 File snapshotFile = new File(fname);
376 FileOutputStream out = new FileOutputStream(snapshotFile);
377 try {
378 try {
379 handler.snapshot(out, value);
380 } catch (IOException e) {
381 throw e;
382 } catch (Exception e) {
383 throw new IOException("snapshot failed", e);
384 }
385 lastSnapshot = System.currentTimeMillis();
386 } finally {
387 out.close();
388 snapshotBytes = snapshotFile.length();
389 }
390
391 openLogFile(true);
392 writeVersionFile(true);
393 commitToNewVersion();
394 deleteSnapshot(oldVersion);
395 deleteLogFile(oldVersion);
396 }
397
398 /**
399 * Close the stable storage directory in an orderly manner.
400 *
401 * @exception IOException If an I/O error occurs when the log is
402 * closed
403 */
404 public synchronized void close() throws IOException {
405 if (log == null) return;
406 try {
407 log.close();
408 } finally {
409 log = null;
410 }
411 }
412
413 /**
414 * Returns the size of the snapshot file in bytes;
415 */
416 public long snapshotSize() {
417 return snapshotBytes;
418 }
419
420 /**
421 * Returns the size of the log file in bytes;
422 */
423 public long logSize() {
424 return logBytes;
425 }
426
427 /* private methods */
428
429 /**
430 * Write an int value in single write operation. This method
431 * assumes that the caller is synchronized on the log file.
432 *
433 * @param out output stream
434 * @param val int value
435 * @throws IOException if any other I/O error occurs
436 */
437 private void writeInt(DataOutput out, int val)
438 throws IOException
439 {
440 intBuf[0] = (byte) (val >> 24);
441 intBuf[1] = (byte) (val >> 16);
442 intBuf[2] = (byte) (val >> 8);
443 intBuf[3] = (byte) val;
444 out.write(intBuf);
445 }
446
447 /**
448 * Generates a filename prepended with the stable storage directory path.
449 *
450 * @param name the leaf name of the file
451 */
452 private String fName(String name) {
453 return dir.getPath() + File.separator + name;
454 }
455
456 /**
457 * Generates a version 0 filename prepended with the stable storage
458 * directory path
459 *
460 * @param name version file name
461 */
462 private String versionName(String name) {
463 return versionName(name, 0);
464 }
465
466 /**
467 * Generates a version filename prepended with the stable storage
468 * directory path with the version number as a suffix.
469 *
470 * @param name version file name
471 * @thisversion a version number
472 */
473 private String versionName(String prefix, int ver) {
474 ver = (ver == 0) ? version : ver;
475 return fName(prefix) + String.valueOf(ver);
476 }
477
478 /**
479 * Increments the directory version number.
480 */
481 private void incrVersion() {
482 do { version++; } while (version==0);
483 }
484
485 /**
486 * Delete a file.
487 *
488 * @param name the name of the file
489 * @exception IOException If new version file couldn't be removed
490 */
491 private void deleteFile(String name) throws IOException {
492
493 File f = new File(name);
494 if (!f.delete())
495 throw new IOException("couldn't remove file: " + name);
496 }
497
498 /**
499 * Removes the new version number file.
500 *
501 * @exception IOException If an I/O error has occurred.
502 */
503 private void deleteNewVersionFile() throws IOException {
504 deleteFile(fName(newVersionFile));
505 }
506
507 /**
508 * Removes the snapshot file.
509 *
510 * @param ver the version to remove
511 * @exception IOException If an I/O error has occurred.
512 */
513 private void deleteSnapshot(int ver) throws IOException {
514 if (ver == 0) return;
515 deleteFile(versionName(snapshotPrefix, ver));
516 }
517
518 /**
519 * Removes the log file.
520 *
521 * @param ver the version to remove
522 * @exception IOException If an I/O error has occurred.
523 */
524 private void deleteLogFile(int ver) throws IOException {
525 if (ver == 0) return;
526 deleteFile(versionName(logfilePrefix, ver));
527 }
528
529 /**
530 * Opens the log file in read/write mode. If file does not exist, it is
531 * created.
532 *
533 * @param truncate if true and file exists, file is truncated to zero
534 * length
535 * @exception IOException If an I/O error has occurred.
536 */
537 private void openLogFile(boolean truncate) throws IOException {
538 try {
539 close();
540 } catch (IOException e) { /* assume this is okay */
541 }
542
543 logName = versionName(logfilePrefix);
544
545 try {
546 log = (logClassConstructor == null ?
547 new LogFile(logName, "rw") :
548 logClassConstructor.newInstance(logName, "rw"));
549 } catch (Exception e) {
550 throw (IOException) new IOException(
551 "unable to construct LogFile instance").initCause(e);
552 }
553
554 if (truncate) {
555 initializeLogFile();
556 }
557 }
558
559 /**
560 * Creates a new log file, truncated and initialized with the format
561 * version number preferred by this implementation.
562 * <p>Environment: inited, synchronized
563 * <p>Precondition: valid: log, log contains nothing useful
564 * <p>Postcondition: if successful, log is initialised with the format
565 * version number (Preferred{Major,Minor}Version), and logBytes is
566 * set to the resulting size of the updatelog, and logEntries is set to
567 * zero. Otherwise, log is in an indeterminate state, and logBytes
568 * is unchanged, and logEntries is unchanged.
569 *
570 * @exception IOException If an I/O error has occurred.
571 */
572 private void initializeLogFile()
573 throws IOException
574 {
575 log.setLength(0);
576 majorFormatVersion = PreferredMajorVersion;
577 writeInt(log, PreferredMajorVersion);
578 minorFormatVersion = PreferredMinorVersion;
579 writeInt(log, PreferredMinorVersion);
580 logBytes = intBytes * 2;
581 logEntries = 0;
582 }
583
584
585 /**
586 * Writes out version number to file.
587 *
588 * @param newVersion if true, writes to a new version file
589 * @exception IOException If an I/O error has occurred.
590 */
591 private void writeVersionFile(boolean newVersion) throws IOException {
592 String name;
593 if (newVersion) {
594 name = newVersionFile;
595 } else {
596 name = versionFile;
597 }
598 DataOutputStream out =
599 new DataOutputStream(new FileOutputStream(fName(name)));
600 writeInt(out, version);
601 out.close();
602 }
603
604 /**
605 * Creates the initial version file
606 *
607 * @exception IOException If an I/O error has occurred.
608 */
609 private void createFirstVersion() throws IOException {
610 version = 0;
611 writeVersionFile(false);
612 }
613
614 /**
615 * Commits (atomically) the new version.
616 *
617 * @exception IOException If an I/O error has occurred.
618 */
619 private void commitToNewVersion() throws IOException {
620 writeVersionFile(false);
621 deleteNewVersionFile();
622 }
623
624 /**
625 * Reads version number from a file.
626 *
627 * @param name the name of the version file
628 * @return the version
629 * @exception IOException If an I/O error has occurred.
630 */
631 private int readVersion(String name) throws IOException {
632 DataInputStream in = new DataInputStream(new FileInputStream(name));
633 try {
634 return in.readInt();
635 } finally {
636 in.close();
637 }
638 }
639
640 /**
641 * Sets the version. If version file does not exist, the initial
642 * version file is created.
643 *
644 * @exception IOException If an I/O error has occurred.
645 */
646 private void getVersion() throws IOException {
647 try {
648 version = readVersion(fName(newVersionFile));
649 commitToNewVersion();
650 } catch (IOException e) {
651 try {
652 deleteNewVersionFile();
653 }
654 catch (IOException ex) {
655 }
656
657 try {
658 version = readVersion(fName(versionFile));
659 }
660 catch (IOException ex) {
661 createFirstVersion();
662 }
663 }
664 }
665
666 /**
667 * Applies outstanding updates to the snapshot.
668 *
669 * @param state the most recent snapshot
670 * @exception IOException If serious log corruption is detected or
671 * if an exception occurred during a readUpdate callback or if
672 * other I/O error has occurred.
673 * @return the resulting state of the object after all updates
674 */
675 private Object recoverUpdates(Object state)
676 throws IOException
677 {
678 logBytes = 0;
679 logEntries = 0;
680
681 if (version == 0) return state;
682
683 String fname = versionName(logfilePrefix);
684 InputStream in =
685 new BufferedInputStream(new FileInputStream(fname));
686 DataInputStream dataIn = new DataInputStream(in);
687
688 if (Debug)
689 System.err.println("log.debug: reading updates from " + fname);
690
691 try {
692 majorFormatVersion = dataIn.readInt(); logBytes += intBytes;
693 minorFormatVersion = dataIn.readInt(); logBytes += intBytes;
694 } catch (EOFException e) {
695 /* This is a log which was corrupted and/or cleared (by
696 * fsck or equivalent). This is not an error.
697 */
698 openLogFile(true); // create and truncate
699 in = null;
700 }
701 /* A new major version number is a catastrophe (it means
702 * that the file format is incompatible with older
703 * clients, and we'll only be breaking things by trying to
704 * use the log). A new minor version is no big deal for
705 * upward compatibility.
706 */
707 if (majorFormatVersion != PreferredMajorVersion) {
708 if (Debug) {
709 System.err.println("log.debug: major version mismatch: " +
710 majorFormatVersion + "." + minorFormatVersion);
711 }
712 throw new IOException("Log file " + logName + " has a " +
713 "version " + majorFormatVersion +
714 "." + minorFormatVersion +
715 " format, and this implementation " +
716 " understands only version " +
717 PreferredMajorVersion + "." +
718 PreferredMinorVersion);
719 }
720
721 try {
722 while (in != null) {
723 int updateLen = 0;
724
725 try {
726 updateLen = dataIn.readInt();
727 } catch (EOFException e) {
728 if (Debug)
729 System.err.println("log.debug: log was sync'd cleanly");
730 break;
731 }
732 if (updateLen <= 0) {/* crashed while writing last log entry */
733 if (Debug) {
734 System.err.println(
735 "log.debug: last update incomplete, " +
736 "updateLen = 0x" +
737 Integer.toHexString(updateLen));
738 }
739 break;
740 }
741
742 // this is a fragile use of available() which relies on the
743 // twin facts that BufferedInputStream correctly consults
744 // the underlying stream, and that FileInputStream returns
745 // the number of bytes remaining in the file (via FIONREAD).
746 if (in.available() < updateLen) {
747 /* corrupted record at end of log (can happen since we
748 * do only one fsync)
749 */
750 if (Debug)
751 System.err.println("log.debug: log was truncated");
752 break;
753 }
754
755 if (Debug)
756 System.err.println("log.debug: rdUpdate size " + updateLen);
757 try {
758 state = handler.readUpdate(new LogInputStream(in, updateLen),
759 state);
760 } catch (IOException e) {
761 throw e;
762 } catch (Exception e) {
763 e.printStackTrace();
764 throw new IOException("read update failed with " +
765 "exception: " + e);
766 }
767 logBytes += (intBytes + updateLen);
768 logEntries++;
769 } /* while */
770 } finally {
771 if (in != null)
772 in.close();
773 }
774
775 if (Debug)
776 System.err.println("log.debug: recovered updates: " + logEntries);
777
778 /* reopen log file at end */
779 openLogFile(false);
780
781 // avoid accessing a null log field
782 if (log == null) {
783 throw new IOException("rmid's log is inaccessible, " +
784 "it may have been corrupted or closed");
785 }
786
787 log.seek(logBytes);
788 log.setLength(logBytes);
789
790 return state;
791 }
792
793 /**
794 * ReliableLog's log file implementation. This implementation
795 * is subclassable for testing purposes.
796 */
797 public static class LogFile extends RandomAccessFile {
798
799 private final FileDescriptor fd;
800
801 /**
802 * Constructs a LogFile and initializes the file descriptor.
803 **/
804 public LogFile(String name, String mode)
805 throws FileNotFoundException, IOException
806 {
807 super(name, mode);
808 this.fd = getFD();
809 }
810
811 /**
812 * Invokes sync on the file descriptor for this log file.
813 */
814 protected void sync() throws IOException {
815 fd.sync();
816 }
817
818 /**
819 * Returns true if writing 4 bytes starting at the specified file
820 * position, would span a 512 byte sector boundary; otherwise returns
821 * false.
822 **/
823 protected boolean checkSpansBoundary(long fp) {
824 return fp % 512 > 508;
825 }
826 }
827}