// // 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 }
// // 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 }
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 }