/// <summary>
        /// Detach the aggregated data from the aggregator.
        /// </summary>
        /// <returns>The aggregated data (null if it was already detached).</returns>
        public KeyedDataStore <TInternal> AcquireData()
        {
            var ret = this.data;

            this.data = null;
            return(ret);
        }
        public void WriteData <TInternal>(string name, DateTime start, DateTime end, uint dataCount,
                                          IEnumerable <PersistedDataSource> sources, KeyedDataStore <TInternal> data)
            where TInternal : class, IInternalData, new()
        {
            var header = new PersistedDataHeader(name, start, end,
                                                 PersistedDataProtocol.GetPersistedTypeCodeFromType(typeof(TInternal)),
                                                 sources, this.dimensionSet, dataCount);

            this.WriteDataWithLengthAndCRC32(ms =>
            {
                header.Write(new BufferWriter(ms));
            }, header.SerializedSize, true);

            // The raw data does not compress particularly well. There is some overlap in the keys, but particularly
            // for histograms they come pre-compressed. We also use VLE heavily in KeyedDataStore.Serialize which
            // makes for pretty compact data.
            this.WriteDataWithLengthAndCRC32(data.Serialize, data.SerializedSize, false);

            // We can now determine what our block length really is and back-fill our data.
            var currentPosition = this.sourceStream.Position;
            var blockLength     = this.sourceStream.Position - this.blockStartOffset;

            this.sourceStream.Position = this.blockLengthOffset;
            this.sourceStreamWriter.WriteUInt64((ulong)blockLength);
            this.sourceStream.Position = currentPosition;
        }
예제 #3
0
        public KeyedDataStore <TInternal> LoadData <TInternal>()
            where TInternal : class, IInternalData, new()
        {
            PersistedDataType          dataType = this.Header.DataType;
            KeyedDataStore <TInternal> store    =
                this.LoadAndValidateData((ms, buffer, length) =>
            {
                var newStore = new KeyedDataStore <TInternal>(
                    this.DimensionSet, this.memoryStreamManager,
                    ms, (int)this.pendingObjects, dataType, "new");
                this.pendingObjects -= (uint)newStore.Count;
                return(newStore);
            });

            return(store);
        }
예제 #4
0
        public DataBucket(DimensionSet dimensionSet, DateTime timestamp, long timeSpanInTicks, string storagePath,
                          RecyclableMemoryStreamManager memoryStreamManager)
        {
            timestamp = timestamp.ToUniversalTime();

            this.DimensionSet        = dimensionSet;
            this.TimeSpan            = TimeSpan.FromTicks(timeSpanInTicks);
            this.StartTime           = RoundTimeStampToBucketKey(timestamp, timeSpanInTicks);
            this.memoryStreamManager = memoryStreamManager;

            if (storagePath != null)
            {
                this.Filename = Path.Combine(storagePath, GenerateFilename(this.StartTicks, this.EndTicks));
            }

            this.Blobname = GenerateBlobname(this.StartTicks, this.EndTicks);
            this.data     = new KeyedDataStore <TInternal>(this.DimensionSet, this.memoryStreamManager, "db ctor");
        }
예제 #5
0
        public void UpdateDataFromSources(IList <string> sourceList, DimensionSet sourceDimensions,
                                          KeyedDataStore <TInternal> sourceData)
        {
            if (this.Sealed)
            {
                throw new InvalidOperationException("Attempt to write to sealed bucket.");
            }

            foreach (var s in sourceList)
            {
                // Below we do some sanity checking to make sure that we're not ingesting data we were already given,
                // or ingesting data from a source that wasn't pre-declared as an input. Either of these would indicate
                // an upstream logic fault.
                var source = this.FindSource(s);
                if (source == null)
                {
                    throw new InvalidOperationException("Adding data from previously unknown source " + s);
                }

                if (source.Status != PersistedDataSourceStatus.Unknown)
                {
                    throw new InvalidOperationException("Double adding data from source " + s);
                }

                source.Status = PersistedDataSourceStatus.Available;
            }

            using (SharedLock.OpenExclusive(this.dataAccessLock))
            {
                this.Load();
                if (this.data == null || this.data.Empty)
                {
                    this.DimensionSet = sourceDimensions;
                    this.data         = sourceData;
                }
                else
                {
                    this.data.TakeData(sourceData);
                    sourceData.Dispose();
                }

                this.dirty = true;
            }
        }
        public void TakeData(KeyedDataStore <TInternal> otherData)
        {
            lock (this)
            {
                if (otherData.mergedData != null)
                {
                    this.unmergedData.Add(otherData.mergedData);
                    otherData.mergedData = null;
                }

                if (otherData.pendingDataStream != null)
                {
                    otherData.SealWriteBuffer(null);
                }

                this.unmergedData.AddRange(otherData.unmergedData);
                otherData.unmergedData.Clear();
            }
        }
예제 #7
0
        /// <summary>
        /// Release data from memory and write it to persisted storage if possible. This call will block until all users
        /// are finished accessing the data.
        /// </summary>
        public void ReleaseData()
        {
            using (SharedLock.OpenExclusive(this.dataAccessLock))
            {
                this.Persist();
                if (this.data != null)
                {
                    this.data.Dispose();
                    // force unloading our (probably populous) dimension set by doing a shallow copy.
                    // NOTE: This also gets rid of potentially large arrays whereas clearing them might not do so. Other
                    // work could be done to free up this memory but there's not a ton of value in this.
                    this.DimensionSet = new DimensionSet(this.DimensionSet);
                }

                // Once sealed we can guarantee no more source updates.
                if (this.Sealed)
                {
                    this.sources.Clear();
                }

                this.data = null;
            }
        }
        private void UnpackResponse(PersistedDataReader dataReader)
        {
            while (dataReader.ReadDataHeader())
            {
                lock (this)
                {
                    if (this.DimensionSet == null)
                    {
                        this.DimensionSet = dataReader.DimensionSet;
                    }

                    var remoteData = dataReader.LoadData <TInternal>();
                    if (!remoteData.Validate())
                    {
                        remoteData.Dispose();
                        throw new PersistedDataException("Remote data is invalid.");
                    }

                    if (this.data == null && this.DimensionSet.Equals(dataReader.DimensionSet))
                    {
                        this.DimensionSet = dataReader.DimensionSet;
                        this.data         = remoteData;
                    }
                    else
                    {
                        if (this.data == null)
                        {
                            this.data = new KeyedDataStore <TInternal>(this.DimensionSet, this.memoryStreamManager);
                        }

                        this.data.TakeData(remoteData);
                        remoteData.Dispose();
                    }
                }

                foreach (var responseSource in dataReader.Header.Sources)
                {
                    // NOTE: We use 'StartsWith' below because lots of data is currently marked with
                    // the non-FQDN machine name. We can change it to 'Equals' in the future.
                    var localSource =
                        this.Sources.FirstOrDefault(s =>
                                                    s.Name.StartsWith(responseSource.Name,
                                                                      StringComparison.OrdinalIgnoreCase));
                    if (localSource == null)
                    {
                        // XXX: here for testing because we have to query 'localhost' but won't ever get something good
                        // back. Yes, this is STUPID.
                        if (this.Sources.Count == 1 && this.Sources[0].Name == "localhost")
                        {
                            localSource = this.Sources[0];
                        }
                        else
                        {
                            throw new PersistedDataException(
                                      string.Format("Source {0} returned by server is unknown", responseSource.Name));
                        }
                    }
                    localSource.Status = responseSource.Status;
                }
            }
        }
예제 #9
0
        private void ReadFromStorage(string filename, bool sourcesOnly)
        {
            KeyedDataStore <TInternal> readData = null;

            try
            {
                Events.Write.BeginLoadingData(filename);
                using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    using (var reader = new PersistedDataReader(stream, this.memoryStreamManager, this.DimensionSet))
                    {
                        // We'll only ever write one set of data, so we only try to read one.
                        if (reader.ReadDataHeader())
                        {
                            this.MergeSourceStatus(reader.Header.Sources);

                            if (sourcesOnly)
                            {
                                return;
                            }

                            if (typeof(TInternal) != reader.DataType)
                            {
                                throw new InvalidDataException(
                                          string.Format(
                                              "this.start={0},this.end={1}, hdr.start={2}, hdr.end={3}, this.type={4}, hdr.type={5}",
                                              this.StartTicks, this.EndTicks, reader.StartTime.Ticks,
                                              reader.EndTime.Ticks,
                                              typeof(TInternal), reader.DataType));
                            }

                            readData = reader.LoadData <TInternal>();
                            if (this.DimensionSet.Equals(reader.DimensionSet) &&
                                (this.data == null || this.data.Empty))
                            {
                                this.DimensionSet = reader.DimensionSet;
                                if (this.data != null)
                                {
                                    this.data.Dispose();
                                }
                                this.data = readData;
                                readData  = null;
                            }
                            else
                            {
                                if (this.data == null)
                                {
                                    this.data = new KeyedDataStore <TInternal>(this.DimensionSet,
                                                                               this.memoryStreamManager,
                                                                               "read data");
                                }
                                this.data.TakeData(readData);
                                this.data.Merge();
                            }
                        }
                    }
                }
            }
            catch (FileNotFoundException)
            {
                Events.Write.SealedDataFileMissing(filename);
            }
            catch (PersistedDataException ex)
            {
                Events.Write.PersistedDataException(ex);
                Events.Write.DiscardingIncompleteData(filename);
                if (this.data != null)
                {
                    this.data.Dispose();
                }
                this.data = null;
            }
            catch (OutOfMemoryException)
            {
                // TODO: this code is here to deal with file corruption issues, once checksums have been added and
                // are fully available it must be removed.
                File.Delete(filename);
                throw;
            }
            finally
            {
                if (readData != null)
                {
                    readData.Dispose();
                }
            }

            // if data is still null, some error happened loading the file (empty, missing, corrupt).
            // Just start over with clean data.
            if (this.data == null)
            {
                if (File.Exists(this.Filename))
                {
                    File.Delete(this.Filename);
                }

                this.data = new KeyedDataStore <TInternal>(this.DimensionSet, this.memoryStreamManager,
                                                           "placeholder for invalid data.");
            }

            Events.Write.EndLoadingData(filename);
        }