5 virtual void Mutate(SegmentMap *table,
6 const SegmentMap *source_table,
7 MTRandom *rand) const = 0;
13 MODIFY = 1, // Mutate a certain range w/ random or supplied data
14 ADD = 2, // Insert random or supplied data
15 DELETE = 3, // Delete a specified range of data
16 COPY = 4, // Copy from one region, inserting elsewhere
17 MOVE = 5, // Copy then delete copied-from range
18 COPYOVER = 6 // Copy then delete copied-to range
20 // ADD, DELETE, and COPY change the file size
21 // MODIFY, MOVE, COPYOVER preserve the file size
24 // Constructor for modify, add, delete.
25 Change(Kind kind0, xoff_t size0, xoff_t addr1_0)
31 CHECK(kind != MOVE && kind != COPY && kind != COPYOVER);
34 // Constructor for modify, add w/ provided data.
35 Change(Kind kind0, xoff_t size0, xoff_t addr1_0, Segment *insert0)
41 CHECK(kind != MOVE && kind != COPY && kind != COPYOVER);
44 // Constructor for move, copy, overwrite
45 Change(Kind kind0, xoff_t size0, xoff_t addr1_0, xoff_t addr2_0)
51 CHECK(kind == MOVE || kind == COPY || kind == COPYOVER);
58 Segment *insert; // For modify and/or add
61 typedef list<Change> ChangeList;
62 typedef typename ChangeList::const_iterator ConstChangeListIterator;
63 typedef typename ChangeList::iterator ChangeListIterator;
65 class ChangeListMutator : public Mutator {
67 ChangeListMutator(const ChangeList &cl)
70 ChangeListMutator() { }
72 void Mutate(SegmentMap *table,
73 const SegmentMap *source_table,
74 MTRandom *rand) const {
75 // The speed of processing gigabytes of data is so slow compared with
76 // these table-copy operations, no attempt to make this fast.
79 for (ConstChangeListIterator iter(cl_.begin());
80 iter != cl_.end(); ++iter) {
81 const Change &ch = *iter;
83 Mutate(ch, &tmp, source_table, rand);
89 static void Mutate(const Change &ch,
91 const SegmentMap *source_table,
95 AddChange(ch, table, source_table, rand);
98 ModifyChange(ch, table, source_table, rand);
101 DeleteChange(ch, table, source_table, rand);
104 CopyChange(ch, table, source_table, rand);
107 MoveChange(ch, table, source_table, rand);
109 case Change::COPYOVER:
110 OverwriteChange(ch, table, source_table, rand);
115 static void ModifyChange(const Change &ch,
117 const SegmentMap *source_table,
119 xoff_t m_start = ch.addr1;
120 xoff_t m_end = m_start + ch.size;
124 for (ConstSegmentMapIterator iter(source_table->begin());
125 iter != source_table->end();
127 const Segment &seg = iter->second;
128 i_start = iter->first;
129 i_end = i_start + seg.Size();
131 if (i_end <= m_start || i_start >= m_end) {
132 table->insert(table->end(), make_pair(i_start, seg));
136 if (i_start < m_start) {
137 table->insert(table->end(),
139 seg.Subseg(0, m_start - i_start)));
142 // Insert the entire segment, even though it may extend into later
143 // segments. This condition avoids inserting it during later
145 if (m_start >= i_start) {
146 if (ch.insert != NULL) {
147 table->insert(table->end(), make_pair(m_start, *ch.insert));
149 Segment part(m_end - m_start, rand);
150 table->insert(table->end(), make_pair(m_start, part));
155 table->insert(table->end(),
157 seg.Subseg(m_end - i_start, i_end - m_end)));
161 // This check verifies that the modify does not extend past the
163 CHECK_LE(m_end, i_end);
166 static void AddChange(const Change &ch,
168 const SegmentMap *source_table,
170 xoff_t m_start = ch.addr1;
174 for (ConstSegmentMapIterator iter(source_table->begin());
175 iter != source_table->end();
177 const Segment &seg = iter->second;
178 i_start = iter->first;
179 i_end = i_start + seg.Size();
181 if (i_end <= m_start) {
182 table->insert(table->end(), make_pair(i_start, seg));
186 if (i_start > m_start) {
187 table->insert(table->end(), make_pair(i_start + ch.size, seg));
191 if (i_start < m_start) {
192 table->insert(table->end(),
194 seg.Subseg(0, m_start - i_start)));
197 if (ch.insert != NULL) {
198 table->insert(table->end(), make_pair(m_start, *ch.insert));
200 Segment addseg(ch.size, rand);
201 table->insert(table->end(), make_pair(m_start, addseg));
204 if (m_start < i_end) {
205 table->insert(table->end(),
206 make_pair(m_start + ch.size,
207 seg.Subseg(m_start - i_start,
212 CHECK_LE(m_start, i_end);
214 // Special case for add at end-of-input.
215 if (m_start == i_end) {
216 Segment addseg(ch.size, rand);
217 table->insert(table->end(), make_pair(m_start, addseg));
221 static void DeleteChange(const Change &ch,
223 const SegmentMap *source_table,
225 xoff_t m_start = ch.addr1;
226 xoff_t m_end = m_start + ch.size;
230 for (ConstSegmentMapIterator iter(source_table->begin());
231 iter != source_table->end();
233 const Segment &seg = iter->second;
234 i_start = iter->first;
235 i_end = i_start + seg.Size();
237 if (i_end <= m_start) {
238 table->insert(table->end(), make_pair(i_start, seg));
242 if (i_start >= m_end) {
243 table->insert(table->end(), make_pair(i_start - ch.size, seg));
247 if (i_start < m_start) {
248 table->insert(table->end(),
250 seg.Subseg(0, m_start - i_start)));
254 table->insert(table->end(),
255 make_pair(m_end - ch.size,
256 seg.Subseg(m_end - i_start, i_end - m_end)));
260 CHECK_LT(m_start, i_end);
261 CHECK_LE(m_end, i_end);
264 // A move is a copy followed by delete of the copied-from range.
265 static void MoveChange(const Change &ch,
267 const SegmentMap *source_table,
270 CHECK_NE(ch.addr1, ch.addr2);
271 CopyChange(ch, &tmp, source_table, rand);
272 Change d(Change::DELETE, ch.size,
273 ch.addr1 < ch.addr2 ? ch.addr1 : ch.addr1 + ch.size);
274 DeleteChange(d, table, &tmp, rand);
277 // An overwrite is a copy followed by a delete of the copied-to range.
278 static void OverwriteChange(const Change &ch,
280 const SegmentMap *source_table,
283 CHECK_NE(ch.addr1, ch.addr2);
284 CopyChange(ch, &tmp, source_table, rand);
285 Change d(Change::DELETE, ch.size, ch.addr2 + ch.size);
286 DeleteChange(d, table, &tmp, rand);
289 static void CopyChange(const Change &ch,
291 const SegmentMap *source_table,
293 xoff_t m_start = ch.addr2;
294 xoff_t c_start = ch.addr1;
298 // Like AddChange() with AppendCopy instead of a random segment.
299 for (ConstSegmentMapIterator iter(source_table->begin());
300 iter != source_table->end();
302 const Segment &seg = iter->second;
303 i_start = iter->first;
304 i_end = i_start + seg.Size();
306 if (i_end <= m_start) {
307 table->insert(table->end(), make_pair(i_start, seg));
311 if (i_start > m_start) {
312 table->insert(table->end(), make_pair(i_start + ch.size, seg));
316 if (i_start < m_start) {
317 table->insert(table->end(),
319 seg.Subseg(0, m_start - i_start)));
322 AppendCopy(table, source_table, c_start, m_start, ch.size);
324 if (m_start < i_end) {
325 table->insert(table->end(),
326 make_pair(m_start + ch.size,
327 seg.Subseg(m_start - i_start, i_end - m_start)));
331 CHECK_LE(m_start, i_end);
333 // Special case for copy to end-of-input.
334 if (m_start == i_end) {
335 AppendCopy(table, source_table, c_start, m_start, ch.size);
339 static void AppendCopy(SegmentMap *table,
340 const SegmentMap *source_table,
342 xoff_t append_offset,
344 ConstSegmentMapIterator pos(source_table->upper_bound(copy_offset));
348 while (got < length) {
349 size_t seg_offset = copy_offset - pos->first;
350 size_t advance = min(pos->second.Size() - seg_offset,
351 (size_t)(length - got));
353 table->insert(table->end(),
354 make_pair(append_offset,
355 pos->second.Subseg(seg_offset,
359 copy_offset += advance;
360 append_offset += advance;
365 ChangeList* Changes() {
369 const ChangeList* Changes() const {
377 class Modify1stByte : public Mutator {
379 void Mutate(SegmentMap *table,
380 const SegmentMap *source_table,
381 MTRandom *rand) const {
382 ChangeListMutator::Mutate(Change(Change::MODIFY, 1, 0),
383 table, source_table, rand);