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.collection.ByteBuffer;
15 
16 import hunt.Exceptions;
17 import hunt.io.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  * @since 1.4
51  */
52 
53 abstract class MappedByteBuffer : ByteBuffer
54 {
55 
56     // This is a little bit backwards: By rights MappedByteBuffer should be a
57     // subclass of DirectByteBuffer, but to keep the spec clear and simple, and
58     // for optimization purposes, it's easier to do it the other way around.
59     // This works because DirectByteBuffer is a package-private class.
60 
61     // For mapped buffers, a FileDescriptor that may be used for mapping
62     // operations if valid; null if the buffer is not mapped.
63     private FileDescriptor fd;
64 
65     // This should only be invoked by the DirectByteBuffer constructors
66     //
67     this(int mark, int pos, int lim, int cap, // package-private
68                      FileDescriptor fd)
69     {
70         super(mark, pos, lim, cap);
71         this.fd = fd;
72     }
73 
74     this(int mark, int pos, int lim, int cap) { // package-private
75         super(mark, pos, lim, cap);
76         this.fd = null;
77     }
78 
79     private void checkMapped() {
80         if (fd is null)
81             // Can only happen if a luser explicitly casts a direct byte buffer
82             throw new UnsupportedOperationException();
83     }
84 
85     // // Returns the distance (in bytes) of the buffer from the page aligned address
86     // // of the mapping. Computed each time to avoid storing in every direct buffer.
87     // private long mappingOffset() {
88     //     int ps = Bits.pageSize();
89     //     long offset = address % ps;
90     //     return (offset >= 0) ? offset : (ps + offset);
91     // }
92 
93     // private long mappingAddress(long mappingOffset) {
94     //     return address - mappingOffset;
95     // }
96 
97     // private long mappingLength(long mappingOffset) {
98     //     return cast(long)capacity() + mappingOffset;
99     // }
100 
101     // /**
102     //  * Tells whether or not this buffer's content is resident in physical
103     //  * memory.
104     //  *
105     //  * <p> A return value of <tt>true</tt> implies that it is highly likely
106     //  * that all of the data in this buffer is resident in physical memory and
107     //  * may therefore be accessed without incurring any virtual-memory page
108     //  * faults or I/O operations.  A return value of <tt>false</tt> does not
109     //  * necessarily imply that the buffer's content is not resident in physical
110     //  * memory.
111     //  *
112     //  * <p> The returned value is a hint, rather than a guarantee, because the
113     //  * underlying operating system may have paged out some of the buffer's data
114     //  * by the time that an invocation of this method returns.  </p>
115     //  *
116     //  * @return  <tt>true</tt> if it is likely that this buffer's content
117     //  *          is resident in physical memory
118     //  */
119     // final bool isLoaded() {
120     //     checkMapped();
121     //     if ((address == 0) || (capacity() == 0))
122     //         return true;
123     //     long offset = mappingOffset();
124     //     long length = mappingLength(offset);
125     //     return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length));
126     // }
127 
128     // // not used, but a potential target for a store, see load() for details.
129     // private static byte unused;
130 
131     // /**
132     //  * Loads this buffer's content into physical memory.
133     //  *
134     //  * <p> This method makes a best effort to ensure that, when it returns,
135     //  * this buffer's content is resident in physical memory.  Invoking this
136     //  * method may cause some number of page faults and I/O operations to
137     //  * occur. </p>
138     //  *
139     //  * @return  This buffer
140     //  */
141     // final MappedByteBuffer load() {
142     //     checkMapped();
143     //     if ((address == 0) || (capacity() == 0))
144     //         return this;
145     //     long offset = mappingOffset();
146     //     long length = mappingLength(offset);
147     //     load0(mappingAddress(offset), length);
148 
149     //     // Read a byte from each page to bring it into memory. A checksum
150     //     // is computed as we go along to prevent the compiler from otherwise
151     //     // considering the loop as dead code.
152     //     Unsafe unsafe = Unsafe.getUnsafe();
153     //     int ps = Bits.pageSize();
154     //     int count = Bits.pageCount(length);
155     //     long a = mappingAddress(offset);
156     //     byte x = 0;
157     //     for (int i=0; i<count; i++) {
158     //         x ^= unsafe.getByte(a);
159     //         a += ps;
160     //     }
161     //     if (unused != 0)
162     //         unused = x;
163 
164     //     return this;
165     // }
166 
167     // /**
168     //  * Forces any changes made to this buffer's content to be written to the
169     //  * storage device containing the mapped file.
170     //  *
171     //  * <p> If the file mapped into this buffer resides on a local storage
172     //  * device then when this method returns it is guaranteed that all changes
173     //  * made to the buffer since it was created, or since this method was last
174     //  * invoked, will have been written to that device.
175     //  *
176     //  * <p> If the file does not reside on a local device then no such guarantee
177     //  * is made.
178     //  *
179     //  * <p> If this buffer was not mapped in read/write mode ({@link
180     //  * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this
181     //  * method has no effect. </p>
182     //  *
183     //  * @return  This buffer
184     //  */
185     // final MappedByteBuffer force() {
186     //     checkMapped();
187     //     if ((address != 0) && (capacity() != 0)) {
188     //         long offset = mappingOffset();
189     //         force0(fd, mappingAddress(offset), mappingLength(offset));
190     //     }
191     //     return this;
192     // }
193 
194     private bool isLoaded0(long address, long length, int pageCount) {
195         implementationMissing(false);
196         return false;
197     }
198     private void load0(long address, long length) {
199         implementationMissing(false);
200     }
201     private void force0(FileDescriptor fd, long address, long length){
202         implementationMissing(false);
203     }
204 }