Exemple #1
0
//
// TODO: This function is not transactional.
//
func (c *MetadataRepo) CreateIndex(defn *common.IndexDefn) error {

	// check if defn already exist
	exist, err := c.GetIndexDefnById(defn.DefnId)
	if exist != nil {
		// TODO: should not return error if not found (should return nil)
		return NewError(ERROR_META_IDX_DEFN_EXIST, NORMAL, METADATA_REPO, nil,
			fmt.Sprintf("Index Definition '%s' already exist", defn.Name))
	}

	// marshall the defn
	data, err := common.MarshallIndexDefn(defn)
	if err != nil {
		return err
	}

	// save by defn id
	lookupName := indexDefnKeyById(defn.DefnId)
	if err := c.setMeta(lookupName, data); err != nil {
		return err
	}

	c.mutex.Lock()
	defer c.mutex.Unlock()

	c.defnCache[defn.DefnId] = defn

	return nil
}
Exemple #2
0
//
// Handle Create Index DDL.  This function will block until
// 1) The index defn is persisted durably in the dictionary
// 2) The index defn is applied locally to each "active" indexer
//    node.  An active node is a running node that is in the same
//    network partition as the leader.   A leader is always in
//    the majority partition.
//
// This function will return an error if the outcome of the
// request is not known (e.g. the node is partitioned
// from the network).  It may still mean that the request
// is able to go through (processed by some other nodes).
//
// A Index DDL can be processed by any node. If this node is a leader,
// then the DDL request will be processed by the leader.  If it is a
// follower, it will forward the request to the leader.
//
// This function will not be processed until the index manager
// is either a leader or follower. Therefore, if (1) the node is
// in the minority partition after network partition or (2) the leader
// dies, this node will unblock any in-flight request initiated
// by this node (by returning error).  The node will run leader
// election again. Until this node has became a leader or follower,
// it will not be able to handle another request.
//
// If this node is partitioned from its leader, it can still recieve
// updates from the dictionary if this node still connects to it.
//
func (m *IndexManager) HandleCreateIndexDDL(defn *common.IndexDefn) error {

	key := fmt.Sprintf("%d", defn.DefnId)
	content, err := common.MarshallIndexDefn(defn)
	if err != nil {
		return err
	}

	if USE_MASTER_REPO {
		if !m.coordinator.NewRequest(uint32(OPCODE_ADD_IDX_DEFN), indexDefnIdStr(defn.DefnId), content) {
			// TODO: double check if it exists in the dictionary
			return NewError(ERROR_MGR_DDL_CREATE_IDX, NORMAL, INDEX_MANAGER, nil,
				fmt.Sprintf("Fail to complete processing create index statement for index '%s'", defn.Name))
		}
	} else {
		return m.requestServer.MakeRequest(client.OPCODE_CREATE_INDEX, key, content)
	}

	return nil
}
Exemple #3
0
func (o *MetadataProvider) CreateIndexWithPlan(
	name, bucket, using, exprType, partnExpr, whereExpr string,
	secExprs []string, isPrimary bool, plan map[string]interface{}) (c.IndexDefnId, error, bool) {

	// FindIndexByName will only return valid index
	if o.FindIndexByName(name, bucket) != nil {
		return c.IndexDefnId(0), errors.New(fmt.Sprintf("Index %s already exist.", name)), false
	}

	var deferred bool = false
	var wait bool = true
	var nodes []string = nil

	if plan != nil {
		logging.Debugf("MetadataProvider:CreateIndexWithPlan(): plan %v", plan)

		ns, ok := plan["nodes"].([]interface{})
		if ok {
			if len(ns) != 1 {
				return c.IndexDefnId(0), errors.New("Create Index is allowed for one and only one node"), false
			}
			n, ok := ns[0].(string)
			if ok {
				nodes = []string{n}
			} else {
				return c.IndexDefnId(0),
					errors.New(fmt.Sprintf("Fails to create index.  Node '%v' is not valid", plan["nodes"])),
					false
			}
		} else {
			n, ok := plan["nodes"].(string)
			if ok {
				nodes = []string{n}
			} else if _, ok := plan["nodes"]; ok {
				return c.IndexDefnId(0),
					errors.New(fmt.Sprintf("Fails to create index.  Node '%v' is not valid", plan["nodes"])),
					false
			}
		}

		deferred2, ok := plan["defer_build"].(bool)
		if !ok {
			deferred_str, ok := plan["defer_build"].(string)
			if ok {
				var err error
				deferred2, err = strconv.ParseBool(deferred_str)
				if err != nil {
					return c.IndexDefnId(0),
						errors.New("Fails to create index.  Parameter defer_build must be a boolean value of (true or false)."),
						false
				}
				deferred = deferred2
				wait = !deferred

			} else if _, ok := plan["defer_build"]; ok {
				return c.IndexDefnId(0),
					errors.New("Fails to create index.  Parameter defer_build must be a boolean value of (true or false)."),
					false
			}
		} else {
			deferred = deferred2
			wait = !deferred
		}
	}

	logging.Debugf("MetadataProvider:CreateIndex(): deferred_build %v sync %v nodes %v", deferred, wait, nodes)

	watcher, err, retry := o.findWatcherWithRetry(nodes)
	if err != nil {
		return c.IndexDefnId(0), err, retry
	}

	// set the node list using indexerId
	nodes = []string{string(watcher.getIndexerId())}

	defnID, err := c.NewIndexDefnId()
	if err != nil {
		return c.IndexDefnId(0),
			errors.New(fmt.Sprintf("Fails to create index. Fail to create uuid for index definition.")),
			false
	}

	idxDefn := &c.IndexDefn{
		DefnId:          defnID,
		Name:            name,
		Using:           c.IndexType(using),
		Bucket:          bucket,
		IsPrimary:       isPrimary,
		SecExprs:        secExprs,
		ExprType:        c.ExprType(exprType),
		PartitionScheme: c.SINGLE,
		PartitionKey:    partnExpr,
		WhereExpr:       whereExpr,
		Deferred:        deferred,
		Nodes:           nodes}

	content, err := c.MarshallIndexDefn(idxDefn)
	if err != nil {
		return 0, err, false
	}

	key := fmt.Sprintf("%d", defnID)
	if _, err = watcher.makeRequest(OPCODE_CREATE_INDEX, key, content); err != nil {
		return defnID, err, false
	}

	if wait {
		err := watcher.waitForEvent(defnID, []c.IndexState{c.INDEX_STATE_ACTIVE, c.INDEX_STATE_DELETED})
		return defnID, err, false
	}

	return defnID, nil, false
}