Пример #1
0
        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;
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        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;
                }
            }
        }
Пример #4
0
        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;
        }
Пример #5
0
        //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;
        }
Пример #6
0
        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;
        }
Пример #7
0
        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;
        }
Пример #8
0
        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;
        }