예제 #1
0
        private byte[] ReadEntriesFromFile(PersistentQueueEntry firstEntry, long currentBufferSize)
        {
            byte[] buffer = new byte[currentBufferSize];
            if (firstEntry.Length < 1)
            {
                return(buffer);
            }
            using (FileStream reader = new FileStream(GetDataPath(firstEntry.FileNumber),
                                                      FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite))
            {
                reader.Position = firstEntry.Start;
                int totalRead = 0;
                do
                {
                    int bytesRead = reader.Read(buffer, totalRead, buffer.Length - totalRead);
                    if (bytesRead == 0)
                    {
                        throw new InvalidOperationException("End of file reached while trying to read queue item");
                    }
                    totalRead += bytesRead;
                } while (totalRead < buffer.Length);
            }

            return(buffer);
        }
예제 #2
0
        public PersistentQueueEntry Dequeue()
        {
            lock (_entries)
            {
                LinkedListNode <PersistentQueueEntry> first = _entries.First;
                if (first == null)
                {
                    return(null);
                }
                PersistentQueueEntry entry = first.Value;

                if (entry.Data == null)
                {
                    ReadAhead();
                }

                _entries.RemoveFirst();
                // we need to create a copy so we will not hold the data
                // in memory as well as the position
                lock (_checkedOutEntries)
                {
                    _checkedOutEntries.Add(new PersistentQueueEntry(entry.FileNumber, entry.Start, entry.Length));
                }

                return(entry);
            }
        }
예제 #3
0
        private IEnumerable <int> ApplyTransactionOperationsInMemory(IEnumerable <PersistentQueueOperation> operations)
        {
            foreach (PersistentQueueOperation operation in operations)
            {
                switch (operation.Type)
                {
                case PersistentQueueOperationTypes.ENQUEUE:
                    PersistentQueueEntry entryToAdd = new PersistentQueueEntry(operation);
                    lock (_entries)
                    {
                        _entries.AddLast(entryToAdd);
                    }
                    int itemCountAddition = _countOfItemsPerFile.GetValueOrDefault(entryToAdd.FileNumber);
                    _countOfItemsPerFile[entryToAdd.FileNumber] = itemCountAddition + 1;
                    break;

                case PersistentQueueOperationTypes.DEQUEUE:
                    PersistentQueueEntry entryToRemove = new PersistentQueueEntry(operation);
                    lock (_checkedOutEntries)
                    {
                        _checkedOutEntries.Remove(entryToRemove);
                    }

                    int itemCountRemoval = _countOfItemsPerFile.GetValueOrDefault(entryToRemove.FileNumber);
                    _countOfItemsPerFile[entryToRemove.FileNumber] = itemCountRemoval - 1;
                    break;

                case PersistentQueueOperationTypes.REINSTATE:
                    PersistentQueueEntry entryToReinstate = new PersistentQueueEntry(operation);
                    lock (_entries)
                    {
                        _entries.AddFirst(entryToReinstate);
                    }

                    lock (_checkedOutEntries)
                    {
                        _checkedOutEntries.Remove(entryToReinstate);
                    }

                    break;
                }
            }

            HashSet <int> filesToRemove = new HashSet <int>(
                from pair in _countOfItemsPerFile
                where pair.Value < 1
                select pair.Key
                );

            foreach (int i in filesToRemove)
            {
                _countOfItemsPerFile.Remove(i);
            }

            return(filesToRemove.ToArray());
        }
예제 #4
0
        /// <summary>
        /// This special purpose function is to work around potential issues with Mono
        /// </summary>
//		private static PersistentQueueEntry[] ToArray(LinkedList<PersistentQueueEntry> list)
//		{
//			if (list == null) return new PersistentQueueEntry[0];
//			List<PersistentQueueEntry> outp = new List<PersistentQueueEntry>(25);
//			LinkedListNode<PersistentQueueEntry> cur = list.First;
//			while (cur != null)
//			{
//				outp.Add(cur.Value);
//				cur = cur.Next;
//			}
//
//			return outp.ToArray();
//		}

        private static void WriteEntryToTransactionLog(Stream ms, PersistentQueueEntry entry, PersistentQueueOperationTypes operationType)
        {
            ms.Write(PersistentQueueUtils.OperationSeparatorBytes, 0, PersistentQueueUtils.OperationSeparatorBytes.Length);

            ms.WriteByte((byte)operationType);

            byte[] fileNumber = BitConverter.GetBytes(entry.FileNumber);
            ms.Write(fileNumber, 0, fileNumber.Length);

            byte[] start = BitConverter.GetBytes(entry.Start);
            ms.Write(start, 0, start.Length);

            byte[] length = BitConverter.GetBytes(entry.Length);
            ms.Write(length, 0, length.Length);
        }
예제 #5
0
        /// <summary>
        /// Try to pull data from the queue. Data is removed from the queue on `Flush()`
        /// </summary>
        public byte[] Dequeue()
        {
            PersistentQueueEntry entry = _queue.Dequeue();

            if (entry == null)
            {
                return(null);
            }
            _operations.Add(new PersistentQueueOperation(
                                PersistentQueueOperationTypes.DEQUEUE,
                                entry.FileNumber,
                                entry.Start,
                                entry.Length
                                ));
            return(entry.Data);
        }
예제 #6
0
        /// <summary>
        /// Assumes that entries has at least one entry. Should be called inside a lock.
        /// </summary>
        private void ReadAhead()
        {
            long currentBufferSize          = 0;
            PersistentQueueEntry firstEntry = _entries.First.Value;
            PersistentQueueEntry lastEntry  = firstEntry;

            foreach (PersistentQueueEntry entry in _entries)
            {
                // we can't read ahead to another file or
                // if we have unordered queue, or sparse items
                if (entry != lastEntry &&
                    (entry.FileNumber != lastEntry.FileNumber ||
                     entry.Start != (lastEntry.Start + lastEntry.Length)))
                {
                    break;
                }
                if (currentBufferSize + entry.Length > PersistentQueueUtils._1Megabytes)
                {
                    break;
                }
                lastEntry          = entry;
                currentBufferSize += entry.Length;
            }

            if (lastEntry == firstEntry)
            {
                currentBufferSize = lastEntry.Length;
            }

            byte[] buffer = ReadEntriesFromFile(firstEntry, currentBufferSize);

            int index = 0;

            foreach (PersistentQueueEntry entry in _entries)
            {
                entry.Data = new byte[entry.Length];
                Buffer.BlockCopy(buffer, index, entry.Data, 0, entry.Length);
                index += entry.Length;
                if (entry == lastEntry)
                {
                    break;
                }
            }
        }