-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFileWriter.java
More file actions
89 lines (72 loc) · 3.17 KB
/
Copy pathFileWriter.java
File metadata and controls
89 lines (72 loc) · 3.17 KB
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.Semaphore;
/**
* This class takes chunks from the queue, writes them to disk and updates the file's metadata.
*
* NOTE: make sure that the file interface you choose writes every update to the file's content or metadata
* synchronously to the underlying storage device.
*/
public class FileWriter implements Callable<Void> {
private final BlockingQueue<Chunk> chunkQueue;
private DownloadableMetadata downloadableMetadata;
private Semaphore numChunks;
private RandomAccessFile data;
FileWriter(DownloadableMetadata downloadableMetadata, BlockingQueue<Chunk> chunkQueue, Semaphore numChunks) {
this.chunkQueue = chunkQueue;
this.downloadableMetadata = downloadableMetadata;
this.numChunks = numChunks;
this.data = null;
}
private void writeChunks() throws InterruptedException, IOException {
// get access to the data file
data = new RandomAccessFile(downloadableMetadata.getFilename(), "rwd");
// setting up our variables for the writing loop
Chunk chunk;
int percent = (int)(((double)downloadableMetadata.numRanges() - (double)downloadableMetadata.getNumRangesLeft())*100
/ (double)downloadableMetadata.numRanges());;
System.err.println("Downloaded " + percent + "%");
// While metadata object indicates that I'm still downloading....
while(downloadableMetadata.getNumRangesLeft() != 0) {
// writes to file
numChunks.acquire();
chunk = chunkQueue.take();
data.seek(chunk.getOffset());
data.write(chunk.getData(), 0, chunk.getSize_in_bytes());
// update the metadata file when we completed a range
if(chunk.getStamp()) {
// remove the range from the rangeList
downloadableMetadata.removeFromRanges(chunk.getRange());
// copy the rangeList into a temporary file
downloadableMetadata.writeMissingRanges("temp." + downloadableMetadata.getMetadataFileName());
// move the temp file to be the proper metadata file
// atomically
Path metadatafile = Paths.get(downloadableMetadata.getMetadataFileName());
Path tempfile = Paths.get("temp." + downloadableMetadata.getMetadataFileName());
try {
Files.move(tempfile, metadatafile, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
System.err.println("Couldn't update metadata file.");
System.exit(1);
}
percent = (int)(((double)downloadableMetadata.numRanges() - (double)downloadableMetadata.getNumRangesLeft())*100 / (double)downloadableMetadata.numRanges());
System.err.println("Downloaded " + percent + "%");
}
}
}
@Override
public Void call() throws IOException, InterruptedException {
try {
this.writeChunks();
} catch (InterruptedException e) {
// exit gracefully from the program
}
return null;
}
}