Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server/region_handler: txn debug tool for tikv #3787

Merged
merged 38 commits into from
Jul 28, 2017
Merged

Conversation

AndreMouche
Copy link
Contributor

Hi,
This PR implement two API for txn debug:
1. Get MvccInfo BY Key GET /mvcc/key/{db}/{table}/{recordID}
2. Get Primary's MvccInfo by start_ts /mvcc/txn/{startTS}/{db}/{table} / /mvcc/txn/{startTS}

@disksing @hhkbp2 PTAL

startKey = codec.EncodeBytes(nil, tableStartKey)
endKey = codec.EncodeBytes(nil, tableEndKey)
startKey = EncodeRowKeyWithHandle(tableID, math.MinInt64)
endKey = EncodeRowKeyWithHandle(tableID, math.MaxInt64)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to update table codec?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since when use a codecPDClient instead of pd.Client in regionHandler, there is no need to use codec.EncodeBytes again. And this function will only be used in regionHandler

info.Writes = make([]*kvrpcpb.WriteInfo, len(e.values), len(e.values))
info.Values = make([]*kvrpcpb.ValueInfo, len(e.values), len(e.values))

for id, item := range e.values {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id -> i

}
}

info.Writes = make([]*kvrpcpb.WriteInfo, len(e.values), len(e.values))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info.Writes = make([]*kvrpcpb.WriteInfo, len(e.values))

tp = kvrpcpb.Op_Del
case typeRollback:
tp = kvrpcpb.Op_Rollback
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's more clear to list all values in switch-case:

var tp mvccValueType
switch item.valueType {
case typePut:
case typeDelete:
case typeRollback:
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address comment

@@ -547,6 +598,35 @@ func (s *MvccStore) RawScan(startKey, endKey []byte, limit int) []Pair {
return pairs
}

// MvccGetByStartTS gets mvcc info for the primary key with startTS
func (s MvccStore) MvccGetByStartTS(starTS uint64) *kvrpcpb.MvccInfo {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to add startKey and endKey arguments to restrict the method in a single region.

"encoding/json"
"fmt"
"math"
"net/http"

"bytes"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not in good order.


const (
opMvccGetByKey = "key"
opMvccGetByTXN = "txn"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use Txn instead of TXN.

}

func (rh TableRegionsHandler) getRegionsMeta(regionIDs []uint64) ([]RegionMeta, error) {
func (tool *regionHandlerTool) getRegionsMeta(regionIDs []uint64) ([]RegionMeta, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually use t instead of tool.

@shenli
Copy link
Member

shenli commented Jul 19, 2017

@disksing PTAL

@AndreMouche
Copy link
Contributor Author

@hhkbp2 @disksing PTAL

return rh.getMvccByRecordID(tableID, recordID)
}

func (rh *mvccTxnHandler) handleMvccGetByTXN(params map[string]string) (interface{}, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TXN -> Txn.


tikvReq := &tikvrpc.Request{
Type: tikvrpc.CmdMvccGetByStartTs,
Priority: kvrpcpb.CommandPri_Normal,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Low? We don't want debug commands slow down normal ones.

},
}
kvResp, err := t.store.SendReq(t.bo, tikvReq, curRegion.Region, time.Hour)
log.Info(startTS, string(startKey), curRegion.Region, string(curRegion.StartKey), string(curRegion.EndKey), kvResp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forget to remove the debug message?

Copy link
Contributor Author

@AndreMouche AndreMouche Jul 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No , it's used to show the process imformation @disksing

c.Assert(len(data.Info.Writes) > 0, IsTrue)
startTs := data.Info.Writes[0].StartTs

resp, err = http.Get(fmt.Sprintf("http://127.0.0.1:10090/mvcc/txn/%d", startTs))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test that the ts doesn't exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

address comments

@disksing
Copy link
Contributor

LGTM.

@disksing disksing added the status/LGT1 Indicates that a PR has LGTM 1. label Jul 20, 2017
)

// prepare checks and prepares for region request. It returns
// regionHandlerTool on success while return an err on any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while returns an error if any error happens.

return
}

store := s.driver.(*TiDBDriver).store
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Frankly speaking, those kind of logic is vulnerable, if the implementation change one day, we got a panic here.

Copy link
Contributor Author

@AndreMouche AndreMouche Jul 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestion @tiancaiamao ?

}

type regionHandlerTool struct {
bo *tikv.Backoffer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why store backoffer rather than pass it as argument?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean?The regionHanderTool is used to generate and store common tools for each regionHander. I set the backoffer as a member of the tool since more than one regionHander needed it @tiancaiamao

js, err := json.Marshal(data)
if err != nil {
rh.writeError(w, err)
return
}
log.Info(string(js))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only in this debug tool, we needed it. @tiancaiamao

router.Handle("/regions/{regionID}", s.newRegionHandler(pdClient))

tikvHandler, err := s.newRegionHandler()
if err == nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log an error or fatal for error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the error won't be nil when the store is not tikv, I think it's more appropriate to log an info here @siddontang .

ts.startServer(c)
ts.prepareData(c)
defer ts.stopServer(c)
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:10090/mvcc/key/tidb/test/1"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why use a fixed port 10090 here? It is better to listen 0 and get a random port for the test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's referenced on tidb_test.go. And I'm not pretty sure that whether we should keep same with it. @siddontang

if !ok {
err = fmt.Errorf("Invalid KvStore")
return
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you shouldn't return a "Invalid KvStore" when driver assert failed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe like this?

    if store, ok := s.driver.(*TiDBDriver); !ok {
        err = fmt.Errorf("Invalid Driver")
    } else {
        if tikvStore, ok = store.store.(kvStore); !ok {
            err = fmt.Errorf("Invalid kvStore")
        }
    }
    if err != nil {
        return
    }

tikvStore, ok = store.store.(kvStore)
}
if !ok {
err = fmt.Errorf("Invalid KvStore")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use errors.New instead

err = decoder.Decode(&data)
c.Assert(err, IsNil)
c.Assert(data.Info, NotNil)
c.Assert(len(data.Info.Writes) > 0, IsTrue)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c.Assert(len(data.Info.Writes), Larger, 0)

@AndreMouche
Copy link
Contributor Author

tikvStore, ok = store.store.(kvStore)
}
if !ok {
err = errors.New("Invalid KvStore")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different error kind for invalid kvstore and invalid driver

}

if tikvStore, ok = store.store.(kvStore); !ok {
log.Fatal("Invalid KvStore with illegal store")
Copy link
Contributor

@choleraehyq choleraehyq Jul 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use log.Fatal instead of returning an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this error should never happen. And if it failed there must some unrecoverable disaster happened @choleraehyq

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, why not just panic?
There is little reason to use log.Fatal. It call os.Exit behind, which will exit immediately without calling deferred functions, which may lead to resource leaking or something. Also, it doesn't print out the calling stack.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the return after log.Fatal is redundent.

@AndreMouche
Copy link
Contributor Author

Copy link
Contributor

@zhangjinpeng87 zhangjinpeng87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@AndreMouche AndreMouche merged commit 5308024 into master Jul 28, 2017
@AndreMouche AndreMouche deleted the shirly/txn_tool branch July 28, 2017 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/LGT1 Indicates that a PR has LGTM 1.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants