2015-01-22 03:07:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Copyright 2014 The Prometheus Authors
 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-20 00:18:44 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Licensed under the Apache License, Version 2.0 (the "License");
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// you may not use this file except in compliance with the License.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// You may obtain a copy of the License at
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// http://www.apache.org/licenses/LICENSE-2.0
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Unless required by applicable law or agreed to in writing, software
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// distributed under the License is distributed on an "AS IS" BASIS,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// See the License for the specific language governing permissions and
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// limitations under the License.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								package  local 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								import  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"bufio" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"encoding/binary" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"fmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"io" 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-04 01:59:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"io/ioutil" 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"os" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"path" 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-14 23:52:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"path/filepath" 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-03 03:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"strconv" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"sync" 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"sync/atomic" 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"github.com/golang/glog" 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/prometheus/client_golang/prometheus" 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									clientmodel  "github.com/prometheus/client_golang/model" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/prometheus/prometheus/storage/local/codable" 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-14 23:52:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/prometheus/prometheus/storage/local/flock" 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-22 04:06:11 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/prometheus/prometheus/storage/local/index" 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/prometheus/prometheus/storage/metric" 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  ( 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-04 01:59:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// Version of the storage as it can be found in the version file.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// Increment to protect against incompatible changes.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-03 03:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									Version          =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									versionFileName  =  "VERSION" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									seriesFileSuffix      =  ".db" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									seriesTempFileSuffix  =  ".db.tmp" 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									seriesDirNameLen      =  2  // How many bytes of the fingerprint in dir name.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									headsFileName             =  "heads.db" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									headsTempFileName         =  "heads.db.tmp" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									headsFormatVersion        =  2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									headsFormatLegacyVersion  =  1  // Can read, but will never write.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									headsMagicString          =  "PrometheusHeads" 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									dirtyFileName  =  "DIRTY" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-04 23:27:14 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									fileBufSize  =  1  <<  16  // 64kiB.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-12 23:46:46 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									chunkHeaderLen              =  17 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									chunkHeaderTypeOffset       =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									chunkHeaderFirstTimeOffset  =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									chunkHeaderLastTimeOffset   =  9 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-06 21:58:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									indexingMaxBatchSize   =  1024  *  1024 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									indexingBatchTimeout   =  500  *  time . Millisecond  // Commit batch when idle for that long.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									indexingQueueCapacity  =  1024  *  16 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								var  fpLen  =  len ( clientmodel . Fingerprint ( 0 ) . String ( ) )  // Length of a fingerprint as string.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								const  ( 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									flagHeadChunkPersisted  byte  =  1  <<  iota 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// Add more flags here like:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// flagFoo
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// flagBar
 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								type  indexingOpType  byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									add  indexingOpType  =  iota 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									remove 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  indexingOp  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fingerprint  clientmodel . Fingerprint 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									metric       clientmodel . Metric 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									opType       indexingOpType 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// A Persistence is used by a Storage implementation to store samples
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// persistently across restarts. The methods are only goroutine-safe if
 
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												Improve persisting chunks to disk.
This is done by bucketing chunks by fingerprint. If the persisting to
disk falls behind, more and more chunks are in the queue. As soon as
there are "double hits", we will now persist both chunks in one go,
doubling the disk throughput (assuming it is limited by disk
seeks). Should even more pile up so that we end wit "triple hits", we
will persist those first, and so on.
Even if we have millions of time series, this will still help,
assuming not all of them are growing with the same speed. Series that
get many samples and/or are not very compressable will accumulate
chunks faster, and they will soon get double- or triple-writes.
To improve the chance of double writes,
-storage.local.persistence-queue-capacity could be set to a higher
value. However, that will slow down shutdown a lot (as the queue has
to be worked through). So we leave it to the user to set it to a
really high value. A more fundamental solution would be to checkpoint
not only head chunks, but also chunks still in the persist queue. That
would be quite complicated for a rather limited use-case (running many
time series with high ingestion rate on slow spinning disks).
											 
										 
										
											2015-02-14 03:08:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// explicitly marked as such below. The chunk-related methods persistChunks,
 
							 
						 
					
						
							
								
									
										
										
											
												Fix a bug handling freshly unarchived series.
