public void Read(BinaryReader msg) { From = msg.ReadIPEndPoint(); if (msg.ReadBoolean()) { var entry = new LogEntry(); var index = new LogIndex(); index.Term = msg.ReadUInt32(); index.Type = (LogIndexType)msg.ReadUInt32(); index.ChunkOffset = msg.ReadUInt32(); index.ChunkSize = msg.ReadUInt32(); index.Flag1 = msg.ReadUInt32(); index.Flag2 = msg.ReadUInt32(); index.Flag3 = msg.ReadUInt32(); index.Flag4 = msg.ReadUInt32(); entry.Index = index; var dataLength = msg.ReadInt32(); entry.Data = msg.ReadBytes(dataLength); Entry = entry; } else { Entry = null; } }
public static bool AreEqual(LogEntry left, LogEntry right) { if (LogIndex.AreEqual(left.Index, right.Index)) { if (left.Data == null && right.Data == null) return true; if (left.Data != null && right.Data == null) return false; if (left.Data == null && right.Data != null) return false; if (left.Data.Length != right.Data.Length) return false; for (var i = 0; i < left.Data.Length; i++) if (left.Data[i] != right.Data[i]) return false; return true; } return false; }
public void Read(BinaryReader msg) { From = msg.ReadIPEndPoint(); AgentIP = msg.ReadIPEndPoint(); Term = msg.ReadUInt32(); PrevTerm = msg.ReadUInt32(); PrevIndex = msg.ReadUInt32(); CommitIndex = msg.ReadUInt32(); var length = msg.ReadInt32(); if (length > 0) { Entries = new LogEntry[length]; for (var i = 0; i < length; i++) { var entry = new LogEntry(); var index = new LogIndex(); index.Term = msg.ReadUInt32(); index.Type = (LogIndexType)msg.ReadUInt32(); index.ChunkOffset = msg.ReadUInt32(); index.ChunkSize = msg.ReadUInt32(); index.Flag1 = msg.ReadUInt32(); index.Flag2 = msg.ReadUInt32(); index.Flag3 = msg.ReadUInt32(); index.Flag4 = msg.ReadUInt32(); entry.Index = index; var dataLength = msg.ReadInt32(); entry.Data = msg.ReadBytes(dataLength); Entries[i] = entry; } } }
public LogEntry[] GetEntries(uint start, uint end) { if (start < 0 || end < 1 || start == end) return null; var entries = new LogEntry[end - start]; for (var i = start; i < end; i++) { var entry = GetEntry(i + 1); System.Diagnostics.Debug.Assert(entry.HasValue); entries[i - start] = entry.Value; } return entries; }
//public bool WriteChunk(Server server, byte[] ) public bool Push(Server server, LogEntry data) { //we couldn't take this entry because we are still waiting for another //to finish if (_configLocked) { return false; } //if (data.Data == null && data.Index.ChunkSize > 0) //{ // Console.WriteLine("{0}: Data length is 0 and data chunksize is {1}", server.Name, data.Index.ChunkSize); // return false; //} //if (data.Data != null && data.Data.Length != data.Index.ChunkSize) //{ // Console.WriteLine("{0}: Data length is {1} and data chunksize is {2}", server.Name, data.Data.Length, data.Index.ChunkSize); // return false; //} // we must first write the data to the dat file // in case of crash in between log data and log entry // this will orphan the data and on startup will reclaim the space // stream length is in UNSIGN but seek is SIGN? // seek before we commit the data so we are at the right position _logIndexWriter.Seek((int)(SUPER_BLOCK_SIZE + _logLength * LogIndex.LOG_RECORD_SIZE), SeekOrigin.Begin); // make sure we have enough capacity ensureLogIndices(_logLength + 1); //write to log data file _logDataFile.Seek(DataPosition, SeekOrigin.Begin); _logDataFile.Write(data.Data, 0, (int)data.Index.ChunkSize); //update log entries _logIndices[_logLength] = data.Index; //flush data _logDataFile.Flush(); //write data _logIndexWriter.Write(data.Index.Term); _logIndexWriter.Write((uint)data.Index.Type); _logIndexWriter.Write(data.Index.ChunkOffset); _logIndexWriter.Write(data.Index.ChunkSize); _logIndexWriter.Write(data.Index.Flag1); _logIndexWriter.Write(data.Index.Flag2); _logIndexWriter.Write(data.Index.Flag3); _logIndexWriter.Write(data.Index.Flag4); _logIndexWriter.Flush(); //inc log index _logLength++; //add server before commit if (data.Index.Type == LogIndexType.AddServer) { var id = GetIPEndPoint(data.Data); if (!server.ID.Equals(id)) server.AddClientFromLog(id); //System.Diagnostics.Debug.Assert(_configLocked == false); Console.WriteLine("{0}: Adding server {1} and locking config", server.Name, id); _configLocked = true; saveSuperBlock(); } else if (data.Index.Type == LogIndexType.RemoveServer) { var id = GetIPEndPoint(data.Data); if (!server.ID.Equals(id)) server.RemoveClientFromLog(id); //System.Diagnostics.Debug.Assert(_configLocked == false); Console.WriteLine("{0}: Removing server {1} and locking config", server.Name, id); _configLocked = true; saveSuperBlock(); } //this can happen on log rollbacks //System.Diagnostics.Debug.Assert(_logDataFile.Length == DataPosition); return true; }
public uint CreateData(Server server, byte[] data) { //this function breaks the entries in to MAX_LOG_ENTRY_SIZE as //DataChunk types but preserves the first byte so that when //it creates the DataBlob entry to spans the entire chunk range //this helps AppendEntries send data in chunks instead of blobs //once the LogEntry return from here is committed, the DataBlob is //safe and linear in entries via DataChunks var start = DataPosition; var remaining = data.Length; while (remaining > MAX_LOG_ENTRY_SIZE) { Array.Copy(data, data.Length - remaining, _writeSpad, 0, MAX_LOG_ENTRY_SIZE); var chunkEntry = new LogEntry() { Index = new LogIndex() { Term = _currentTerm, ChunkOffset = DataPosition, ChunkSize = MAX_LOG_ENTRY_SIZE, Type = LogIndexType.DataChunk, Flag3 = start, Flag4 = (uint)data.Length }, Data = _writeSpad }; //if (server != null) // Console.WriteLine("{0}: Creating chunk {1}", server.ID, chunkEntry.Index); Push(server, chunkEntry); remaining -= MAX_LOG_ENTRY_SIZE; } Array.Copy(data, data.Length - remaining, _writeSpad, 0, remaining); var entry = new LogEntry() { Index = new LogIndex() { Term = _currentTerm, ChunkOffset = DataPosition, ChunkSize = (uint)remaining, Type = LogIndexType.DataBlob, Flag3 = start, Flag4 = (uint)data.Length }, Data = _writeSpad }; //if (server != null) // Console.WriteLine("{0}: Created {1}", server.ID, entry.Index); Push(server, entry); return _logLength; }
public uint CreateNoop(Server server) { var entry = new LogEntry() { Index = new LogIndex() { Term = _currentTerm, ChunkOffset = DataPosition, ChunkSize = 0, Type = LogIndexType.NOOP }, Data = new byte[0] }; if (server != null) Console.WriteLine("{0}: Created NOOP", server.Name); Push(server, entry); return _logLength; }
public LogEntry RemoveServer(Server server, IPEndPoint id) { var data = id.Address.GetAddressBytes(); Array.Resize(ref data, data.Length + 4); data[data.Length - 4] = (byte)(id.Port >> 24); data[data.Length - 3] = (byte)(id.Port >> 16); data[data.Length - 2] = (byte)(id.Port >> 8); data[data.Length - 1] = (byte)(id.Port); var entry = new LogEntry() { Index = new LogIndex() { Term = _currentTerm, ChunkOffset = DataPosition, ChunkSize = (uint)data.Length, Type = LogIndexType.RemoveServer }, Data = data }; Push(server, entry); return entry; }