// initIndexPartitions first attempts to initialize the index partitions using the partition map document in
// the index bucket.  If that hasn't been created yet, tries to generate the partition information from CBGT.
// If unsuccessful on both of these, returns error and leaves k.indexPartitions as nil.
func (k *kvChangeIndex) initIndexPartitions() (*base.IndexPartitions, error) {

	k.indexPartitionsLock.Lock()
	defer k.indexPartitionsLock.Unlock()

	// Check if it's been initialized while we waited for the lock
	if k.indexPartitions != nil {
		return k.indexPartitions, nil
	}

	// First attempt to load from the bucket
	partitionDef, err := k.loadIndexPartitionsFromBucket()
	if err != nil {
		return nil, err
	}

	indexExpvars.Add("get_indexPartitionMap", 1)
	// If unable to load from index bucket - attempt to initialize based on cbgt partitions
	if partitionDef == nil {
		partitionDef, err = k.retrieveCBGTPartitions()
		if err != nil {
			return nil, errors.New(fmt.Sprintf("Unable to determine partition map for index - not found in index, and not available from cbgt: %v", err))
		}
		// Add to the bucket
		value, err := json.Marshal(partitionDef)
		if err != nil {
			return nil, err
		}
		added, err := k.reader.indexReadBucket.AddRaw(base.KIndexPartitionKey, 0, value)
		if err != nil {
			return nil, err
		}
		// If add fails, it may have been written by another node since the last read attempt.  Make
		// another attempt to use the version from the bucket, to ensure consistency.
		if added == false {
			partitionDef, err = k.loadIndexPartitionsFromBucket()
			if err != nil {
				return nil, err
			}
		}
	}

	// Create k.indexPartitions based on partitionDef
	k.indexPartitions = base.NewIndexPartitions(partitionDef)
	return k.indexPartitions, nil
}
func testPartitionMap() *base.IndexPartitions {

	partitions := make([]base.PartitionStorage, 64)

	numPartitions := uint16(64)
	vbPerPartition := 1024 / numPartitions
	for partition := uint16(0); partition < numPartitions; partition++ {
		pStorage := base.PartitionStorage{
			Index: partition,
			Uuid:  fmt.Sprintf("partition_%d", partition),
			VbNos: make([]uint16, vbPerPartition),
		}
		for index := uint16(0); index < vbPerPartition; index++ {
			vb := partition*vbPerPartition + index
			pStorage.VbNos[index] = vb
		}
		partitions[partition] = pStorage
	}

	indexPartitions := base.NewIndexPartitions(partitions)
	return indexPartitions
}
func (k *kvChangeIndex) initIndexPartitions() (*base.IndexPartitions, error) {

	k.indexPartitionsLock.Lock()
	defer k.indexPartitionsLock.Unlock()

	// Check if it's been initialized while we waited for the lock
	if k.indexPartitions != nil {
		return k.indexPartitions, nil
	}

	var partitionDef []base.PartitionStorage
	// First attempt to load from the bucket
	value, _, err := k.reader.indexReadBucket.GetRaw(base.KIndexPartitionKey)
	indexExpvars.Add("get_indexPartitionMap", 1)
	if err == nil {
		if err = json.Unmarshal(value, &partitionDef); err != nil {
			return nil, err
		}
	}

	// If unable to load from index bucket - attempt to initialize based on cbgt partitions
	if partitionDef == nil {
		var manager *cbgt.Manager
		if k.context != nil {
			manager = k.context.BucketSpec.CbgtContext.Manager
		} else {
			return nil, errors.New("Unable to determine partition map for index - not found in index, and no database context")
		}

		if manager == nil {
			return nil, errors.New("Unable to determine partition map for index - not found in index, and no CBGT manager")
		}

		_, planPIndexesByName, _ := manager.GetPlanPIndexes(true)
		indexName := k.context.GetCBGTIndexNameForBucket(k.context.Bucket)
		pindexes := planPIndexesByName[indexName]

		for index, pIndex := range pindexes {
			vbStrings := strings.Split(pIndex.SourcePartitions, ",")
			// convert string vbNos to uint16
			vbNos := make([]uint16, len(vbStrings))
			for i := 0; i < len(vbStrings); i++ {
				vbNumber, err := strconv.ParseUint(vbStrings[i], 10, 16)
				if err != nil {
					base.LogFatal("Error creating index partition definition - unable to parse vbucket number %s as integer:%v", vbStrings[i], err)
				}
				vbNos[i] = uint16(vbNumber)
			}
			entry := base.PartitionStorage{
				Index: uint16(index),
				Uuid:  pIndex.UUID,
				VbNos: vbNos,
			}
			partitionDef = append(partitionDef, entry)
		}

		// Persist to bucket
		value, err = json.Marshal(partitionDef)
		if err != nil {
			return nil, err
		}
		k.reader.indexReadBucket.SetRaw(base.KIndexPartitionKey, 0, value)
	}

	// Create k.indexPartitions based on partitionDef
	k.indexPartitions = base.NewIndexPartitions(partitionDef)
	return k.indexPartitions, nil
}