Usually, if you unarchive a series, it is to add something to it,
which will create a new head chunk. However, if a series in
unarchived, and before anything is added to it, it is handled by the
maintenance loop, it will be archived again. In that case, we have to
load the chunkDescs to know the lastTime of the series to be
archived. Usually, this case will happen only rarely (as a race, has
never happened so far, possibly because the locking around unarchiving
and the subsequent sample append is smart enough). However, during
crash recovery, we sometimes treat series as "freshly unarchived"
without directly appending a sample. We might add more cases of that
type later, so better deal with archiving properly and load chunkDescs
if required.
											 
										 
										
											2015-01-08 23:10:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// dropChunks, loadChunks, and loadChunkDescs can be called concurrently with
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// each other if each call refers to a different fingerprint.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  persistence  struct  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-13 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									basePath  string 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									archivedFingerprintToMetrics    * index . FingerprintMetricIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									archivedFingerprintToTimeRange  * index . FingerprintTimeRangeIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									labelPairToFingerprints         * index . LabelPairFingerprintIndex 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									labelNameToLabelValues          * index . LabelNameLabelValuesIndex 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									indexingQueue    chan  indexingOp 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									indexingStopped  chan  struct { } 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									indexingFlush    chan  chan  int 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									indexingQueueLength    prometheus . Gauge 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									indexingQueueCapacity  prometheus . Metric 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									indexingBatchSizes     prometheus . Summary 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									indexingBatchDuration  prometheus . Summary 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									checkpointDuration     prometheus . Gauge 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:03:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									dirtyMtx        sync . Mutex      // Protects dirty and becameDirty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									dirty           bool            // true if persistence was started in dirty state.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									becameDirty     bool            // true if an inconsistency came up during runtime.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									pedanticChecks  bool            // true if crash recovery should check each series.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									dirtyFileName   string          // The file used for locking and to mark dirty state.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fLock           flock . Releaser  // The file lock to protect against concurrent usage.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									shouldSync  syncStrategy 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// newPersistence returns a newly allocated persistence backed by local disk storage, ready to use.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  newPersistence ( basePath  string ,  dirty ,  pedanticChecks  bool ,  shouldSync  syncStrategy )  ( * persistence ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-03 03:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									dirtyPath  :=  filepath . Join ( basePath ,  dirtyFileName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									versionPath  :=  filepath . Join ( basePath ,  versionFileName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-04 01:59:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  versionData ,  err  :=  ioutil . ReadFile ( versionPath ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  persistedVersion ,  err  :=  strconv . Atoi ( strings . TrimSpace ( string ( versionData ) ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  fmt . Errorf ( "cannot parse content of %s: %s" ,  versionPath ,  versionData ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-03 03:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										}  else  if  persistedVersion  !=  Version  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  fmt . Errorf ( "found storage version %d on disk, need version %d - please wipe storage or run a version of Prometheus compatible with storage version %d" ,  persistedVersion ,  Version ,  persistedVersion ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  if  os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// No version file found. Let's create the directory (in case
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// it's not there yet) and then check if it is actually
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// empty. If not, we have found an old storage directory without
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// version file, so we have to bail out.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  os . MkdirAll ( basePath ,  0700 ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-04 01:59:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										fis ,  err  :=  ioutil . ReadDir ( basePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-03 03:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-04 01:59:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  len ( fis )  >  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-03 03:02:37 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  nil ,  fmt . Errorf ( "could not detect storage version on disk, assuming version 0, need version %d - please wipe storage or run a version of Prometheus compatible with storage version 0" ,  Version ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// Finally we can write our own version into a new version file.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										file ,  err  :=  os . Create ( versionPath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										defer  file . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  _ ,  err  :=  fmt . Fprintf ( file ,  "%d\n" ,  Version ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-14 23:52:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fLock ,  dirtyfileExisted ,  err  :=  flock . New ( dirtyPath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Errorf ( "Could not lock %s, Prometheus already running?" ,  dirtyPath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  dirtyfileExisted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										dirty  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									archivedFingerprintToMetrics ,  err  :=  index . NewFingerprintMetricIndex ( basePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-22 04:06:11 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									archivedFingerprintToTimeRange ,  err  :=  index . NewFingerprintTimeRangeIndex ( basePath ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p  :=  & persistence { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-13 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										basePath :  basePath , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										archivedFingerprintToMetrics :    archivedFingerprintToMetrics , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										archivedFingerprintToTimeRange :  archivedFingerprintToTimeRange , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										indexingQueue :    make ( chan  indexingOp ,  indexingQueueCapacity ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										indexingStopped :  make ( chan  struct { } ) , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										indexingFlush :    make ( chan  chan  int ) , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										indexingQueueLength :  prometheus . NewGauge ( prometheus . GaugeOpts { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Namespace :  namespace , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Subsystem :  subsystem , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Name :       "indexing_queue_length" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Help :       "The number of metrics waiting to be indexed." , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										indexingQueueCapacity :  prometheus . MustNewConstMetric ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											prometheus . NewDesc ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												prometheus . BuildFQName ( namespace ,  subsystem ,  "indexing_queue_capacity" ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												"The capacity of the indexing queue." , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												nil ,  nil , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											prometheus . GaugeValue , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											float64 ( indexingQueueCapacity ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										indexingBatchSizes :  prometheus . NewSummary ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											prometheus . SummaryOpts { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Namespace :  namespace , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Subsystem :  subsystem , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Name :       "indexing_batch_sizes" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Help :       "Quantiles for indexing batch sizes (number of metrics per batch)." , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										indexingBatchDuration :  prometheus . NewSummary ( 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											prometheus . SummaryOpts { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Namespace :  namespace , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Subsystem :  subsystem , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												Name :       "indexing_batch_duration_milliseconds" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												Help :       "Quantiles for batch indexing duration in milliseconds." , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) , 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										checkpointDuration :  prometheus . NewGauge ( prometheus . GaugeOpts { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Namespace :  namespace , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Subsystem :  subsystem , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Name :       "checkpoint_duration_milliseconds" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											Help :       "The duration (in milliseconds) it took to checkpoint in-memory metrics and head chunks." , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} ) , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:03:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										dirty :           dirty , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										pedanticChecks :  pedanticChecks , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										dirtyFileName :   dirtyPath , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										fLock :           fLock , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										shouldSync :      shouldSync , 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  p . dirty  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// Blow away the label indexes. We'll rebuild them later.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  index . DeleteLabelPairFingerprintIndex ( basePath ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  index . DeleteLabelNameLabelValuesIndex ( basePath ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									labelPairToFingerprints ,  err  :=  index . NewLabelPairFingerprintIndex ( basePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									labelNameToLabelValues ,  err  :=  index . NewLabelNameLabelValuesIndex ( basePath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . labelPairToFingerprints  =  labelPairToFingerprints 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . labelNameToLabelValues  =  labelNameToLabelValues 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									go  p . processIndexingQueue ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  p ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Describe implements prometheus.Collector.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  Describe ( ch  chan <-  * prometheus . Desc )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									ch  <-  p . indexingQueueLength . Desc ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ch  <-  p . indexingQueueCapacity . Desc ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . indexingBatchSizes . Describe ( ch ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . indexingBatchDuration . Describe ( ch ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									ch  <-  p . checkpointDuration . Desc ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Collect implements prometheus.Collector.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  Collect ( ch  chan <-  prometheus . Metric )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . indexingQueueLength . Set ( float64 ( len ( p . indexingQueue ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ch  <-  p . indexingQueueLength 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									ch  <-  p . indexingQueueCapacity 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . indexingBatchSizes . Collect ( ch ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . indexingBatchDuration . Collect ( ch ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									ch  <-  p . checkpointDuration 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// isDirty returns the dirty flag in a goroutine-safe way.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  isDirty ( )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . dirtyMtx . Lock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  p . dirtyMtx . Unlock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  p . dirty 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// setDirty sets the dirty flag in a goroutine-safe way. Once the dirty flag was
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// set to true with this method, it cannot be set to false again. (If we became
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// dirty during our runtime, there is no way back. If we were dirty from the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// start, a clean-up might make us clean again.)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  setDirty ( dirty  bool )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . dirtyMtx . Lock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  p . dirtyMtx . Unlock ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  p . becameDirty  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . dirty  =  dirty 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  dirty  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . becameDirty  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "The storage is now inconsistent. Restart Prometheus ASAP to initiate recovery." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getFingerprintsForLabelPair returns the fingerprints for the given label
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// pair. This method is goroutine-safe but take into account that metrics queued
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// for indexing with IndexMetric might not have made it into the index
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// yet. (Same applies correspondingly to UnindexMetric.)
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  getFingerprintsForLabelPair ( lp  metric . LabelPair )  ( clientmodel . Fingerprints ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									fps ,  _ ,  err  :=  p . labelPairToFingerprints . Lookup ( lp ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  fps ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getLabelValuesForLabelName returns the label values for the given label
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// name. This method is goroutine-safe but take into account that metrics queued
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// for indexing with IndexMetric might not have made it into the index
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// yet. (Same applies correspondingly to UnindexMetric.)
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  getLabelValuesForLabelName ( ln  clientmodel . LabelName )  ( clientmodel . LabelValues ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									lvs ,  _ ,  err  :=  p . labelNameToLabelValues . Lookup ( ln ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  lvs ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												Improve persisting chunks to disk.
This is done by bucketing chunks by fingerprint. If the persisting to
disk falls behind, more and more chunks are in the queue. As soon as
there are "double hits", we will now persist both chunks in one go,
doubling the disk throughput (assuming it is limited by disk
seeks). Should even more pile up so that we end wit "triple hits", we
will persist those first, and so on.
Even if we have millions of time series, this will still help,
assuming not all of them are growing with the same speed. Series that
get many samples and/or are not very compressable will accumulate
chunks faster, and they will soon get double- or triple-writes.
To improve the chance of double writes,
-storage.local.persistence-queue-capacity could be set to a higher
value. However, that will slow down shutdown a lot (as the queue has
to be worked through). So we leave it to the user to set it to a
really high value. A more fundamental solution would be to checkpoint
not only head chunks, but also chunks still in the persist queue. That
would be quite complicated for a rather limited use-case (running many
time series with high ingestion rate on slow spinning disks).
											 
										 
										
											2015-02-14 03:08:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// persistChunks persists a number of consecutive chunks of a series. It is the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// caller's responsibility to not modify the chunks concurrently and to not
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// persist or drop anything for the same fingerprint concurrently. It returns
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// the (zero-based) index of the first persisted chunk within the series
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// file. In case of an error, the returned index is -1 (to avoid the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// misconception that the chunk was written at position 0).
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  persistChunks ( fp  clientmodel . Fingerprint ,  chunks  [ ] chunk )  ( index  int ,  err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											glog . Error ( "Error persisting chunks: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . setDirty ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												Improve persisting chunks to disk.
This is done by bucketing chunks by fingerprint. If the persisting to
disk falls behind, more and more chunks are in the queue. As soon as
there are "double hits", we will now persist both chunks in one go,
doubling the disk throughput (assuming it is limited by disk
seeks). Should even more pile up so that we end wit "triple hits", we
will persist those first, and so on.
Even if we have millions of time series, this will still help,
assuming not all of them are growing with the same speed. Series that
get many samples and/or are not very compressable will accumulate
chunks faster, and they will soon get double- or triple-writes.
To improve the chance of double writes,
-storage.local.persistence-queue-capacity could be set to a higher
value. However, that will slow down shutdown a lot (as the queue has
to be worked through). So we leave it to the user to set it to a
really high value. A more fundamental solution would be to checkpoint
not only head chunks, but also chunks still in the persist queue. That
would be quite complicated for a rather limited use-case (running many
time series with high ingestion rate on slow spinning disks).
											 
										 
										
											2015-02-14 03:08:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									f ,  err  :=  p . openChunkFileForWriting ( fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  - 1 ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									defer  p . closeChunkFile ( f ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  writeChunks ( f ,  chunks ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  - 1 ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												Improve persisting chunks to disk.
This is done by bucketing chunks by fingerprint. If the persisting to
disk falls behind, more and more chunks are in the queue. As soon as
there are "double hits", we will now persist both chunks in one go,
doubling the disk throughput (assuming it is limited by disk
seeks). Should even more pile up so that we end wit "triple hits", we
will persist those first, and so on.
Even if we have millions of time series, this will still help,
assuming not all of them are growing with the same speed. Series that
get many samples and/or are not very compressable will accumulate
chunks faster, and they will soon get double- or triple-writes.
To improve the chance of double writes,
-storage.local.persistence-queue-capacity could be set to a higher
value. However, that will slow down shutdown a lot (as the queue has
to be worked through). So we leave it to the user to set it to a
really high value. A more fundamental solution would be to checkpoint
not only head chunks, but also chunks still in the persist queue. That
would be quite complicated for a rather limited use-case (running many
time series with high ingestion rate on slow spinning disks).
											 
										 
										
											2015-02-14 03:08:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// Determine index within the file.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									offset ,  err  :=  f . Seek ( 0 ,  os . SEEK_CUR ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  - 1 ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									index ,  err  =  chunkIndexForOffset ( offset ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  - 1 ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										 
										
											
												Improve persisting chunks to disk.
This is done by bucketing chunks by fingerprint. If the persisting to
disk falls behind, more and more chunks are in the queue. As soon as
there are "double hits", we will now persist both chunks in one go,
doubling the disk throughput (assuming it is limited by disk
seeks). Should even more pile up so that we end wit "triple hits", we
will persist those first, and so on.
Even if we have millions of time series, this will still help,
assuming not all of them are growing with the same speed. Series that
get many samples and/or are not very compressable will accumulate
chunks faster, and they will soon get double- or triple-writes.
To improve the chance of double writes,
-storage.local.persistence-queue-capacity could be set to a higher
value. However, that will slow down shutdown a lot (as the queue has
to be worked through). So we leave it to the user to set it to a
really high value. A more fundamental solution would be to checkpoint
not only head chunks, but also chunks still in the persist queue. That
would be quite complicated for a rather limited use-case (running many
time series with high ingestion rate on slow spinning disks).
											 
										 
										
											2015-02-14 03:08:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  index  -  len ( chunks ) ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// loadChunks loads a group of chunks of a timeseries by their index. The chunk
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// with the earliest time will have index 0, the following ones will have
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// incrementally larger indexes. The indexOffset denotes the offset to be added to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// each index in indexes. It is the caller's responsibility to not persist or
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// drop anything for the same fingerprint concurrently.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  loadChunks ( fp  clientmodel . Fingerprint ,  indexes  [ ] int ,  indexOffset  int )  ( [ ] chunk ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									f ,  err  :=  p . openChunkFileForReading ( fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 21:53:05 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									chunks  :=  make ( [ ] chunk ,  0 ,  len ( indexes ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									typeBuf  :=  make ( [ ] byte ,  1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  idx  :=  range  indexes  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										_ ,  err  :=  f . Seek ( offsetForChunkIndex ( idx + indexOffset ) ,  os . SEEK_SET ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										n ,  err  :=  f . Read ( typeBuf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  n  !=  1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											panic ( "read returned != 1 bytes" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_ ,  err  =  f . Seek ( chunkHeaderLen - 1 ,  os . SEEK_CUR ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-13 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										chunk  :=  newChunkForEncoding ( chunkEncoding ( typeBuf [ 0 ] ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										chunk . unmarshal ( f ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										chunks  =  append ( chunks ,  chunk ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									chunkOps . WithLabelValues ( load ) . Add ( float64 ( len ( chunks ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									atomic . AddInt64 ( & numMemChunks ,  int64 ( len ( chunks ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									return  chunks ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// loadChunkDescs loads chunkDescs for a series up until a given time.  It is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// the caller's responsibility to not persist or drop anything for the same
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// fingerprint concurrently.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 21:53:05 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  loadChunkDescs ( fp  clientmodel . Fingerprint ,  beforeTime  clientmodel . Timestamp )  ( [ ] * chunkDesc ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									f ,  err  :=  p . openChunkFileForReading ( fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fi ,  err  :=  f . Stat ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-04 20:40:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									totalChunkLen  :=  chunkHeaderLen  +  chunkLen 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  fi . Size ( ) % int64 ( totalChunkLen )  !=  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										p . setDirty ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"size of series file for fingerprint %v is %d, which is not a multiple of the chunk length %d" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											fp ,  fi . Size ( ) ,  totalChunkLen , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									numChunks  :=  int ( fi . Size ( ) )  /  totalChunkLen 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 21:53:05 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									cds  :=  make ( [ ] * chunkDesc ,  0 ,  numChunks ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									for  i  :=  0 ;  i  <  numChunks ;  i ++  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										_ ,  err  :=  f . Seek ( offsetForChunkIndex ( i ) + chunkHeaderFirstTimeOffset ,  os . SEEK_SET ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										chunkTimesBuf  :=  make ( [ ] byte ,  16 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_ ,  err  =  io . ReadAtLeast ( f ,  chunkTimesBuf ,  16 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										cd  :=  & chunkDesc { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 21:53:05 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											chunkFirstTime :  clientmodel . Timestamp ( binary . LittleEndian . Uint64 ( chunkTimesBuf ) ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											chunkLastTime :   clientmodel . Timestamp ( binary . LittleEndian . Uint64 ( chunkTimesBuf [ 8 : ] ) ) , 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-29 02:01:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  ! cd . chunkLastTime . Before ( beforeTime )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											// From here on, we have chunkDescs in memory already.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										cds  =  append ( cds ,  cd ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-23 01:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									chunkDescOps . WithLabelValues ( load ) . Add ( float64 ( len ( cds ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 01:25:03 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									numMemChunkDescs . Add ( float64 ( len ( cds ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									return  cds ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// checkpointSeriesMapAndHeads persists the fingerprint to memory-series mapping
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// and all non persisted chunks. Do not call concurrently with
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// loadSeriesMapAndHeads. This method will only write heads format v2, but
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// loadSeriesMapAndHeads can also understand v1.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Description of the file format (for both, v1 and v2):
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (1) Magic string (const headsMagicString).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (2) Varint-encoded format version (const headsFormatVersion).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (3) Number of series in checkpoint as big-endian uint64.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (4) Repeated once per series:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.1) A flag byte, see flag constants above. (Present but unused in v2.)
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (4.2) The fingerprint as big-endian uint64.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (4.3) The metric as defined by codable.Metric.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.4) The varint-encoded persistWatermark. (Missing in v1.)
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:54:59 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.5) The modification time of the series file as nanoseconds elapsed since
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:59:26 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// January 1, 1970 UTC. -1 if the modification time is unknown or no series file
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// exists yet. (Missing in v1.)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (4.6) The varint-encoded chunkDescsOffset.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.6) The varint-encoded savedFirstTime.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.7) The varint-encoded number of chunk descriptors.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.8) Repeated once per chunk descriptor, oldest to most recent, either
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// variant 4.8.1 (if index < persistWatermark) or variant 4.8.2 (if index >=
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// persistWatermark). In v1, everything is variant 4.8.1 except for a
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// non-persisted head-chunk (determined by the flags).
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.8.1.1) The varint-encoded first time.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (4.8.1.2) The varint-encoded last time.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// (4.8.2.1) A byte defining the chunk type.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (4.8.2.2) The chunk itself, marshaled with the marshal() method.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 03:46:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								//
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  checkpointSeriesMapAndHeads ( fingerprintToSeries  * seriesMap ,  fpLocker  * fingerprintLocker )  ( err  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									glog . Info ( "Checkpointing in-memory metrics and chunks..." ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									begin  :=  time . Now ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									f ,  err  :=  os . OpenFile ( p . headsTempFileName ( ) ,  os . O_WRONLY | os . O_TRUNC | os . O_CREATE ,  0640 ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-12 02:10:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										f . Sync ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										closeErr  :=  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										err  =  closeErr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										err  =  os . Rename ( p . headsTempFileName ( ) ,  p . headsFileName ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										duration  :=  time . Since ( begin ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . checkpointDuration . Set ( float64 ( duration )  /  float64 ( time . Millisecond ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										glog . Infof ( "Done checkpointing in-memory metrics and chunks in %v." ,  duration ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									w  :=  bufio . NewWriterSize ( f ,  fileBufSize ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  _ ,  err  =  w . WriteString ( headsMagicString ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  numberOfSeriesOffset  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  numberOfSeriesOffset ,  err  =  codable . EncodeVarint ( w ,  headsFormatVersion ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									numberOfSeriesOffset  +=  len ( headsMagicString ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									numberOfSeriesInHeader  :=  uint64 ( fingerprintToSeries . length ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// We have to write the number of series as uint64 because we might need
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// to overwrite it later, and a varint might change byte width then.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  =  codable . EncodeUint64 ( w ,  numberOfSeriesInHeader ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									iter  :=  fingerprintToSeries . iter ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// Consume the iterator in any case to not leak goroutines.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-12-26 20:37:30 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										for  range  iter  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  realNumberOfSeries  uint64 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									for  m  :=  range  iter  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										func ( )  {  // Wrapped in function to use defer for unlocking the fp.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											fpLocker . Lock ( m . fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											defer  fpLocker . Unlock ( m . fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  len ( m . series . chunkDescs )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												// This series was completely purged or archived in the meantime. Ignore.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											realNumberOfSeries ++ 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											// seriesFlags left empty in v2.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  =  w . WriteByte ( 0 ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  =  codable . EncodeUint64 ( w ,  uint64 ( m . fp ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											var  buf  [ ] byte 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											buf ,  err  =  codable . Metric ( m . series . metric ) . MarshalBinary ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											w . Write ( buf ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  _ ,  err  =  codable . EncodeVarint ( w ,  int64 ( m . series . persistWatermark ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:59:26 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  m . series . modTime . IsZero ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  _ ,  err  =  codable . EncodeVarint ( w ,  - 1 ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  _ ,  err  =  codable . EncodeVarint ( w ,  m . series . modTime . UnixNano ( ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  _ ,  err  =  codable . EncodeVarint ( w ,  int64 ( m . series . chunkDescsOffset ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-08 08:01:34 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  _ ,  err  =  codable . EncodeVarint ( w ,  int64 ( m . series . savedFirstTime ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  _ ,  err  =  codable . EncodeVarint ( w ,  int64 ( len ( m . series . chunkDescs ) ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											for  i ,  chunkDesc  :=  range  m . series . chunkDescs  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												if  i  <  m . series . persistWatermark  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													if  _ ,  err  =  codable . EncodeVarint ( w ,  int64 ( chunkDesc . firstTime ( ) ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													if  _ ,  err  =  codable . EncodeVarint ( w ,  int64 ( chunkDesc . lastTime ( ) ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													// This is the non-persisted head chunk. Fully marshal it.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-13 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													if  err  =  w . WriteByte ( byte ( chunkDesc . chunk . encoding ( ) ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
														return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													if  err  =  chunkDesc . chunk . marshal ( w ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											// Series is checkpointed now, so declare it clean.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											m . series . dirty  =  false 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  =  w . Flush ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  realNumberOfSeries  !=  numberOfSeriesInHeader  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// The number of series has changed in the meantime.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// Rewrite it in the header.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  _ ,  err  =  f . Seek ( int64 ( numberOfSeriesOffset ) ,  os . SEEK_SET ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  =  codable . EncodeUint64 ( f ,  realNumberOfSeries ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// loadSeriesMapAndHeads loads the fingerprint to memory-series mapping and all
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// the chunks contained in the checkpoint (and thus not yet persisted to series
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// files). The method is capable of loading the checkpoint format v1 and v2. If
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// recoverable corruption is detected, or if the dirty flag was set from the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// beginning, crash recovery is run, which might take a while. If an
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// unrecoverable error is encountered, it is returned. Call this method during
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// start-up while nothing else is running in storage land. This method is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// utterly goroutine-unsafe.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  loadSeriesMapAndHeads ( )  ( sm  * seriesMap ,  chunksToPersist  int64 ,  err  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-27 07:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  chunkDescsTotal  int64 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									fingerprintToSeries  :=  make ( map [ clientmodel . Fingerprint ] * memorySeries ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									sm  =  & seriesMap { m :  fingerprintToSeries } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  sm  !=  nil  &&  p . dirty  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											glog . Warning ( "Persistence layer appears dirty." ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											err  =  p . recoverFromCrash ( fingerprintToSeries ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												sm  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-28 01:25:03 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											numMemChunkDescs . Add ( float64 ( chunkDescsTotal ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-23 21:18:32 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									f ,  err  :=  os . Open ( p . headsFileName ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  sm ,  0 ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										glog . Warning ( "Could not open heads file:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . dirty  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									r  :=  bufio . NewReaderSize ( f ,  fileBufSize ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									buf  :=  make ( [ ] byte ,  len ( headsMagicString ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  _ ,  err  :=  io . ReadFull ( r ,  buf ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										glog . Warning ( "Could not read from heads file:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  sm ,  0 ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									magic  :=  string ( buf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  magic  !=  headsMagicString  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										glog . Warningf ( 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											"unexpected magic string, want %q, got %q" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											headsMagicString ,  magic , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										p . dirty  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									version ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  ( version  !=  headsFormatVersion  &&  version  !=  headsFormatLegacyVersion )  ||  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										glog . Warningf ( "unknown heads format version, want %d" ,  headsFormatVersion ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  sm ,  0 ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									numSeries ,  err  :=  codable . DecodeUint64 ( r ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										glog . Warning ( "Could not decode number of series:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  sm ,  0 ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  ;  numSeries  >  0 ;  numSeries --  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										seriesFlags ,  err  :=  r . ReadByte ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Warning ( "Could not read series flags:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										headChunkPersisted  :=  seriesFlags & flagHeadChunkPersisted  !=  0 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										fp ,  err  :=  codable . DecodeUint64 ( r ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Warning ( "Could not decode fingerprint:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										var  metric  codable . Metric 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  :=  metric . UnmarshalFromReader ( r ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Warning ( "Could not decode metric:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										var  persistWatermark  int64 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:59:26 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										var  modTime  time . Time 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  version  !=  headsFormatLegacyVersion  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// persistWatermark only present in v2.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											persistWatermark ,  err  =  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												glog . Warning ( "Could not decode persist watermark:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:59:26 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											modTimeNano ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												glog . Warning ( "Could not decode modification time:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												p . dirty  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  modTimeNano  !=  - 1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												modTime  =  time . Unix ( 0 ,  modTimeNano ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										chunkDescsOffset ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Warning ( "Could not decode chunk descriptor offset:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-08 08:01:34 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										savedFirstTime ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											glog . Warning ( "Could not decode saved first time:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-08 08:01:34 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										numChunkDescs ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Warning ( "Could not decode number of chunk descriptors:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 21:53:05 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										chunkDescs  :=  make ( [ ] * chunkDesc ,  numChunkDescs ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  version  ==  headsFormatLegacyVersion  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  headChunkPersisted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												persistWatermark  =  numChunkDescs 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												persistWatermark  =  numChunkDescs  -  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										for  i  :=  int64 ( 0 ) ;  i  <  numChunkDescs ;  i ++  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  i  <  persistWatermark  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												firstTime ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													glog . Warning ( "Could not decode first time:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												lastTime ,  err  :=  binary . ReadVarint ( r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													glog . Warning ( "Could not decode last time:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												chunkDescs [ i ]  =  & chunkDesc { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 21:53:05 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													chunkFirstTime :  clientmodel . Timestamp ( firstTime ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													chunkLastTime :   clientmodel . Timestamp ( lastTime ) , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												chunkDescsTotal ++ 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												// Non-persisted chunk.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-13 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												encoding ,  err  :=  r . ReadByte ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													glog . Warning ( "Could not decode chunk type:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-13 22:49:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												chunk  :=  newChunkForEncoding ( chunkEncoding ( encoding ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												if  err  :=  chunk . unmarshal ( r ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													glog . Warning ( "Could not decode chunk type:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													p . dirty  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
													return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-23 01:21:23 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												chunkDescs [ i ]  =  newChunkDesc ( chunk ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												chunksToPersist ++ 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										fingerprintToSeries [ clientmodel . Fingerprint ( fp ) ]  =  & memorySeries { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											metric :            clientmodel . Metric ( metric ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											chunkDescs :        chunkDescs , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											persistWatermark :  int ( persistWatermark ) , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:59:26 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											modTime :           modTime , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											chunkDescsOffset :  int ( chunkDescsOffset ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											savedFirstTime :    clientmodel . Timestamp ( savedFirstTime ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											headChunkClosed :   persistWatermark  >=  numChunkDescs , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:36:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  sm ,  chunksToPersist ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// dropAndPersistChunks deletes all chunks from a series file whose last sample
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// time is before beforeTime, and then appends the provided chunks, leaving out
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// those whose last sample time is before beforeTime. It returns the timestamp
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// of the first sample in the oldest chunk _not_ dropped, the offset within the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// series file of the first chunk persisted (out of the provided chunks), the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// number of deleted chunks, and true if all chunks of the series have been
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// deleted (in which case the returned timestamp will be 0 and must be ignored).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// It is the caller's responsibility to make sure nothing is persisted or loaded
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// for the same fingerprint concurrently.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  dropAndPersistChunks ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fp  clientmodel . Fingerprint ,  beforeTime  clientmodel . Timestamp ,  chunks  [ ] chunk , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								)  ( 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									firstTimeNotDropped  clientmodel . Timestamp , 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									offset  int , 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									numDropped  int , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									allDropped  bool , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									err  error , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								)  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// Style note: With the many return values, it was decided to use naked
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// returns in this method. They make the method more readable, but
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// please handle with care!
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Error ( "Error dropping and/or persisting chunks: " ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											p . setDirty ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  len ( chunks )  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// We have chunks to persist. First check if those are already
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// too old. If that's the case, the chunks in the series file
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// are all too old, too.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										i  :=  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										for  ;  i  <  len ( chunks )  &&  chunks [ i ] . lastTime ( ) . Before ( beforeTime ) ;  i ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  i  <  len ( chunks )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											firstTimeNotDropped  =  chunks [ i ] . firstTime ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  i  >  0  ||  firstTimeNotDropped . Before ( beforeTime )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// Series file has to go.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  numDropped ,  err  =  p . deleteSeriesFile ( fp ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											numDropped  +=  i 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  i  ==  len ( chunks )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												allDropped  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// Now simply persist what has to be persisted to a new file.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											_ ,  err  =  p . persistChunks ( fp ,  chunks [ i : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// If we are here, we have to check the series file itself.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									f ,  err  :=  p . openChunkFileForReading ( fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										// No series file. Only need to create new file with chunks to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// persist, if there are any.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  len ( chunks )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											allDropped  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											err  =  nil  // Do not report not-exist err.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										offset ,  err  =  p . persistChunks ( fp ,  chunks ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// Find the first chunk in the file that should be kept.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  ;  ;  numDropped ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_ ,  err  =  f . Seek ( offsetForChunkIndex ( numDropped ) ,  os . SEEK_SET ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										headerBuf  :=  make ( [ ] byte ,  chunkHeaderLen ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_ ,  err  =  io . ReadAtLeast ( f ,  headerBuf ,  chunkHeaderLen ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  err  ==  io . EOF  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// We ran into the end of the file without finding any chunks that should
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// be kept. Remove the whole file.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  numDropped ,  err  =  p . deleteSeriesFile ( fp ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  len ( chunks )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												allDropped  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											offset ,  err  =  p . persistChunks ( fp ,  chunks ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										lastTime  :=  clientmodel . Timestamp ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											binary . LittleEndian . Uint64 ( headerBuf [ chunkHeaderLastTimeOffset : ] ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  ! lastTime . Before ( beforeTime )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											firstTimeNotDropped  =  clientmodel . Timestamp ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												binary . LittleEndian . Uint64 ( headerBuf [ chunkHeaderFirstTimeOffset : ] ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											chunkOps . WithLabelValues ( drop ) . Add ( float64 ( numDropped ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// We've found the first chunk that should be kept. If it is the first
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// one, just append the chunks.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  numDropped  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  len ( chunks )  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											offset ,  err  =  p . persistChunks ( fp ,  chunks ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// Otherwise, seek backwards to the beginning of its header and start
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// copying everything from there into a new file. Then append the chunks
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// to the new file.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 02:09:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									_ ,  err  =  f . Seek ( - chunkHeaderLen ,  os . SEEK_CUR ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									temp ,  err  :=  os . OpenFile ( p . tempFileNameForFingerprint ( fp ) ,  os . O_WRONLY | os . O_CREATE ,  0640 ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										p . closeChunkFile ( temp ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											err  =  os . Rename ( p . tempFileNameForFingerprint ( fp ) ,  p . fileNameForFingerprint ( fp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									written ,  err  :=  io . Copy ( temp ,  f ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									offset  =  int ( written  /  ( chunkHeaderLen  +  chunkLen ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  len ( chunks )  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  =  writeChunks ( temp ,  chunks ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-28 03:40:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// deleteSeriesFile deletes a series file belonging to the provided
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// fingerprint. It returns the number of chunks that were contained in the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// deleted file.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  deleteSeriesFile ( fp  clientmodel . Fingerprint )  ( int ,  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fname  :=  p . fileNameForFingerprint ( fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fi ,  err  :=  os . Stat ( fname ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// Great. The file is already gone.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  0 ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  - 1 ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									numChunks  :=  int ( fi . Size ( )  /  ( chunkHeaderLen  +  chunkLen ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  os . Remove ( fname ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  - 1 ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									chunkOps . WithLabelValues ( drop ) . Add ( float64 ( numChunks ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  numChunks ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 19:59:26 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getSeriesFileModTime returns the modification time of the series file
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// belonging to the provided fingerprint. In case of an error, the zero value of
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// time.Time is returned.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  getSeriesFileModTime ( fp  clientmodel . Fingerprint )  time . Time  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									var  modTime  time . Time 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  fi ,  err  :=  os . Stat ( p . fileNameForFingerprint ( fp ) ) ;  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  fi . ModTime ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  modTime 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// indexMetric queues the given metric for addition to the indexes needed by
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// getFingerprintsForLabelPair, getLabelValuesForLabelName, and
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// getFingerprintsModifiedBefore.  If the queue is full, this method blocks
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// until the metric can be queued.  This method is goroutine-safe.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-29 02:01:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  indexMetric ( fp  clientmodel . Fingerprint ,  m  clientmodel . Metric )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . indexingQueue  <-  indexingOp { fp ,  m ,  add } 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// unindexMetric queues references to the given metric for removal from the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// indexes used for getFingerprintsForLabelPair, getLabelValuesForLabelName, and
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// getFingerprintsModifiedBefore. The index of fingerprints to archived metrics
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// is not affected by this removal. (In fact, never call this method for an
 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-26 22:19:44 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// archived metric. To purge an archived metric, call purgeArchivedFingerprint.)
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// If the queue is full, this method blocks until the metric can be queued. This
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// method is goroutine-safe.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-29 02:01:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  unindexMetric ( fp  clientmodel . Fingerprint ,  m  clientmodel . Metric )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . indexingQueue  <-  indexingOp { fp ,  m ,  remove } 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// waitForIndexing waits until all items in the indexing queue are processed. If
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// queue processing is currently on hold (to gather more ops for batching), this
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// method will trigger an immediate start of processing. This method is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// goroutine-safe.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  waitForIndexing ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:32:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									wait  :=  make ( chan  int ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										p . indexingFlush  <-  wait 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  <- wait  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// archiveMetric persists the mapping of the given fingerprint to the given
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// metric, together with the first and last timestamp of the series belonging to
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:33:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// the metric. The caller must have locked the fingerprint.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  archiveMetric ( 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									fp  clientmodel . Fingerprint ,  m  clientmodel . Metric ,  first ,  last  clientmodel . Timestamp , 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								)  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  p . archivedFingerprintToMetrics . Put ( codable . Fingerprint ( fp ) ,  codable . Metric ( m ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										p . setDirty ( true ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  p . archivedFingerprintToTimeRange . Put ( codable . Fingerprint ( fp ) ,  codable . TimeRange { First :  first ,  Last :  last } ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										p . setDirty ( true ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// hasArchivedMetric returns whether the archived metric for the given
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// fingerprint exists and if yes, what the first and last timestamp in the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// corresponding series is. This method is goroutine-safe.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  hasArchivedMetric ( fp  clientmodel . Fingerprint )  ( 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									hasMetric  bool ,  firstTime ,  lastTime  clientmodel . Timestamp ,  err  error , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								)  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									firstTime ,  lastTime ,  hasMetric ,  err  =  p . archivedFingerprintToTimeRange . Lookup ( fp ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// updateArchivedTimeRange updates an archived time range. The caller must make
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// sure that the fingerprint is currently archived (the time range will
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// otherwise be added without the corresponding metric in the archive).
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  updateArchivedTimeRange ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fp  clientmodel . Fingerprint ,  first ,  last  clientmodel . Timestamp , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								)  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  p . archivedFingerprintToTimeRange . Put ( codable . Fingerprint ( fp ) ,  codable . TimeRange { First :  first ,  Last :  last } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getFingerprintsModifiedBefore returns the fingerprints of archived timeseries
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// that have live samples before the provided timestamp. This method is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// goroutine-safe.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  getFingerprintsModifiedBefore ( beforeTime  clientmodel . Timestamp )  ( [ ] clientmodel . Fingerprint ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:32:07 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  fp  codable . Fingerprint 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									var  tr  codable . TimeRange 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fps  :=  [ ] clientmodel . Fingerprint { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									p . archivedFingerprintToTimeRange . ForEach ( func ( kv  index . KeyValueAccessor )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  kv . Value ( & tr ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  tr . First . Before ( beforeTime )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  :=  kv . Key ( & fp ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											fps  =  append ( fps ,  clientmodel . Fingerprint ( fp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  fps ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getArchivedMetric retrieves the archived metric with the given
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// fingerprint. This method is goroutine-safe.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  getArchivedMetric ( fp  clientmodel . Fingerprint )  ( clientmodel . Metric ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									metric ,  _ ,  err  :=  p . archivedFingerprintToMetrics . Lookup ( fp ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  metric ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-02-26 22:19:44 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// purgeArchivedMetric deletes an archived fingerprint and its corresponding
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// metric entirely. It also queues the metric for un-indexing (no need to call
 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-26 22:19:44 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// unindexMetric for the deleted metric.) It does not touch the series file,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// though. The caller must have locked the fingerprint.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  purgeArchivedMetric ( fp  clientmodel . Fingerprint )  ( err  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:22:08 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . setDirty ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									metric ,  err  :=  p . getArchivedMetric ( fp ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  ||  metric  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-29 19:57:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									deleted ,  err  :=  p . archivedFingerprintToMetrics . Delete ( codable . Fingerprint ( fp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-29 19:57:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  ! deleted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Errorf ( "Tried to delete non-archived fingerprint %s from archivedFingerprintToMetrics index. This should never happen." ,  fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									deleted ,  err  =  p . archivedFingerprintToTimeRange . Delete ( codable . Fingerprint ( fp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-29 19:57:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  ! deleted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Errorf ( "Tried to delete non-archived fingerprint %s from archivedFingerprintToTimeRange index. This should never happen." ,  fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-29 02:01:41 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									p . unindexMetric ( fp ,  metric ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-06-06 17:55:53 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2014-08-22 04:06:11 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// unarchiveMetric deletes an archived fingerprint and its metric, but (in
 
							 
						 
					
						
							
								
									
										
										
										
											2015-02-26 22:19:44 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// contrast to purgeArchivedMetric) does not un-index the metric.  If a metric
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// was actually deleted, the method returns true and the first time of the
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-11 01:33:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// deleted metric. The caller must have locked the fingerprint.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  unarchiveMetric ( fp  clientmodel . Fingerprint )  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									deletedAnything  bool , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									firstDeletedTime  clientmodel . Timestamp , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									err  error , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								)  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  func ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											p . setDirty ( true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									firstTime ,  _ ,  has ,  err  :=  p . archivedFingerprintToTimeRange . Lookup ( fp ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  ||  ! has  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  false ,  firstTime ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-29 19:57:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									deleted ,  err  :=  p . archivedFingerprintToMetrics . Delete ( codable . Fingerprint ( fp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  false ,  firstTime ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-29 19:57:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  ! deleted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Errorf ( "Tried to delete non-archived fingerprint %s from archivedFingerprintToMetrics index. This should never happen." ,  fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									deleted ,  err  =  p . archivedFingerprintToTimeRange . Delete ( codable . Fingerprint ( fp ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  false ,  firstTime ,  err 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-14 21:33:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-29 19:57:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  ! deleted  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Errorf ( "Tried to delete non-archived fingerprint %s from archivedFingerprintToTimeRange index. This should never happen." ,  fp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  true ,  firstTime ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// close flushes the indexing queue and other buffered data and releases any
 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// held resources. It also removes the dirty marker file if successful and if
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// the persistence is currently not marked as dirty.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  close ( )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									close ( p . indexingQueue ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									<- p . indexingStopped 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-01-14 23:52:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  lastError ,  dirtyFileRemoveError  error 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  p . archivedFingerprintToMetrics . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										lastError  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "Error closing archivedFingerprintToMetric index DB: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  p . archivedFingerprintToTimeRange . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										lastError  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "Error closing archivedFingerprintToTimeRange index DB: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  p . labelPairToFingerprints . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										lastError  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "Error closing labelPairToFingerprints index DB: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-16 21:47:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  p . labelNameToLabelValues . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										lastError  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "Error closing labelNameToLabelValues index DB: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  lastError  ==  nil  &&  ! p . isDirty ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-14 23:52:09 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										dirtyFileRemoveError  =  os . Remove ( p . dirtyFileName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  p . fLock . Release ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										lastError  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "Error releasing file lock: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  dirtyFileRemoveError  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// On Windows, removing the dirty file before unlocking is not
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// possible.  So remove it here if it failed above.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										lastError  =  os . Remove ( p . dirtyFileName ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-06 03:02:45 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  lastError 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  dirNameForFingerprint ( fp  clientmodel . Fingerprint )  string  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									fpStr  :=  fp . String ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  path . Join ( p . basePath ,  fpStr [ 0 : seriesDirNameLen ] ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  fileNameForFingerprint ( fp  clientmodel . Fingerprint )  string  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fpStr  :=  fp . String ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  path . Join ( p . basePath ,  fpStr [ 0 : seriesDirNameLen ] ,  fpStr [ seriesDirNameLen : ] + seriesFileSuffix ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  tempFileNameForFingerprint ( fp  clientmodel . Fingerprint )  string  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fpStr  :=  fp . String ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-11-21 04:03:51 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  path . Join ( p . basePath ,  fpStr [ 0 : seriesDirNameLen ] ,  fpStr [ seriesDirNameLen : ] + seriesTempFileSuffix ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  openChunkFileForWriting ( fp  clientmodel . Fingerprint )  ( * os . File ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  os . MkdirAll ( p . dirNameForFingerprint ( fp ) ,  0700 ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-26 20:48:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  os . OpenFile ( p . fileNameForFingerprint ( fp ) ,  os . O_WRONLY | os . O_APPEND | os . O_CREATE ,  0640 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// NOTE: Although the file was opened for append,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									//     f.Seek(0, os.SEEK_CUR)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// would now return '0, nil', so we cannot check for a consistent file length right now.
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// However, the chunkIndexForOffset function is doing that check, so a wrong file length
 
							 
						 
					
						
							
								
									
										
										
										
											2015-01-26 20:48:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// would still be detected.
 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:54:59 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// closeChunkFile first syncs the provided file if mandated so by the sync
 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// strategy. Then it closes the file. Errors are logged.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  closeChunkFile ( f  * os . File )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  p . shouldSync ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  f . Sync ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:54:59 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											glog . Error ( "Error syncing file:" ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-19 22:41:50 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  f . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										glog . Error ( "Error closing chunk file:" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  openChunkFileForReading ( fp  clientmodel . Fingerprint )  ( * os . File ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-15 23:07:12 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  os . Open ( p . fileNameForFingerprint ( fp ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  headsFileName ( )  string  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-11 00:41:52 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  path . Join ( p . basePath ,  headsFileName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-25 02:27:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  headsTempFileName ( )  string  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  path . Join ( p . basePath ,  headsTempFileName ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-10-08 01:11:24 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( p  * persistence )  processIndexingQueue ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									batchSize  :=  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									nameToValues  :=  index . LabelNameLabelValuesMapping { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									pairToFPs  :=  index . LabelPairFingerprintsMapping { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									batchTimeout  :=  time . NewTimer ( indexingBatchTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									defer  batchTimeout . Stop ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									commitBatch  :=  func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										p . indexingBatchSizes . Observe ( float64 ( batchSize ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 23:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										defer  func ( begin  time . Time )  { 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-20 00:06:16 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											p . indexingBatchDuration . Observe ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												float64 ( time . Since ( begin ) )  /  float64 ( time . Millisecond ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 23:18:48 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} ( time . Now ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 22:51:18 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  :=  p . labelPairToFingerprints . IndexBatch ( pairToFPs ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											glog . Error ( "Error indexing label pair to fingerprints batch: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  p . labelNameToLabelValues . IndexBatch ( nameToValues ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											glog . Error ( "Error indexing label name to label values batch: " ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										batchSize  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										nameToValues  =  index . LabelNameLabelValuesMapping { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										pairToFPs  =  index . LabelPairFingerprintsMapping { } 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										batchTimeout . Reset ( indexingBatchTimeout ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  flush  chan  chan  int 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								loop : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										// Only process flush requests if the queue is currently empty.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  len ( p . indexingQueue )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											flush  =  p . indexingFlush 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											flush  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  <- batchTimeout . C : 
							 
						 
					
						
							
								
									
										
										
										
											2014-10-17 19:55:54 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											// Only commit if we have something to commit _and_
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// nothing is waiting in the queue to be picked up. That
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// prevents a death spiral if the LookupSet calls below
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// are slow for some reason.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  batchSize  >  0  &&  len ( p . indexingQueue )  ==  0  { 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												commitBatch ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												batchTimeout . Reset ( indexingBatchTimeout ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  r  :=  <- flush : 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  batchSize  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												commitBatch ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 20:41:38 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											r  <-  len ( p . indexingQueue ) 
							 
						 
					
						
							
								
									
										
										
										
											2014-09-24 01:21:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										case  op ,  ok  :=  <- p . indexingQueue : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  batchSize  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													commitBatch ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												break  loop 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											batchSize ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											for  ln ,  lv  :=  range  op . metric  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												lp  :=  metric . LabelPair { Name :  ln ,  Value :  lv } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												baseFPs ,  ok  :=  pairToFPs [ lp ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													baseFPs ,  _ ,  err  =  p . labelPairToFingerprints . LookupSet ( lp ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														glog . Errorf ( "Error looking up label pair %v: %s" ,  lp ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													pairToFPs [ lp ]  =  baseFPs 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												baseValues ,  ok  :=  nameToValues [ ln ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													baseValues ,  _ ,  err  =  p . labelNameToLabelValues . LookupSet ( ln ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														glog . Errorf ( "Error looking up label name %v: %s" ,  ln ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													nameToValues [ ln ]  =  baseValues 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												switch  op . opType  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												case  add : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													baseFPs [ op . fingerprint ]  =  struct { } { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													baseValues [ lv ]  =  struct { } { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												case  remove : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													delete ( baseFPs ,  op . fingerprint ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													if  len ( baseFPs )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
														delete ( baseValues ,  lv ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													panic ( "unknown op type" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  batchSize  >=  indexingMaxBatchSize  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												commitBatch ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									close ( p . indexingStopped ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2015-03-09 09:33:10 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  offsetForChunkIndex ( i  int )  int64  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  int64 ( i  *  ( chunkHeaderLen  +  chunkLen ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  chunkIndexForOffset ( offset  int64 )  ( int ,  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  int ( offset ) % ( chunkHeaderLen + chunkLen )  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  - 1 ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"offset %d is not a multiple of on-disk chunk length %d" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											offset ,  chunkHeaderLen + chunkLen , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  int ( offset )  /  ( chunkHeaderLen  +  chunkLen ) ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  writeChunkHeader ( w  io . Writer ,  c  chunk )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									header  :=  make ( [ ] byte ,  chunkHeaderLen ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									header [ chunkHeaderTypeOffset ]  =  byte ( c . encoding ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									binary . LittleEndian . PutUint64 ( header [ chunkHeaderFirstTimeOffset : ] ,  uint64 ( c . firstTime ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									binary . LittleEndian . PutUint64 ( header [ chunkHeaderLastTimeOffset : ] ,  uint64 ( c . lastTime ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									_ ,  err  :=  w . Write ( header ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  writeChunks ( w  io . Writer ,  chunks  [ ] chunk )  error  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									b  :=  bufio . NewWriterSize ( w ,  len ( chunks ) * ( chunkHeaderLen + chunkLen ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  chunk  :=  range  chunks  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  writeChunkHeader ( b ,  chunk ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  :=  chunk . marshal ( b ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  b . Flush ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}