-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRAID.cpp
More file actions
122 lines (94 loc) · 3.15 KB
/
RAID.cpp
File metadata and controls
122 lines (94 loc) · 3.15 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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "RAID.h"
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <filesystem>
using namespace std;
namespace fs = filesystem;
RAID::RAID(StripeMap& stripeMap, DMAController& dmaController)
// because we pass by reference, we need to initialize them with a value
:map(stripeMap), dma(dmaController)
{
}
void RAID::disassemble(string inputFilePath) {
cout << "Opening: " << inputFilePath << endl;
if (!fs::exists(inputFilePath)) {
cerr << "Error | file not found: " << inputFilePath << endl;
return;
}
size_t fileSize = fs::file_size(inputFilePath);
ifstream file(inputFilePath, ios::binary);
if (!file) {
cerr << "Error in RAID: Could not open input file: " << inputFilePath << endl;
return;
}
map.buildMap(fileSize);
size_t chunkSize = map.getChunkSize();
vector<char> buffer(chunkSize);
size_t chunkIdx = 0;
/*
* We want to read the file at <chunkSize> bytes at a time
* and push this data into the initial buffer (fixed size)
*
* then create a deep copy of this data loaded into bufferB
* which is made to fit the data exactly
* (the one to pass into the DMA for writing)
*
*/
while (file) {
file.read(buffer.data(), chunkSize);
size_t bytesRead = file.gcount();
if (bytesRead == 0) {
break; // EOF
}
// not using buffer.end() because file chunk won't always fully fill buffer
// => adds garbage memory
vector<char> bufferB(buffer.begin(), buffer.begin() + bytesRead);
string fileName = fs::path(inputFilePath).filename().string();
int diskId = map.fetchDiskId(chunkIdx);
string diskPath = map.fetchDiskPath(diskId);
// use the fileName as the chunk's unique identifier so we can easily delete later on
string finalPath = diskPath + fileName + ".chunk" + to_string(chunkIdx);
// don't need to copy bufferB again since we aren't using it in this thread anymore
dma.scheduleWrite(finalPath, move(bufferB));
chunkIdx++;
}
}
void RAID::reassemble(string fileName, string outputFilePath, size_t originalFileSize) {
// our output file to 'assemble' all the data into (reconstructing it)
ofstream file(outputFilePath, ios::binary);
if (!file) {
cerr << "Error in RAID: Could not create output file: " << outputFilePath << endl;
return;
}
map.buildMap(originalFileSize);
size_t chunkSize = map.getChunkSize();
size_t totalChunks = (originalFileSize + chunkSize - 1) / chunkSize;
for (size_t i = 0; i < totalChunks; i++) {
int diskId = map.fetchDiskId(i);
string diskPath = map.fetchDiskPath(diskId);
string chunkPath = diskPath + fileName + ".chunk" + to_string(i);
ifstream chunkedFile(chunkPath, ios::binary);
if (chunkedFile) {
size_t fragmentSize = fs::file_size(chunkPath);
// use this buffer to help assemble the file
vector<char> buffer(fragmentSize);
chunkedFile.read(buffer.data(), fragmentSize);
file.write(buffer.data(), fragmentSize);
chunkedFile.close();
}
else {
/*
* in case of missing preceeding chunks
*
* fill the chunk with 0s so the file isn't
* corrupted, that way it still keeps the file
* structure
*/
vector<char> fill(chunkSize, 0);
file.write(fill.data(), chunkSize);
}
}
cout << "Done" << endl;
}