Pythonã¨Rubyã®ã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªãæ¸ããã®ã§ã次ã¯Goã ãgRPCçéã§ã¯Goããã使ããããããªã®ã§ãåªå 度é«ãã§çæããã詳ãããã¨ã¯API文書ãã覧ããã ãããããç°¡åãªä½¿ãæ¹ãããã§ãç´¹ä»ããã
ä»ã®è¨èªã¨åãããã«ãTkrzwã®C++ã®ã³ã¢ã©ã¤ãã©ãªã«ã¯ä¾åããã«ãgRPCã ãã«ä¾åããããã«ã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªãæ¸ããããã£ã¦ãã¯ã©ã¤ã¢ã³ãå´ã§ã¯Tkrzwã®ã³ã¢ã©ã¤ãã©ãªãã¤ã³ã¹ãã¼ã«ããå¿ è¦ã¯ãªããã¨ã¯ãããåä½ç¢ºèªããã«ã¯Tkrzw-RPCã®ãµã¼ããå¿ è¦ã ããªã®ã§ãTkrzwã¨Tkrzw-RPCã¯æ®éã«make, make installã§ã¤ã³ã¹ãã¼ã«ãã¦ããã¦ããã ããGo moduleã使ãã°ãã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã®ã¤ã³ã¹ãã¼ã«ä½æ¥ã¯å¿ è¦ãªããã¤ã³ãã¼ãæãæ¸ãã ãã§gRPCã¨ã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã¯åæã«ã¤ã³ã¹ãã¼ã«ãããã
ãµã³ãã«ããã°ã©ã ãå®è¡ããåã«ãTkrzw-RPCã®ãµã¼ããç«ã¦ãã以ä¸ã®ã³ãã³ããå®è¡ããã°ãããããã©ã«ãã§ã¯ããã¼ã«ã«ãã¹ãã®1978çªãã¼ãã§ããªã³ã¡ã¢ãªãã¼ã¿ãã¼ã¹ããµã¼ãããããããã°ãã°ãåºåãã¦ãã©ããªå¦çãè¡ããã¦ãããããããããããã¦ãããã
$ tkrzw_server --log_level debug
æãç°¡åãªãµã³ãã«ããã°ã©ã ã示ãããGoã®mapã¨ã»ã¼åãããã«ä½¿ããã®ãã»ã¼ã«ã¹ãã¤ã³ãã ã
package main import ( "fmt" // ãã®ã¤ã³ãã¼ãæã ãæ¸ãã°åæã«ã¤ã³ã¹ãã¼ã«ããã¦å©ç¨å¯è½ã«ãªã "github.com/estraier/tkrzw-rpc-go" ) func main() { // ãã¼ã¿ãã¼ã¹ãæºåãã dbm := tkrzw_rpc.NewRemoteDBM() dbm.Connect("127.0.0.1:1978", -1) // ã¬ã³ã¼ããæ¸ãè¾¼ã // ãã¼ã¨å¤ã¯æé»çã«ãã¤ãåã«å¤æããã¦ä¿åããã dbm.Set("first", "hop", true) dbm.Set("second", "step", true) dbm.Set("third", "jump", true) // ã¬ã³ã¼ããæ¤ç´¢ãã¦ãå¤ãæååã¨ãã¦åãåºã fmt.Println(dbm.GetStrSimple("first", "*")) fmt.Println(dbm.GetStrSimple("second", "*")) fmt.Println(dbm.GetStrSimple("third", "*")) // ãã¼ã¿ãã¼ã¹å ã®ã¬ã³ã¼ããæ¨ªæçã«åå¾ãã for record := range dbm.EachStr() { fmt.Println(record.Key, record.Value) } // æ¥ç¶ãéãã dbm.Disconnect() }
ããã¡ããè¤éãªãµã³ãã«ã示ããããã¡ãã¡ã¨ã©ã¼ãã§ãã¯ããã£ã¦ãããCompareExchangeMultiã使ã£ã¦ãã¢ãããã¯ãªãã©ã³ã¶ã¯ã·ã§ã³ãå®ç¾ãã¦ãããã¢ãªã¹ã®ã¬ã³ã¼ãã®å¤ã500æ¸ããã¦ãããã®ã¬ã³ã¼ãã®å¤ã500å¢ããã¨ããæä½ãããªã¢ã¼ããããã¢ãããã¯ã«è¡ããã
package main import ( "fmt" "github.com/estraier/tkrzw-rpc-go" ) func main() { // ãã¼ã¿ãã¼ã¹ãæºåãã // ã¿ã¤ã ã¢ã¦ããç§åä½ã§æå®ã§ãã // åæä½ã®æå¦ã¯Statusã¨ãã¦è¿ããããããã®OrDieã¡ã½ããã¯ãã¨ã©ã¼æã«ã®ã¿ // panicãçºçããã // çé¢ç®ãªã¦ã¼ã¹ã±ã¼ã¹ã§ã¯ãä»»æã®ã¨ã©ã¼å¦çãæ¸ãã㨠dbm := tkrzw_rpc.NewRemoteDBM() dbm.Connect("localhost:1978", 10).OrDie() // é å»¶å®è¡ã使ã£ã¦æ¥ç¶ã確å®ã«éãã defer func() { dbm.Disconnect().OrDie() }() // ããã¨ã¢ãªã¹ã®éè¡å£åº§ã表ç¾ãã // é éé¡ã10鲿°ã®æååã¨ãã¦è¡¨ç¾ãã dbm.Set("Bob", 1000, false).OrDie() dbm.Set("Alice", 3000, false).OrDie() // ééå¦çãã¢ãããã¯ã«å®ç¾ãããã©ã³ã¶ã¯ã·ã§ã³ transfer := func(src_key string, dest_key string, amount int64) *tkrzw_rpc.Status { // ééå ã¨ééå ã®ç¾å¨ã®å¤ã調ã¹ã old_src_value := tkrzw_rpc.ToInt(dbm.GetStrSimple(src_key, "0")) old_dest_value := tkrzw_rpc.ToInt(dbm.GetStrSimple(dest_key, "0")) // æ°ããå¤ãè¨ç®ãããééå ã®éé¡ãæ¸ãããééå ã®éé¡ãå¢ãã new_src_value := old_src_value - amount new_dest_value := old_dest_value + amount if new_src_value < 0 { return tkrzw_rpc.NewStatus(tkrzw_rpc.StatusApplicationError, "insufficient value") } // ãã©ã³ã¶ã¯ã·ã§ã³ã®çºè¡åã¨çºè¡å¾ã®æ¡ä»¶ãã¹ã©ã¤ã¹ã¨ãã¦è¡¨ç¾ãã old_records := []tkrzw_rpc.KeyValueStrPair{ {src_key, tkrzw_rpc.ToString(old_src_value)}, {dest_key, tkrzw_rpc.ToString(old_dest_value)}, } new_records := []tkrzw_rpc.KeyValueStrPair{ {src_key, tkrzw_rpc.ToString(new_src_value)}, {dest_key, tkrzw_rpc.ToString(new_dest_value)}, } // ã¢ãããã¯ã«ãã©ã³ã¶ã¯ã·ã§ã³ãå®è¡ãã // äºåæ¡ä»¶ã«åè´ããå ´åãã¤ã¾ãä»ã®ãã©ã³ã¶ã¯ã·ã§ã³ã両å£åº§ã®ç¾å¨ã®é éé¡ã // 夿´ãã¦ããªãå ´åãäºå¾æ¡ä»¶ã®å¤ãè¨å®ããã // äºåæ¡ä»¶ãæºããããªãå ´åã失æãã return dbm.CompareExchangeMultiStr(old_records, new_records) } // ãã©ã³ã¶ã¯ã·ã§ã³ãæåããã¾ã§è©¦è¡ãã var status *tkrzw_rpc.Status for num_tries := 0; num_tries < 100; num_tries++ { status = transfer("Alice", "Bob", 500) if !status.Equals(tkrzw_rpc.StatusInfeasibleError) { break } } status.OrDie() // ã¤ãã¬ã¼ã¿ã使ã£ã¦ãå ¨ã¦ã®å£åº§ã®æ å ±ãå°åãã iter := dbm.MakeIterator() defer iter.Destruct() iter.First() for { key, value, status := iter.GetStr() if !status.IsOK() { break } fmt.Println(key, value) iter.Next() } }
ãããªããã§ãTkrzwã®ãã¼ã«ã«ã®APIã¨ã»ã¼åãä½¿ç¨æã«ãªã£ã¦ããããå®éãOpen/Closeã®ä»£ããã«Connect/Disconnectã«ãªã£ã¦ãããã¨ä»¥å¤ã¯å ¨ãåãã ããããã¯ã¼ã¯ããã°ã©ãã³ã°ããã¦ããæããã»ã¨ãã©ã³ã¼ãã«ç¾ãããä½ãªããã¼ã¿ãã¼ã¹ãæ±ã£ã¦ããæãããããªãã¨ããã®ãè¯ãæãã§ã¯ãªããã
Pythonã¨Rubyã«æ¯ã¹ãã¨ãgRPCã®å®è£ ã¯ã ãã¶ãããããã£ããç¹ã«ã¹ããªã¼ã ã®å®è£ ãæ¥½ã ã£ããPythonã¨Rubyã§ã¯ã¤ãã¬ã¼ã¿ãã¹ããªã¼ã ã«æ¸¡ãAPIã«ãªã£ã¦ããã®ã ãããããã¤ã³ã¿ã©ã¯ãã£ãã«æ±ãã®ãæ¬å½ã«é¢åãããã®ã ãGoã®å ´åã¯ã¹ããªã¼ã ã®å ¥åºåå¦çãæç¤ºçã«æ¸ããã®ã§ã楽ã ã£ãã
ã¨ããã§ãgRPCã®ã¯ã©ã¤ã¢ã³ãã©ã¤ãã©ãªã¯ãæ¥ç¶æã«ãã£ã³ãã«ãä½ã£ãã ãã§ã¯ã¨ã©ã¼ãã§ãã¯ãããªããããã¯Goã«éãããC++ã§ãPythonã§ãRubyã§ãä¸ç·ã ããµã¼ããæ»ãã¦ããå ´åã«ã¯ãæåã®RPCã³ã¼ã«ãéã£ãæã«ãããæ¤åºããããå¤ãã®å ´åãããã¯æã¾ããåä½ã§ã¯ãªããè¨èªã«ãã£ã¦ã¯ããã£ã³ãã«çææã«æ¥ç¶ã確ç«ããã¾ã§ãããã¯ããã¨ãããªãã·ã§ã³ãããããããã¯ã¨ã©ã¼æã®å試è¡ãå»¶ã ã¨è¡ã£ã¦ãããããããµã¼ããæ»ãã§ãããã¨ããã¤ã¾ã§ãæ¤åºã§ããªãããã®æåãã大æµã®ãªã³ã©ã¤ã³ã·ã¹ãã ã§ã¯è¨±å®¹ã§ããªãã ããã
ãããããã£ã³ãã«ã®ç¶æ é·ç§»ãç£è¦ããæ©è½ãæä¾ããã¦ããã®ã§ãããã使ãã¨ããµã¼ãã®ã¨ã©ã¼ãå³åº§ã«æ¤åºã§ãããå ·ä½çå± ã¯ã以ä¸ã®ãããªã³ã¼ãã§ããã
// ãã£ã³ãã«ãä½ã conn, err := grpc.Dial(address, grpc.WithInsecure()) if err != nil { return NewStatus2(StatusNetworkError, strGRPCError(err)) } // 0.1ç§æ¯ã«3åã ãç¶æ é·ç§»ãç£è¦ããããã§ãæ¥ç¶ã§ããªããã°æãã maxFailures := 3 numFailures := 0 for { // ç¾å¨ã®ç¶æ ãè¦ã¦ãæ¥ç¶ã§ãã¦ããã°æãã state := conn.GetState() if state == connectivity.Ready { break } if state == connectivity.Idle && numFailures > 0 { // Idleç¶æ ã§ããã¤ä¸åº¦ã§ãTransientFailureã«ãªã£ããã¨ãããã°ãã¨ã©ã¼ã¨ã¿ãªã // ã¨ã©ã¼ã®åæ°ãã«ã¦ã³ã numFailures += 1 } else if state == connectivity.TransientFailure { // TransientFailureã¯å復å¯è½ãããããªãã¨ã©ã¼ // ã¨ã©ã¼ã®åæ°ãã«ã¦ã³ã numFailures += 1 } else if state == connectivity.Shutdown { // Shutdownã ã¨ããå復ä¸è½ numFailures = maxFailures } // ã¨ã©ã¼åæ°ãè¦å®ãè¶ ããå ´åãããããã if numFailures >= maxFailures { conn.Close() return NewStatus2(StatusNetworkError, "connection failed") } // ãã£ã³ãã«ã次ã®ç¶æ ã«ç§»ãã¾ã§æå¤§0.1ç§å¾ æ© ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) defer cancel() conn.WaitForStateChange(ctx, state) }
ä»ã®è¨èªã§ãWaitForStateChangeã«é¡ããæ©è½ã¯ããã®ã ããGoã®ããã¯ã¾ã Experimentalãããããããããã®ãããããªãããç¶æ é·ç§»ã®ä»æ¹ããä»ã®è¨èªã¨éããã¨ã«ã¯æ³¨æããã°ãªããªããC++ãPythonãRubyã§ã¯ããµã¼ããæ»ãã§ããå ´åã«ã¯ããã£ã¨TransientFailureç¶æ ã«ãªãã®ã ããGoã ãã¯ãä¸åº¦TransientFailureã«ãªã£ã¦ããããªããIdleã«é·ç§»ãããããã¯ãã°ãªããããªããã¨çã£ã¦ã¯ãããã確証ã¯ãªããä¸è¨ã®ã³ã¼ãã§ã¯ããã®æåãè¸ã¾ããå¦çãæ¸ãã¦ããããæ£ç´å¥å¦ã ãªã¨æãã
ã¾ã¨ããGoã®ã¯ã©ã¤ã¢ã³ããå®è£ ã§ããã®ã§ãã¨ããããTkrzw-RPCã§ãããããã¨ã¯ã ãããåºæ¥ãæãã ãC++ã¨Pythonã¨Rubyã¨Goã®ãã¡ã¤ã«ãåæã«éãã¦åãå¦çãæ¸ãã¨ããä¿®è¡ããã¦ããã®ã§ãåè¨èªã®ç¹å¾´ãææ¡ã§ãã¦é¢ç½ãã£ããæ¬¡åã¯ç°¡åãªæ§è½æ¯è¼ãè¡ãããã