1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.collection.MappedByteBuffer;
13 
14 import hunt.io.ByteBuffer;
15 
16 import hunt.Exceptions;
17 import hunt.stream.FileDescriptor;
18 
19 /**
20  * A direct byte buffer whose content is a memory-mapped region of a file.
21  *
22  * <p> Mapped byte buffers are created via the {@link
23  * java.nio.channels.FileChannel#map FileChannel.map} method.  This class
24  * extends the {@link ByteBuffer} class with operations that are specific to
25  * memory-mapped file regions.
26  *
27  * <p> A mapped byte buffer and the file mapping that it represents remain
28  * valid until the buffer itself is garbage-collected.
29  *
30  * <p> The content of a mapped byte buffer can change at any time, for example
31  * if the content of the corresponding region of the mapped file is changed by
32  * this program or another.  Whether or not such changes occur, and when they
33  * occur, is operating-system dependent and therefore unspecified.
34  *
35  * <a name="inaccess"></a><p> All or part of a mapped byte buffer may become
36  * inaccessible at any time, for example if the mapped file is truncated.  An
37  * attempt to access an inaccessible region of a mapped byte buffer will not
38  * change the buffer's content and will cause an unspecified exception to be
39  * thrown either at the time of the access or at some later time.  It is
40  * therefore strongly recommended that appropriate precautions be taken to
41  * avoid the manipulation of a mapped file by this program, or by a
42  * concurrently running program, except to read or write the file's content.
43  *
44  * <p> Mapped byte buffers otherwise behave no differently than ordinary direct
45  * byte buffers. </p>
46  *
47  *
48  * @author Mark Reinhold
49  * @author JSR-51 Expert Group
50  */
51 
52 abstract class MappedByteBuffer : ByteBuffer
53 {
54 
55     // This is a little bit backwards: By rights MappedByteBuffer should be a
56     // subclass of DirectByteBuffer, but to keep the spec clear and simple, and
57     // for optimization purposes, it's easier to do it the other way around.
58     // This works because DirectByteBuffer is a package-private class.
59 
60     // For mapped buffers, a FileDescriptor that may be used for mapping
61     // operations if valid; null if the buffer is not mapped.
62     private FileDescriptor fd;
63 
64     // This should only be invoked by the DirectByteBuffer constructors
65     //
66     this(int mark, int pos, int lim, int cap, // package-private
67                      FileDescriptor fd)
68     {
69         super(mark, pos, lim, cap);
70         this.fd = fd;
71     }
72 
73     this(int mark, int pos, int lim, int cap) { // package-private
74         super(mark, pos, lim, cap);
75         this.fd = null;
76     }
77 
78     private void checkMapped() {
79         if (fd is null)
80             // Can only happen if a luser explicitly casts a direct byte buffer
81             throw new UnsupportedOperationException();
82     }
83 
84     // // Returns the distance (in bytes) of the buffer from the page aligned address
85     // // of the mapping. Computed each time to avoid storing in every direct buffer.
86     // private long mappingOffset() {
87     //     int ps = Bits.pageSize();
88     //     long offset = address % ps;
89     //     return (offset >= 0) ? offset : (ps + offset);
90     // }
91 
92     // private long mappingAddress(long mappingOffset) {
93     //     return address - mappingOffset;
94     // }
95 
96     // private long mappingLength(long mappingOffset) {
97     //     return cast(long)capacity() + mappingOffset;
98     // }
99 
100     // /**
101     //  * Tells whether or not this buffer's content is resident in physical
102     //  * memory.
103     //  *
104     //  * <p> A return value of <tt>true</tt> implies that it is highly likely
105     //  * that all of the data in this buffer is resident in physical memory and
106     //  * may therefore be accessed without incurring any virtual-memory page
107     //  * faults or I/O operations.  A return value of <tt>false</tt> does not
108     //  * necessarily imply that the buffer's content is not resident in physical
109     //  * memory.
110     //  *
111     //  * <p> The returned value is a hint, rather than a guarantee, because the
112     //  * underlying operating system may have paged out some of the buffer's data
113     //  * by the time that an invocation of this method returns.  </p>
114     //  *
115     //  * @return  <tt>true</tt> if it is likely that this buffer's content
116     //  *          is resident in physical memory
117     //  */
118     // final bool isLoaded() {
119     //     checkMapped();
120     //     if ((address == 0) || (capacity() == 0))
121     //         return true;
122     //     long offset = mappingOffset();
123     //     long length = mappingLength(offset);
124     //     return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length));
125     // }
126 
127     // // not used, but a potential target for a store, see load() for details.
128     // private static byte unused;
129 
130     // /**
131     //  * Loads this buffer's content into physical memory.
132     //  *
133     //  * <p> This method makes a best effort to ensure that, when it returns,
134     //  * this buffer's content is resident in physical memory.  Invoking this
135     //  * method may cause some number of page faults and I/O operations to
136     //  * occur. </p>
137     //  *
138     //  * @return  This buffer
139     //  */
140     // final MappedByteBuffer load() {
141     //     checkMapped();
142     //     if ((address == 0) || (capacity() == 0))
143     //         return this;
144     //     long offset = mappingOffset();
145     //     long length = mappingLength(offset);
146     //     load0(mappingAddress(offset), length);
147 
148     //     // Read a byte from each page to bring it into memory. A checksum
149     //     // is computed as we go along to prevent the compiler from otherwise
150     //     // considering the loop as dead code.
151     //     Unsafe unsafe = Unsafe.getUnsafe();
152     //     int ps = Bits.pageSize();
153     //     int count = Bits.pageCount(length);
154     //     long a = mappingAddress(offset);
155     //     byte x = 0;
156     //     for (int i=0; i<count; i++) {
157     //         x ^= unsafe.getByte(a);
158     //         a += ps;
159     //     }
160     //     if (unused != 0)
161     //         unused = x;
162 
163     //     return this;
164     // }
165 
166     // /**
167     //  * Forces any changes made to this buffer's content to be written to the
168     //  * storage device containing the mapped file.
169     //  *
170     //  * <p> If the file mapped into this buffer resides on a local storage
171     //  * device then when this method returns it is guaranteed that all changes
172     //  * made to the buffer since it was created, or since this method was last
173     //  * invoked, will have been written to that device.
174     //  *
175     //  * <p> If the file does not reside on a local device then no such guarantee
176     //  * is made.
177     //  *
178     //  * <p> If this buffer was not mapped in read/write mode ({@link
179     //  * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this
180     //  * method has no effect. </p>
181     //  *
182     //  * @return  This buffer
183     //  */
184     // final MappedByteBuffer force() {
185     //     checkMapped();
186     //     if ((address != 0) && (capacity() != 0)) {
187     //         long offset = mappingOffset();
188     //         force0(fd, mappingAddress(offset), mappingLength(offset));
189     //     }
190     //     return this;
191     // }
192 
193     private bool isLoaded0(long address, long length, int pageCount) {
194         implementationMissing(false);
195         return false;
196     }
197     private void load0(long address, long length) {
198         implementationMissing(false);
199     }
200     private void force0(FileDescriptor fd, long address, long length){
201         implementationMissing(false);
202     }
203 }