Exemplo n.º 1
0
        /// <summary>
        /// Returns the next non-deleted record from the file, optionally marking it for deletion.
        /// </summary>
        /// <param name="deleteRecord">Pass <c>true</c> to mark the record for deletion.</param>
        /// <returns>The next record or <c>null</c> if there are no more records to be read.</returns>
        /// <exception cref="LogCorruptedException">Thrown when the log file is determined to be corrupted.</exception>
        private AppLogRecord Read(bool deleteRecord)
        {
            int  magic;
            int  cbRecord;
            int  flags;
            int  cFields;
            bool deleted;
            int  nameIndex;
            bool isByteArray;

            byte[]       data;
            int          cbData;
            AppLogRecord record;
            long         flagPos;
            long         nextPos;

            if (!readMode)
            {
                throw new LogAccessException(readMode);
            }

            tryAgain : try
            {
                magic = file.ReadInt16();
                if (magic == AppLog.RecordEnd)
                {
                    // Seek back 2 bytes to keep the file position
                    // at the RecordEnd marker.

                    file.Seek(-2, SeekOrigin.Current);
                    return(null);
                }

                if (magic != AppLog.RecordMagic)
                {
                    throw new LogCorruptedException();
                }

                cbRecord = file.ReadInt32();
                flagPos  = file.Position;
                deleted  = (file.ReadByte() & 0x80) != 0;
                cFields  = file.ReadInt16();

                if (deleted)
                {
                    record = null;
                }
                else
                {
                    record = new AppLogRecord(schemaName, schemaVersion);
                }

                for (int i = 0; i < cFields; i++)
                {
                    flags       = file.ReadByte();
                    isByteArray = (flags & 0x80) != 0;

                    if ((flags & 0x40) != 0)
                    {
                        nameIndex = ((flags & 0x3F) << 8) | file.ReadByte();
                    }
                    else
                    {
                        nameIndex = flags & 0x3F;
                    }

                    if (nameIndex >= id2Field.Length)
                    {
                        throw new LogCorruptedException();
                    }

                    cbData = file.ReadByte();
                    if ((cbData & 0x80) != 0)
                    {
                        // cbData holds the most significant 7-bits of the field
                        // length and the next three bytes hold the least
                        // significant 24-bits.

                        cbData = ((cbData & 0x7F) << 24) | (file.ReadByte() << 16) | (file.ReadByte() << 8) | file.ReadByte();
                    }

                    data = file.ReadBytes(cbData);

                    if (record != null)
                    {
                        if (isByteArray)
                        {
                            record.Add(id2Field[nameIndex], data);
                        }
                        else
                        {
                            record.Add(id2Field[nameIndex], Helper.FromUTF8(data));
                        }
                    }
                }

                if (record != null)
                {
                    if (deleteRecord)
                    {
                        recDeleted    = true;
                        nextPos       = file.Position;
                        file.Position = flagPos;
                        file.WriteByte(0x80);
                        file.Position = nextPos;
                    }

                    if (file.Position != flagPos + cbRecord)
                    {
                        throw new LogCorruptedException();
                    }

                    return(record);
                }
                else
                {
                    goto tryAgain;
                }
            }
            catch
            {
                throw new LogCorruptedException();
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Appends the record to the log file.
        /// </summary>
        /// <param name="record">The record to be appended.</param>
        public void Write(AppLogRecord record)
        {
            long recLenPos;
            long nextPos;

            if (readMode)
            {
                throw new LogAccessException(readMode);
            }

            file.WriteInt16(AppLog.RecordMagic);
            recLenPos = file.Position;
            file.WriteInt32(0);                 // Leave space for the record length
            file.WriteByte(0);                  // Flags = 0
            file.WriteInt16(record.Count);      // Field Count

            foreach (DictionaryEntry entry in record)
            {
                string fieldName = ((string)entry.Key).ToLowerInvariant();
                int    fieldID;
                int    flags;
                byte[] data;
                string s;

                // Map the field name to an ID, adding the field to
                // the map table if necessary

                if (!field2ID.TryGetValue(fieldName, out fieldID))
                {
                    fieldID = field2ID.Count;
                    field2ID.Add(fieldName, fieldID);
                    if (field2ID.Count > MaxFieldNames)
                    {
                        throw new LogException("Too many unique field names.");
                    }
                }

                // Convert strings to UTF-8 byte arrays and set the
                // flag 0x80 bit if the data is a byte array.

                s = entry.Value as string;
                if (s == null)
                {
                    flags = 0x80;
                    data  = (byte[])entry.Value;
                }
                else
                {
                    flags = 0;
                    data  = Helper.ToUTF8(s);
                }

                // Combine the field ID into the flag bits and write the
                // flags out as well as the extended portion of the field
                // name ID (if necessary).

                if (fieldID > 0x3F)
                {
                    flags |= 0x40;
                    flags |= (fieldID >> 8) & 0x3F;
                    file.WriteByte((byte)flags);
                    file.WriteByte((byte)(fieldID & 0xFF));
                }
                else
                {
                    file.WriteByte((byte)(flags | fieldID));
                }

                // Write out the variable length data length field.

                if (data.Length <= 127)
                {
                    file.WriteByte((byte)data.Length);
                }
                else
                {
                    file.WriteByte((byte)(0x80 | (data.Length >> 24)));
                    file.WriteByte((byte)(data.Length >> 16));
                    file.WriteByte((byte)(data.Length >> 8));
                    file.WriteByte((byte)(data.Length));
                }

                // Write out the value bytes

                file.WriteBytesNoLen(data);

                // Compute the overall length of the record and
                // go back and write it after the magic number.

                nextPos       = file.Position;
                file.Position = recLenPos;
                file.WriteInt32((int)(nextPos - recLenPos - 4));
                file.Position = nextPos;
            }

            cRecWritten++;
        }
Exemplo n.º 3
0
 /// <summary>
 /// Appends a record to the cached section of the log.  If the cache has become
 /// large enough, then the method will commit records in the cache.
 /// </summary>
 /// <param name="record">The record to be written.</param>
 public void Write(AppLogRecord record)
 {
     appLog.Write(record);
 }