1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.internal.storage.dfs;
45
46 import java.io.EOFException;
47 import java.io.IOException;
48 import java.nio.ByteBuffer;
49 import java.text.MessageFormat;
50
51 import org.eclipse.jgit.errors.PackInvalidException;
52 import org.eclipse.jgit.internal.storage.pack.PackExt;
53
54
55 abstract class BlockBasedFile {
56
57 final DfsBlockCache cache;
58
59
60 final DfsStreamKey key;
61
62
63 final DfsPackDescription desc;
64 final PackExt ext;
65
66
67
68
69
70
71
72
73
74 volatile int blockSize;
75
76
77
78
79
80
81 volatile long length;
82
83
84 volatile boolean invalid;
85
86
87 protected volatile Exception invalidatingCause;
88
89 BlockBasedFile(DfsBlockCache cache, DfsPackDescription desc, PackExt ext) {
90 this.cache = cache;
91 this.key = desc.getStreamKey(ext);
92 this.desc = desc;
93 this.ext = ext;
94 }
95
96 String getFileName() {
97 return desc.getFileName(ext);
98 }
99
100 boolean invalid() {
101 return invalid;
102 }
103
104 void setInvalid() {
105 invalid = true;
106 }
107
108 void setBlockSize(int newSize) {
109 blockSize = newSize;
110 }
111
112 long alignToBlock(long pos) {
113 int size = blockSize;
114 if (size == 0)
115 size = cache.getBlockSize();
116 return (pos / size) * size;
117 }
118
119 int blockSize(ReadableChannel rc) {
120
121
122 int size = blockSize;
123 if (size == 0) {
124 size = rc.blockSize();
125 if (size <= 0)
126 size = cache.getBlockSize();
127 else if (size < cache.getBlockSize())
128 size = (cache.getBlockSize() / size) * size;
129 blockSize = size;
130 }
131 return size;
132 }
133
134 DfsBlock getOrLoadBlock(long pos, DfsReader ctx) throws IOException {
135 try (LazyChannel c = new LazyChannel(ctx, desc, ext)) {
136 return cache.getOrLoad(this, pos, ctx, c);
137 }
138 }
139
140 DfsBlock readOneBlock(long pos, DfsReader ctx, ReadableChannel rc)
141 throws IOException {
142 if (invalid) {
143 throw new PackInvalidException(getFileName(), invalidatingCause);
144 }
145
146 ctx.stats.readBlock++;
147 long start = System.nanoTime();
148 try {
149 int size = blockSize(rc);
150 pos = (pos / size) * size;
151
152
153
154
155
156 long len = length;
157 if (len < 0) {
158 len = rc.size();
159 if (0 <= len)
160 length = len;
161 }
162
163 if (0 <= len && len < pos + size)
164 size = (int) (len - pos);
165 if (size <= 0)
166 throw new EOFException(MessageFormat.format(
167 DfsText.get().shortReadOfBlock, Long.valueOf(pos),
168 getFileName(), Long.valueOf(0), Long.valueOf(0)));
169
170 byte[] buf = new byte[size];
171 rc.position(pos);
172 int cnt = read(rc, ByteBuffer.wrap(buf, 0, size));
173 ctx.stats.readBlockBytes += cnt;
174 if (cnt != size) {
175 if (0 <= len) {
176 throw new EOFException(MessageFormat.format(
177 DfsText.get().shortReadOfBlock, Long.valueOf(pos),
178 getFileName(), Integer.valueOf(size),
179 Integer.valueOf(cnt)));
180 }
181
182
183
184 byte[] n = new byte[cnt];
185 System.arraycopy(buf, 0, n, 0, n.length);
186 buf = n;
187 } else if (len < 0) {
188
189
190 length = len = rc.size();
191 }
192
193 return new DfsBlock(key, pos, buf);
194 } finally {
195 ctx.stats.readBlockMicros += elapsedMicros(start);
196 }
197 }
198
199 static int read(ReadableChannel rc, ByteBuffer buf) throws IOException {
200 int n;
201 do {
202 n = rc.read(buf);
203 } while (0 < n && buf.hasRemaining());
204 return buf.position();
205 }
206
207 static long elapsedMicros(long start) {
208 return (System.nanoTime() - start) / 1000L;
209 }
210
211
212
213
214 private static class LazyChannel
215 implements AutoCloseable, DfsBlockCache.ReadableChannelSupplier {
216 private final DfsReader ctx;
217 private final DfsPackDescription desc;
218 private final PackExt ext;
219
220 private ReadableChannel rc;
221
222 LazyChannel(DfsReader ctx, DfsPackDescription desc, PackExt ext) {
223 this.ctx = ctx;
224 this.desc = desc;
225 this.ext = ext;
226 }
227
228 @Override
229 public ReadableChannel get() throws IOException {
230 if (rc == null) {
231 rc = ctx.db.openFile(desc, ext);
232 }
233 return rc;
234 }
235
236 @Override
237 public void close() throws IOException {
238 if (rc != null) {
239 rc.close();
240 }
241 }
242 }
243 }