Ejemplo n.º 1
0
// Write the result of an action into topology server
func StoreActionResponse(ts topo.Server, actionNode *ActionNode, actionPath string, actionErr error) error {
	// change our state
	if actionErr != nil {
		// on failure, set an error field on the node
		actionNode.Error = actionErr.Error()
		actionNode.State = ACTION_STATE_FAILED
	} else {
		actionNode.Error = ""
		actionNode.State = ACTION_STATE_DONE
	}
	actionNode.Pid = 0

	// Write the data first to our action node, then to the log.
	// In the error case, this node will be left behind to debug.
	data := ActionNodeToJson(actionNode)
	return ts.StoreTabletActionResponse(actionPath, data)
}
Ejemplo n.º 2
0
func CheckActions(t *testing.T, ts topo.Server) {
	cell := getLocalCell(t, ts)
	tablet := &topo.Tablet{
		Alias:    topo.TabletAlias{Cell: cell, Uid: 1},
		Hostname: "localhost",
		IPAddr:   "10.11.12.13",
		Portmap: map[string]int{
			"vt":    3333,
			"mysql": 3334,
		},
		Parent:   topo.TabletAlias{},
		Keyspace: "test_keyspace",
		Type:     topo.TYPE_MASTER,
		State:    topo.STATE_READ_WRITE,
		KeyRange: newKeyRange("-10"),
	}
	if err := ts.CreateTablet(tablet); err != nil {
		t.Fatalf("CreateTablet: %v", err)
	}
	tabletAlias := topo.TabletAlias{Cell: cell, Uid: 1}

	actionPath, err := ts.WriteTabletAction(tabletAlias, "contents1")
	if err != nil {
		t.Fatalf("WriteTabletAction: %v", err)
	}

	interrupted := make(chan struct{}, 1)
	if _, err := ts.WaitForTabletAction(actionPath, time.Second/100, interrupted); err != topo.ErrTimeout {
		t.Errorf("WaitForTabletAction returned %v", err)
	}
	go func() {
		time.Sleep(time.Second / 10)
		close(interrupted)
	}()
	if _, err := ts.WaitForTabletAction(actionPath, time.Second*5, interrupted); err != topo.ErrInterrupted {
		t.Errorf("WaitForTabletAction returned %v", err)
	}

	// wait for the result in one thread
	wg1 := sync.WaitGroup{}
	wg1.Add(1)
	go func() {
		defer wg1.Done()
		interrupted := make(chan struct{}, 1)
		var err error
		for i := 0; i <= 30; i++ {
			var result string
			result, err = ts.WaitForTabletAction(actionPath, time.Second, interrupted)
			if err == topo.ErrTimeout {
				// we waited for one second, didn't see the
				// result, try again up to 30 seconds.
				t.Logf("WaitForTabletAction timed out at try %v/30", i)
				continue
			}
			if err != nil {
				t.Errorf("WaitForTabletAction returned: %v", err)
			}
			if result != "contents3" {
				t.Errorf("WaitForTabletAction returned bad result: %v", result)
			}
			return
		}
		t.Errorf("WaitForTabletAction timed out: %v", err)
	}()

	// process the action in another thread
	done := make(chan struct{}, 1)
	wg2 := sync.WaitGroup{}
	wg2.Add(1)
	go ts.ActionEventLoop(tabletAlias, func(ap, data string) error {
		// the actionPath sent back to the action processor
		// is the exact one we have in normal cases,
		// but for the tee, we add extra information.
		if ap != actionPath && !strings.HasSuffix(ap, actionPath) {
			t.Errorf("Bad action path: %v", ap)
		}
		if data != "contents1" {
			t.Errorf("Bad data: %v", data)
		}
		ta, contents, version, err := ts.ReadTabletActionPath(ap)
		if err != nil {
			t.Errorf("Error from ReadTabletActionPath: %v", err)
		}
		if contents != data {
			t.Errorf("Bad contents: %v", contents)
		}
		if ta != tabletAlias {
			t.Errorf("Bad tablet alias: %v", ta)
		}

		if err := ts.UpdateTabletAction(ap, "contents2", version); err != nil {
			t.Errorf("UpdateTabletAction failed: %v", err)
		}
		if err := ts.StoreTabletActionResponse(ap, "contents3"); err != nil {
			t.Errorf("StoreTabletActionResponse failed: %v", err)
		}
		if err := ts.UnblockTabletAction(ap); err != nil {
			t.Errorf("UnblockTabletAction failed: %v", err)
		}

		wg2.Done()
		return nil
	}, done)

	// first wait for the processing to be done, then close the
	// action loop, then wait for the response to be received.
	wg2.Wait()
	close(done)
	wg1.Wait()

	// start an action, and try to purge all actions, to test
	// PurgeTabletActions
	actionPath, err = ts.WriteTabletAction(tabletAlias, "contents2")
	if err != nil {
		t.Fatalf("WriteTabletAction(contents2): %v", err)
	}
	if err := ts.PurgeTabletActions(tabletAlias, func(data string) bool {
		return true
	}); err != nil {
		t.Fatalf("PurgeTabletActions(contents2) failed: %v", err)
	}
	if _, _, _, err := ts.ReadTabletActionPath(actionPath); err != topo.ErrNoNode {
		t.Fatalf("ReadTabletActionPath(contents2) should have failed with ErrNoNode: %v", err)
	}
}
Ejemplo n.º 3
0
func CheckActions(t *testing.T, ts topo.Server) {
	cell := getLocalCell(t, ts)
	tablet := &topo.Tablet{
		Cell:     cell,
		Uid:      1,
		Parent:   topo.TabletAlias{},
		Addr:     "localhost:3333",
		Keyspace: "test_keyspace",
		Type:     topo.TYPE_MASTER,
		State:    topo.STATE_READ_WRITE,
		KeyRange: newKeyRange("-10"),
	}
	if err := ts.CreateTablet(tablet); err != nil {
		t.Fatalf("CreateTablet: %v", err)
	}
	tabletAlias := topo.TabletAlias{cell, 1}

	actionPath, err := ts.WriteTabletAction(tabletAlias, "contents1")
	if err != nil {
		t.Fatalf("WriteTabletAction: %v", err)
	}

	interrupted := make(chan struct{}, 1)
	if _, err := ts.WaitForTabletAction(actionPath, time.Second/100, interrupted); err != topo.ErrTimeout {
		t.Errorf("WaitForTabletAction returned %v", err)
	}
	go func() {
		time.Sleep(time.Second / 10)
		close(interrupted)
	}()
	if _, err := ts.WaitForTabletAction(actionPath, time.Second*5, interrupted); err != topo.ErrInterrupted {
		t.Errorf("WaitForTabletAction returned %v", err)
	}

	wg := sync.WaitGroup{}

	// wait for the result in one thread
	wg.Add(1)
	go func() {
		interrupted := make(chan struct{}, 1)
		result, err := ts.WaitForTabletAction(actionPath, time.Second*10, interrupted)
		if err != nil {
			t.Errorf("WaitForTabletAction returned %v", err)
		}
		if result != "contents3" {
			t.Errorf("WaitForTabletAction returned bad result: %v", result)
		}
		wg.Done()
	}()

	// process the action in another thread
	done := make(chan struct{}, 1)
	wg.Add(1)
	go ts.ActionEventLoop(tabletAlias, func(ap, data string) error {
		// the actionPath sent back to the action processor
		// is the exact one we have in normal cases,
		// but for the tee, we add extra information.
		if ap != actionPath && !strings.HasSuffix(ap, actionPath) {
			t.Errorf("Bad action path: %v", ap)
		}
		if data != "contents1" {
			t.Errorf("Bad data: %v", data)
		}
		ta, contents, version, err := ts.ReadTabletActionPath(ap)
		if err != nil {
			t.Errorf("Error from ReadTabletActionPath: %v", err)
		}
		if contents != data {
			t.Errorf("Bad contents: %v", contents)
		}
		if ta != tabletAlias {
			t.Errorf("Bad tablet alias: %v", ta)
		}

		if err := ts.UpdateTabletAction(ap, "contents2", version); err != nil {
			t.Errorf("UpdateTabletAction failed: %v", err)
		}
		if err := ts.StoreTabletActionResponse(ap, "contents3"); err != nil {
			t.Errorf("StoreTabletActionResponse failed: %v", err)
		}
		if err := ts.UnblockTabletAction(ap); err != nil {
			t.Errorf("UnblockTabletAction failed: %v", err)
		}

		wg.Done()
		return nil
	}, done)
	close(done)
	wg.Wait()
}
Ejemplo n.º 4
0
func CheckLotsOfActions(t *testing.T, ts topo.Server) {
	cell := getLocalCell(t, ts)
	tablet := &topo.Tablet{
		Alias:    topo.TabletAlias{Cell: cell, Uid: 1},
		Hostname: "localhost",
		IPAddr:   "10.11.12.13",
		Portmap: map[string]int{
			"vt":    3333,
			"mysql": 3334,
		},
		Parent:   topo.TabletAlias{},
		Keyspace: "test_keyspace",
		Type:     topo.TYPE_MASTER,
		State:    topo.STATE_READ_WRITE,
		KeyRange: newKeyRange("-10"),
	}
	if err := ts.CreateTablet(tablet); err != nil {
		t.Fatalf("CreateTablet: %v", err)
	}

	nActions := 64
	paths := make([]string, nActions)

	// write the actions in parallel, save the paths
	writeWG := sync.WaitGroup{}
	for i := 0; i < nActions; i++ {
		writeWG.Add(1)
		go func(i int) {
			var err error
			paths[i], err = ts.WriteTabletAction(tablet.Alias, fmt.Sprintf("contents %v", i))
			if err != nil {
				t.Fatalf("WriteTabletAction(%v): %v", i, err)
			}
			t.Logf("WriteTabletAction(%v) done", i)
			writeWG.Done()
		}(i)
	}
	writeWG.Wait()

	// wait for all actions in parallel
	waitWG := sync.WaitGroup{}
	interrupted := make(chan struct{}, 1)
	for i := 0; i < nActions; i++ {
		waitWG.Add(1)
		go func(i int) {
			if _, err := ts.WaitForTabletAction(paths[i], time.Second*30, interrupted); err != nil {
				t.Fatalf("WaitForTabletAction returned %v", err)
			}
			t.Logf("WaitForTabletAction(%v) done", i)
			waitWG.Done()
		}(i)
	}

	// and unblock them all in parallel
	unblockWG := sync.WaitGroup{}
	for i := 0; i < nActions; i++ {
		unblockWG.Add(1)
		go func(i int) {
			defer unblockWG.Done()
			ta, contents, _, err := ts.ReadTabletActionPath(paths[i])
			if err != nil {
				t.Errorf("Error from ReadTabletActionPath: %v", err)
			}
			t.Logf("ReadTabletActionPath(%v) done", i)
			if contents != fmt.Sprintf("contents %v", i) {
				t.Errorf("Bad contents: %v", contents)
			}
			if ta != tablet.Alias {
				t.Errorf("Bad tablet alias: %v", ta)
			}

			if err := ts.StoreTabletActionResponse(paths[i], fmt.Sprintf("contents after %v", i)); err != nil {
				t.Errorf("StoreTabletActionResponse failed: %v", err)
			}
			t.Logf("StoreTabletActionResponse(%v) done", i)
			if err := ts.UnblockTabletAction(paths[i]); err != nil {
				t.Errorf("UnblockTabletAction failed: %v", err)
			}
			t.Logf("UnblockTabletAction(%v) done", i)
		}(i)
	}
	unblockWG.Wait()

	waitWG.Wait()
}