1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_recordreplay_File_h
8 #define mozilla_recordreplay_File_h
10 #include "InfallibleVector.h"
11 #include "ProcessRecordReplay.h"
14 #include "mozilla/PodOperations.h"
15 #include "mozilla/RecordReplay.h"
16 #include "mozilla/UniquePtr.h"
19 namespace recordreplay
{
21 // Structure managing file I/O. Each file contains an index for a set of named
22 // streams, whose contents are compressed and interleaved throughout the file.
23 // Additionally, we directly manage the file handle and all associated memory.
24 // This makes it easier to restore memory snapshots without getting confused
25 // about the state of the file handles which the process has opened. Data
26 // written and read from files is automatically compressed with LZ4.
28 // Files are used internally for any disk accesses which the record/replay
29 // infrastructure needs to make. Currently, this is only for accessing the
32 // File is threadsafe for simultaneous read/read and write/write accesses.
33 // Stream is not threadsafe.
35 // A location of a chunk of a stream within a file.
36 struct StreamChunkLocation
{
37 // Offset into the file of the start of the chunk.
40 // Compressed (stored) size of the chunk.
41 uint32_t mCompressedSize
;
43 // Decompressed size of the chunk.
44 uint32_t mDecompressedSize
;
46 // Hash of the compressed chunk data.
49 // Position in the stream of the start of this chunk.
53 enum class StreamName
{ Main
, Lock
, Event
, Count
};
56 class RecordingEventSection
;
60 friend class RecordingEventSection
;
62 // File this stream belongs to.
65 // Prefix name for this stream.
68 // Index which, when combined to mName, uniquely identifies this stream in
72 // When writing, all chunks that have been flushed to disk. When reading, all
73 // chunks in the entire stream.
74 InfallibleVector
<StreamChunkLocation
> mChunks
;
77 UniquePtr
<char[]> mBuffer
;
79 // The maximum number of bytes to buffer before compressing and writing to
80 // disk, and the maximum number of bytes that can be decompressed at once.
81 static const size_t BUFFER_MAX
= 1024 * 1024;
83 // The capacity of mBuffer, at most BUFFER_MAX.
86 // During reading, the number of accessible bytes in mBuffer.
89 // The number of bytes read or written from mBuffer.
92 // The number of uncompressed bytes read or written from the stream.
95 // Any buffer available for use when decompressing or compressing data.
96 UniquePtr
<char[]> mBallast
;
99 // Any buffer available to check for input mismatches.
100 UniquePtr
<char[]> mInputBallast
;
101 size_t mInputBallastSize
;
103 // The last event in this stream, in case of an input mismatch.
104 ThreadEvent mLastEvent
;
106 // The number of chunks that have been completely read or written. When
107 // writing, this equals mChunks.length().
110 // When writing, the number of chunks in this stream when the file was last
112 size_t mFlushedChunks
;
114 // Whether there is a RecordingEventSection instance active for this stream.
115 bool mInRecordingEventSection
;
117 Stream(File
* aFile
, StreamName aName
, size_t aNameIndex
)
120 mNameIndex(aNameIndex
),
128 mInputBallast(nullptr),
129 mInputBallastSize(0),
130 mLastEvent((ThreadEvent
)0),
133 mInRecordingEventSection(false) {}
136 StreamName
Name() const { return mName
; }
137 size_t NameIndex() const { return mNameIndex
; }
139 void ReadBytes(void* aData
, size_t aSize
);
140 void WriteBytes(const void* aData
, size_t aSize
);
142 void WriteScalar(size_t aValue
);
145 inline void RecordOrReplayBytes(void* aData
, size_t aSize
) {
147 WriteBytes(aData
, aSize
);
149 ReadBytes(aData
, aSize
);
153 template <typename T
>
154 inline void RecordOrReplayScalar(T
* aPtr
) {
156 WriteScalar((size_t)*aPtr
);
158 *aPtr
= (T
)ReadScalar();
162 template <typename T
>
163 inline void RecordOrReplayValue(T
* aPtr
) {
164 RecordOrReplayBytes(aPtr
, sizeof(T
));
167 // Note a new thread event for this stream, and make sure it is the same
168 // while replaying as it was while recording.
169 void RecordOrReplayThreadEvent(ThreadEvent aEvent
);
171 // Replay a thread event without requiring it to be a specific event.
172 ThreadEvent
ReplayThreadEvent();
174 // Make sure that a value or buffer is the same while replaying as it was
176 void CheckInput(size_t aValue
);
177 void CheckInput(const char* aValue
);
178 void CheckInput(const void* aData
, size_t aSize
);
180 inline size_t StreamPosition() { return mStreamPos
; }
183 enum ShouldCopy
{ DontCopyExistingData
, CopyExistingData
};
185 void EnsureMemory(UniquePtr
<char[]>* aBuf
, size_t* aSize
, size_t aNeededSize
,
186 size_t aMaxSize
, ShouldCopy aCopy
);
187 void EnsureInputBallast(size_t aSize
);
188 void Flush(bool aTakeLock
);
189 const char* ReadInputString();
191 static size_t BallastMaxSize();
196 enum Mode
{ WRITE
, READ
};
199 friend class RecordingEventSection
;
202 // Open file handle, or 0 if closed.
205 // Whether this file is open for writing or reading.
208 // When writing, the current offset into the file.
209 uint64_t mWriteOffset
;
211 // The offset of the last index read or written to the file.
212 uint64_t mLastIndexOffset
;
214 // All streams in this file, indexed by stream name and name index.
215 typedef InfallibleVector
<UniquePtr
<Stream
>> StreamVector
;
216 StreamVector mStreams
[(size_t)StreamName::Count
];
218 // Lock protecting access to this file.
221 // When writing, lock for synchronizing file flushes (writer) with other
222 // threads writing to streams in this file (readers).
223 ReadWriteSpinLock mStreamLock
;
229 mLastIndexOffset
= 0;
230 for (auto& vector
: mStreams
) {
234 PodZero(&mStreamLock
);
241 bool Open(const char* aName
, Mode aMode
);
244 bool OpenForWriting() const { return mFd
&& mMode
== WRITE
; }
245 bool OpenForReading() const { return mFd
&& mMode
== READ
; }
247 Stream
* OpenStream(StreamName aName
, size_t aNameIndex
);
249 // Prevent/allow other threads to write to streams in this file.
250 void PreventStreamWrites() { mStreamLock
.WriteLock(); }
251 void AllowStreamWrites() { mStreamLock
.WriteUnlock(); }
253 // Flush any changes since the last Flush() call to disk, returning whether
254 // there were such changes.
257 enum class ReadIndexResult
{ InvalidFile
, EndOfFile
, FoundIndex
};
259 // Read any data added to the file by a Flush() call. aUpdatedStreams is
260 // optional and filled in with streams whose contents have changed, and may
262 ReadIndexResult
ReadNextIndex(InfallibleVector
<Stream
*>* aUpdatedStreams
);
265 StreamChunkLocation
WriteChunk(const char* aStart
, size_t aCompressedSize
,
266 size_t aDecompressedSize
, uint64_t aStreamPos
,
268 void ReadChunk(char* aDest
, const StreamChunkLocation
& aChunk
);
271 } // namespace recordreplay
272 } // namespace mozilla
274 #endif // mozilla_recordreplay_File_h