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