|
1 | | -package io.delta.core.internal; |
| 1 | +package io.delta.core.internal.snapshot; |
2 | 2 |
|
3 | 3 | import java.io.FileNotFoundException; |
4 | 4 | import java.util.*; |
5 | 5 | import java.util.stream.Collectors; |
6 | 6 |
|
7 | 7 | import io.delta.core.Snapshot; |
8 | 8 | import io.delta.core.fs.FileStatus; |
| 9 | +import io.delta.core.internal.LogSegment; |
| 10 | +import io.delta.core.internal.TableImpl; |
9 | 11 | import io.delta.core.internal.checkpoint.CheckpointInstance; |
10 | 12 | import io.delta.core.internal.checkpoint.CheckpointMetaData; |
11 | 13 | import io.delta.core.internal.checkpoint.Checkpointer; |
| 14 | +import io.delta.core.internal.checksum.VersionChecksum; |
12 | 15 | import io.delta.core.internal.lang.ListUtils; |
13 | 16 | import io.delta.core.internal.lang.Tuple2; |
14 | 17 | import io.delta.core.internal.util.FileNames; |
| 18 | +import io.delta.core.internal.util.Logging; |
15 | 19 | import io.delta.core.utils.CloseableIterator; |
16 | 20 |
|
17 | | -public class SnapshotManager { |
| 21 | +public class SnapshotManager implements Logging { |
18 | 22 |
|
19 | | - //////////////////// |
20 | | - // Static Methods // |
21 | | - //////////////////// |
| 23 | + ///////////////////////////// |
| 24 | + // Static Fields / Methods // |
| 25 | + ///////////////////////////// |
22 | 26 |
|
23 | 27 | /** |
24 | 28 | * - Verify the versions are contiguous. |
@@ -62,7 +66,8 @@ public SnapshotManager(TableImpl tableImpl) { |
62 | 66 | * Update current snapshot by applying the new delta files if any. |
63 | 67 | */ |
64 | 68 | public Snapshot update() { |
65 | | - |
| 69 | + // TODO |
| 70 | + return null; |
66 | 71 | } |
67 | 72 |
|
68 | 73 | ////////////////// |
@@ -154,11 +159,35 @@ protected final Optional<List<FileStatus>> listDeltaAndCheckpointFiles( |
154 | 159 | * `lastCheckpoint` file as a hint on where to start listing the transaction log directory. If |
155 | 160 | * the _delta_log directory doesn't exist, this method will return an `InitialSnapshot`. |
156 | 161 | */ |
157 | | - private Snapshot getSnapshotAtInit() { |
| 162 | + private SnapshotImpl getSnapshotAtInit() { |
158 | 163 | final long currentTimestamp = System.currentTimeMillis(); |
159 | 164 | final Optional<CheckpointMetaData> lastCheckpointOpt = |
160 | 165 | tableImpl.checkpointer.readLastCheckpointFile(); |
161 | | - getLogSegmentFrom(lastCheckpointOpt); |
| 166 | + final Optional<LogSegment> logSegmentOpt = getLogSegmentFrom(lastCheckpointOpt); |
| 167 | + return logSegmentOpt |
| 168 | + .map(logSegment -> createSnapshot(logSegment, lastCheckpointOpt, Optional.empty())) |
| 169 | + .orElse(new InitialSnapshot()); |
| 170 | + } |
| 171 | + |
| 172 | + private SnapshotImpl createSnapshot( |
| 173 | + LogSegment initSegment, |
| 174 | + Optional<CheckpointMetaData> checkpointMetadataOptHint, |
| 175 | + Optional<VersionChecksum> checksumOpt) { |
| 176 | + final String startingFromStr = initSegment |
| 177 | + .checkpointVersionOpt |
| 178 | + .map(v -> String.format(" starting from checkpoint version %s.", v)) |
| 179 | + .orElse("."); |
| 180 | + logInfo(() -> String.format("Loading version %s%s", initSegment.version, startingFromStr)); |
| 181 | + |
| 182 | + // TODO(SCOTT): createSnapshotFromGivenOrEquivalentLogSegment |
| 183 | + |
| 184 | + return new SnapshotImpl( |
| 185 | + tableImpl.logPath, |
| 186 | + initSegment.version, |
| 187 | + initSegment, |
| 188 | + tableImpl, |
| 189 | + initSegment.lastCommitTimestamp |
| 190 | + ); |
162 | 191 | } |
163 | 192 |
|
164 | 193 | /** |
@@ -301,20 +330,52 @@ private Optional<LogSegment> getLogSegmentForVersion( |
301 | 330 | verifyDeltaVersions(deltaVersions, Optional.of(newCheckpointVersion + 1), versionToLoadOpt); |
302 | 331 | } |
303 | 332 |
|
| 333 | + // TODO(SCOTT): double check newCheckpointOpt.get() won't error out |
| 334 | + |
304 | 335 | final long newVersion = deltaVersions.isEmpty() ? newCheckpointOpt.get().version : deltaVersions.getLast(); |
305 | | - final List<FileStatus> newCheckpointFiles |
306 | | - |
307 | | - |
308 | | - val newVersion = deltaVersions.lastOption.getOrElse(newCheckpoint.get.version) |
309 | | - val newCheckpointFiles: Seq[FileStatus] = newCheckpoint.map { newCheckpoint => |
310 | | - val newCheckpointPaths = newCheckpoint.getCorrespondingFiles(logPath).toSet |
311 | | - val newCheckpointFileArray = checkpoints.filter(f => newCheckpointPaths.contains(f.getPath)) |
312 | | - assert(newCheckpointFileArray.length == newCheckpointPaths.size, |
313 | | - "Failed in getting the file information for:\n" + |
314 | | - newCheckpointPaths.mkString(" -", "\n -", "") + "\n" + |
315 | | - "among\n" + checkpoints.map(_.getPath).mkString(" -", "\n -", "")) |
316 | | - newCheckpointFileArray.toSeq |
317 | | - }.getOrElse(Nil) |
| 336 | + |
| 337 | + // In the case where `deltasAfterCheckpoint` is empty, `deltas` should still not be empty, |
| 338 | + // they may just be before the checkpoint version unless we have a bug in log cleanup. |
| 339 | + if (deltas.isEmpty()) { |
| 340 | + throw new IllegalStateException( |
| 341 | + String.format("Could not find any delta files for version %s", newVersion) |
| 342 | + ); |
| 343 | + } |
| 344 | + |
| 345 | + if (versionToLoadOpt.map(v -> v != newVersion).orElse(false)) { |
| 346 | + throw new IllegalStateException( |
| 347 | + String.format("Trying to load a non-existent version %s", versionToLoadOpt.get()) |
| 348 | + ); |
| 349 | + } |
| 350 | + |
| 351 | + final long lastCommitTimestamp = deltas.get(deltas.size() - 1).modificationTime(); |
| 352 | + |
| 353 | + final List<FileStatus> newCheckpointFiles = newCheckpointOpt.map(newCheckpoint -> { |
| 354 | + final Set<String> newCheckpointPaths = |
| 355 | + new HashSet<>(newCheckpoint.getCorrespondingFiles(tableImpl.logPath)); |
| 356 | + final List<FileStatus> newCheckpointFileList = checkpoints |
| 357 | + .stream() |
| 358 | + .filter(f -> newCheckpointPaths.contains(f.path())) |
| 359 | + .collect(Collectors.toList()); |
| 360 | + assert (newCheckpointFileList.size() == newCheckpointPaths.size()) : |
| 361 | + String.format( |
| 362 | + "Filed in getting the file information for:\n%s\namong\n%s", |
| 363 | + String.join("\n -", newCheckpointPaths), |
| 364 | + checkpoints.stream().map(FileStatus::path).collect(Collectors.joining("\n - ")) |
| 365 | + ); |
| 366 | + return newCheckpointFileList; |
| 367 | + }).orElse(Collections.emptyList()); |
| 368 | + |
| 369 | + return Optional.of( |
| 370 | + new LogSegment( |
| 371 | + tableImpl.logPath, |
| 372 | + newVersion, |
| 373 | + deltasAfterCheckpoint, |
| 374 | + newCheckpointFiles, |
| 375 | + newCheckpointOpt.map(x -> x.version), |
| 376 | + lastCommitTimestamp |
| 377 | + ) |
| 378 | + ); |
318 | 379 | } |
319 | 380 |
|
320 | 381 | /** |
|
0 commit comments