/**@brief append newitem to list * @param key * @param newitem * @return error */ func (ls *Libstore) iAppendToList(key, newitem string) error { var cli *rpc.Client var args storageproto.PutArgs = storageproto.PutArgs{key, newitem} var reply storageproto.PutReply var err error cli, err = ls.GetServer(key) if lsplog.CheckReport(1, err) { return err } //lsplog.Vlogf(0, "AppendToList args %v\n", args) err = cli.Call("StorageRPC.AppendToList", &args, &reply) if lsplog.CheckReport(1, err) { return err } //lsplog.Vlogf(0, "AppendToList reply %v\n", reply) if reply.Status != storageproto.OK { return MakeErr("AppendToList()", reply.Status) } return nil }
/**@brief add subscription to certain user * @param SubscriptionArgs * @param SubscriptionReply * @return error */ func (ts *Tribserver) AddSubscription( args *tribproto.SubscriptionArgs, reply *tribproto.SubscriptionReply) error { var fllw_key string var trib_key string var err error //check whether userid exist trib_key = fmt.Sprintf("%s:T", args.Userid) _, err = ts.Store.GetList(trib_key) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHUSER return nil } //check whether target user exist trib_key = fmt.Sprintf("%s:T", args.Targetuser) _, err = ts.Store.GetList(trib_key) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHTARGETUSER return nil } fllw_key = fmt.Sprintf("%s:F", args.Userid) err = ts.Store.AppendToList(fllw_key, args.Targetuser) if lsplog.CheckReport(1, err) { reply.Status = tribproto.EEXISTS } else { reply.Status = tribproto.OK } return nil }
/**@brief helper function for sorting * @param server master storage server addr * @param myhostport trib server's port * @param flags * @return *Libstore * @return error */ func iNewLibstore(server, myhostport string, flags int) (*Libstore, error) { var store Libstore var master *rpc.Client var args storageproto.GetServersArgs var reply storageproto.RegisterReply var err error store.Addr = myhostport store.Flags = flags if store.Addr != "" { rpc.Register(cacherpc.NewCacheRPC(&store)) } lsplog.Vlogf(3, "libstore try to connect to master storage %s", server) master, err = rpc.DialHTTP("tcp", server) if lsplog.CheckReport(1, err) { return nil, err } lsplog.Vlogf(3, "try to call GetServers") master.Call("StorageRPC.GetServers", &args, &reply) if !reply.Ready { for i := 0; i < 5; i++ { time.Sleep(1000 * time.Millisecond) master.Call("StorageRPC.GetServers", &args, &reply) } } err = master.Close() if lsplog.CheckReport(1, err) { lsplog.Vlogf(3, "WARNING close master failed") } // couldn't get list of servers from master if (reply.Ready == false) || (reply.Servers == nil) { return nil, lsplog.MakeErr("Storage system not ready.") } store.Nodes = reply.Servers store.RPCConn = make([]*rpc.Client, len(store.Nodes)) sort.Sort(store.Nodes) /* for i := 0; i < len(store.Nodes); i++ { fmt.Printf("%v\n", store.Nodes[i]) }*/ store.Leases = cache.NewCache() if lsplog.CheckReport(1, err) { return nil, err } lsplog.Vlogf(3, "libstore create complete") return &store, nil }
/**@brief store key-value into backend * @param key string * @param value string * @return error */ func (ls *Libstore) iPut(key, value string) error { var cli *rpc.Client var args storageproto.PutArgs = storageproto.PutArgs{key, value} var reply storageproto.PutReply var err error //lsplog.Vlogf(0, "libstore put %s->%s!", key, value) cli, err = ls.GetServer(key) if lsplog.CheckReport(1, err) { return err } //lsplog.Vlogf(0, "libstore getserver complete!") //lsplog.Vlogf(0, "put args %v\n", args) /* fmt.Printf("put args %v\n", args) fmt.Printf("here2\n") */ err = cli.Call("StorageRPC.Put", &args, &reply) if lsplog.CheckReport(1, err) { return err } //fmt.Printf("put reply %v\n", reply) //lsplog.Vlogf(0, "put reply %v\n", reply) if reply.Status != storageproto.OK { return MakeErr("Put()", reply.Status) } return nil }
/**@brief create a new user * @param CreateUserArgs * @param CreateUserReply * @return error */ func (ts *Tribserver) CreateUser( args *tribproto.CreateUserArgs, reply *tribproto.CreateUserReply) error { var trib_key, fllw_key string var err error trib_key = fmt.Sprintf("%s:T", args.Userid) fllw_key = fmt.Sprintf("%s:F", args.Userid) _, err = ts.Store.GetList(trib_key) if err == nil { lsplog.Vlogf(0, "try create user %s , but exist !", args.Userid) reply.Status = tribproto.EEXISTS return nil } err = ts.Store.Put(trib_key, "") if lsplog.CheckReport(2, err) { lsplog.Vlogf(0, "user %s , trib_key exist !", args.Userid) reply.Status = tribproto.EEXISTS return nil } err = ts.Store.Put(fllw_key, "") if lsplog.CheckReport(2, err) { reply.Status = tribproto.EEXISTS return nil } reply.Status = tribproto.OK lsplog.Vlogf(0, "create user status %d", tribproto.OK) return nil }
/**@brief collect all tribbles from all users followed * @param CreateUserArgs * @param CreateUserReply * @return error */ func (ts *Tribserver) GetTribblesBySubscription( args *tribproto.GetTribblesArgs, reply *tribproto.GetTribblesReply) error { var fllw_key string var fllw_ids []string var err error var getArgs tribproto.GetTribblesArgs var getReply tribproto.GetTribblesReply var tribs Tribs fllw_key = fmt.Sprintf("%s:F", args.Userid) fllw_ids, err = ts.Store.GetList(fllw_key) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHUSER reply.Tribbles = nil return nil } fmt.Printf("complete geting list %d\n", len(fllw_ids)) reply.Status = tribproto.OK for i := 0; i < len(fllw_ids); i++ { getArgs.Userid = fllw_ids[i] err = ts.GetTribbles(&getArgs, &getReply) fmt.Printf("try geting subscription user %d\n", i+1) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHTARGETUSER reply.Tribbles = nil return nil } reply.Tribbles = append(reply.Tribbles, getReply.Tribbles...) } fmt.Printf("complete getting all subscribed tribs\n") //to satisfy go compiler type check tribs = reply.Tribbles //sort in time order sort.Sort(tribs) if len(reply.Tribbles) > 100 { reply.Tribbles = reply.Tribbles[:100] } return nil }
/**@brief Get value given a key for storage server * @param key * @return value * @return error */ func (ls *Libstore) iGet(key string) (string, error) { var cli *rpc.Client var args storageproto.GetArgs = storageproto.GetArgs{key, false, ls.Addr} var reply storageproto.GetReply var err error //try cache first if tmp, err := ls.Leases.Get(key, &args); err == nil { reply.Value = tmp.(string) return reply.Value, nil } if (ls.Flags & ALWAYS_LEASE) != 0 { args.WantLease = true } //lsplog.Vlogf(0, "libstore Get %s\n", key) cli, err = ls.GetServer(key) if lsplog.CheckReport(1, err) { return "", err } //listen on no port to accept revoke if ls.Addr == "" { args.WantLease = false } //lsplog.Vlogf(0, "Get args:%v\n", args) err = cli.Call("StorageRPC.Get", &args, &reply) if lsplog.CheckReport(1, err) { return "", err } //lsplog.Vlogf(0, "Get reply:%v#!!\n", reply) //fmt.Printf("Get reply granted:%v#!#\n", reply.Lease.Granted) if reply.Lease.Granted { ls.Leases.LeaseGranted(key, reply.Value, reply.Lease) } if reply.Status != storageproto.OK { return "", MakeErr("Get()", reply.Status) } return reply.Value, nil }
/**@brief Hashes a key and returns an RPC connection to the server responsible for storing it. If an RPC connection is not established, create one and store it for future accesses. * @param server master server addr * @param myhostport trib server's port * @param flags * @return *Libstore * @return error */ func (ls *Libstore) GetServer(key string) (*rpc.Client, error) { var id uint32 var svr int var err error //lsplog.Vlogf(3, "libstore GetServer Invoked") id = Storehash(strings.Split(key, ":")[0]) // returns the index of the first server after the key's hash svr = sort.Search( len(ls.Nodes), func(i int) bool { return ls.Nodes[i].NodeID >= id }) svr = (svr) % len(ls.Nodes) //lsplog.Vlogf(0, "%s -> %d (%d)\n", key, id, svr) if ls.RPCConn[svr] == nil { lsplog.Vlogf(0, "Caching RPC connection to %s.\n", ls.Nodes[svr].HostPort) ls.RPCConn[svr], err = rpc.DialHTTP("tcp", ls.Nodes[svr].HostPort) if lsplog.CheckReport(1, err) { return nil, err } } return ls.RPCConn[svr], nil }
/**@brief Post Tribbles * @param PostTribbleArgs * @param PostTribbleReply * @return error */ func (ts *Tribserver) PostTribble( args *tribproto.PostTribbleArgs, reply *tribproto.PostTribbleReply) error { var trib_key string var trib tribproto.Tribble var enc []byte var err error //do not allow empty post if args.Contents == "" { return nil } trib_key = fmt.Sprintf("%s:T", args.Userid) _, err = ts.Store.GetList(trib_key) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHUSER return nil } err = ts.Store.AppendToList(trib_key, strconv.Itoa(ts.Id)) if lsplog.CheckReport(1, err) { reply.Status = tribproto.EEXISTS return nil } trib.Userid = args.Userid trib.Posted = time.Now() trib.Contents = args.Contents enc, err = json.Marshal(trib) if lsplog.CheckReport(1, err) { reply.Status = tribproto.OK return err } err = ts.Store.Put(strconv.Itoa(ts.Id), string(enc)) if lsplog.CheckReport(1, err) { reply.Status = tribproto.OK return err } reply.Status = tribproto.OK ts.Id++ return nil }
func boundedWaitCall(args *storageproto.RevokeLeaseArgs, reply *storageproto.RevokeLeaseReply, con *rpc.Client, doneChan chan int) { err := con.Call("CacheRPC.RevokeLease", &args, &reply) if lsplog.CheckReport(1, err) { fmt.Printf("Try revoke lease holder failed\n!") } doneChan <- 1 return }
/**@brief given a key, get list of strings * @param key * @return string[] * @return error */ func (ls *Libstore) iGetList(key string) ([]string, error) { var cli *rpc.Client var args storageproto.GetArgs = storageproto.GetArgs{key, false, ls.Addr} var reply storageproto.GetListReply var err error //try cache first if tmp, err := ls.Leases.Get(key, &args); err == nil { reply.Value = tmp.([]string) return reply.Value, nil } if (ls.Flags & ALWAYS_LEASE) != 0 { args.WantLease = true } cli, err = ls.GetServer(key) if lsplog.CheckReport(1, err) { return nil, err } //lsplog.Vlogf(0, "GetList args %v", args) err = cli.Call("StorageRPC.GetList", &args, &reply) if lsplog.CheckReport(1, err) { return nil, err } //lsplog.Vlogf(0, "GetList reply %v", reply) if reply.Lease.Granted { ls.Leases.LeaseGranted(key, reply.Value, reply.Lease) } if reply.Status != storageproto.OK { return nil, MakeErr("GetList()", reply.Status) } return reply.Value, nil }
/**@brief remove a item from backend storage * @param key * @param removeitem * @return error */ func (ls *Libstore) iRemoveFromList(key, removeitem string) error { var cli *rpc.Client var args storageproto.PutArgs = storageproto.PutArgs{key, removeitem} var reply storageproto.PutReply var err error cli, err = ls.GetServer(key) if lsplog.CheckReport(1, err) { return err } err = cli.Call("StorageRPC.RemoveFromList", &args, &reply) if lsplog.CheckReport(1, err) { return err } if reply.Status != storageproto.OK { return MakeErr("RemoveFromList()", reply.Status) } return nil }
/**@brief get posted tribbles * @param GetTribblesArgs * @param GetTribblesReply * @return error */ func (ts *Tribserver) GetTribbles( args *tribproto.GetTribblesArgs, reply *tribproto.GetTribblesReply) error { var trib_key string var trib_ids []string var trib_enc string var err error var length int trib_key = fmt.Sprintf("%s:T", args.Userid) trib_ids, err = ts.Store.GetList(trib_key) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHUSER reply.Tribbles = nil return nil } reply.Status = tribproto.OK if len(trib_ids) > 100 { length = 100 } else { length = len(trib_ids) } reply.Tribbles = make([]tribproto.Tribble, length) for i := 0; i < length; i++ { trib_enc, err = ts.Store.Get(trib_ids[len(trib_ids)-1-i]) if lsplog.CheckReport(1, err) { return lsplog.MakeErr("Get Tribbles Message Error") } //fmt.Printf("unmarshal string %s\n", trib_enc) _ = json.Unmarshal([]byte(trib_enc), &(reply.Tribbles[i])) } return nil }
/**@brief get tribbles from subscriped users * @param GetSubscriptionsArgs * @param GetSubscriptionsReply * @return error */ func (ts *Tribserver) GetSubscriptions( args *tribproto.GetSubscriptionsArgs, reply *tribproto.GetSubscriptionsReply) error { var fllw_key string var fllw_ids []string var err error fllw_key = fmt.Sprintf("%s:F", args.Userid) fllw_ids, err = ts.Store.GetList(fllw_key) if lsplog.CheckReport(1, err) { reply.Status = tribproto.ENOSUCHUSER reply.Userids = nil return nil } reply.Status = tribproto.OK reply.Userids = fllw_ids return nil }
/**@brief create a new tribserver * @param string * @param string * @return *tribserver */ func NewTribserver(storagemaster, myhostport string) *Tribserver { lsplog.SetVerbose(3) fmt.Printf("st_master:%s, port:%s\n", storagemaster, myhostport) var svr *Tribserver = new(Tribserver) var err error lsplog.Vlogf(3, "try to create libstore") // libstore.NONE forces no leases on Get and GetList requests svr.Store, err = libstore.NewLibstore(storagemaster, myhostport, libstore.NONE) if lsplog.CheckReport(1, err) { return nil } svr.Id = 1 return svr }
func (ss *Storageserver) revokeLeaseHolders(key string) error { var args storageproto.RevokeLeaseArgs var reply storageproto.RevokeLeaseReply var doneChan chan int entry := (ss.leasePool[key]) (*(entry.pending)) = true fmt.Printf("set key %s pending\n", key) for _, holder := range entry.holders { if isTimeout(holder) { fmt.Printf("revoke holder %s expire\n", key) continue } svr, err := rpc.DialHTTP("tcp", holder.holderAddr) if lsplog.CheckReport(1, err) { fmt.Printf("revoke dial %s failed", holder.holderAddr) } args.Key = key //ensure rpc is bounded waiting go boundedWaitCall(&args, &reply, svr, doneChan) select { case <-doneChan: break case <-time.After((storageproto.LEASE_SECONDS + storageproto.LEASE_GUARD_SECONDS) * time.Second): break } fmt.Printf("revoke complete rpc to holder %s\n", holder.holderAddr) } (*(entry.pending)) = false fmt.Printf("cannel key %s pending !\n", key) return nil }
func NewStorageserver(master string, numnodes int, portnum int, nodeid uint32) *Storageserver { lsplog.SetVerbose(3) fmt.Println("Create New Storage Server") fmt.Printf("master:%s, numnodes:%d, portnum:%d, nodeid:%d\n", master, numnodes, portnum, nodeid) var masterNode *rpc.Client var regArgs storageproto.RegisterArgs var regReply storageproto.RegisterReply var storage Storageserver var err error var nodes = make(map[storageproto.Node]bool) storage.nodeid = nodeid storage.leasePool = make(map[string]leaseEntry) selfAddr := fmt.Sprintf("localhost:%d", portnum) if master == selfAddr { fmt.Printf("for master node\n") //for master node storage.isMaster = true storage.portnum = portnum //storage.portnum = DEFAULT_MASTER_PORT storage.nodes = nodes storage.numnodes = numnodes //add masternode itself to nodes table //hostport := fmt.Sprintf("localhost:%d", DEFAULT_MASTER_PORT) self := storageproto.Node{master, nodeid} storage.nodes[self] = true } else { masterNode, err = rpc.DialHTTP("tcp", master) if lsplog.CheckReport(1, err) { return nil } regArgs.ServerInfo.HostPort = fmt.Sprintf("localhost:%d", portnum) regArgs.ServerInfo.NodeID = nodeid //for slave node storage.isMaster = false storage.portnum = portnum fmt.Printf("for slave node\n") fmt.Printf("begin try $$$\n") for i := 0; (regReply.Ready == false) && (i < 10); i++ { fmt.Printf("try %d times\n", i) masterNode.Call("StorageRPC.Register", ®Args, ®Reply) /* if lsplog.CheckReport(1, err) { lsplog.Vlogf(3, "slave %d call RegisterServer %d time failed", i + 1, portnum) }*/ time.Sleep(1000 * time.Millisecond) } } storage.hash = make(map[string][]byte) return &storage }
func main() { serverAddress := "127.0.0.1" serverPort := fmt.Sprintf("%d", 9010) client, _ := NewTribbleclient(serverAddress, serverPort) //create user status, err := client.CreateUser("1") fmt.Printf("status:%d\n", status) if lsplog.CheckReport(0, err) { return } // //test duplicate create user ! // status, err = client.CreateUser("1") // fmt.Printf("status:%d\n", status) // // //test nonexist user post message // status, err = client.PostTribble("2", "test1") // fmt.Printf("status:%d\n", status) // if lsplog.CheckReport(0, err) { // return // } //test post msg status, err = client.PostTribble("1", "test1") fmt.Printf("status:%d\n", status) //test get msg tribbles, status, err := client.GetTribbles("1") fmt.Printf("status:%d\n", status) PrintTribbles(tribbles) //create user 2 status, err = client.CreateUser("2") fmt.Printf("status:%d\n", status) //user2 post message status, err = client.PostTribble("2", "test2") fmt.Printf("status:%d\n", status) //user2 get message tribbles, status, err = client.GetTribbles("2") fmt.Printf("status:%d\n", status) PrintTribbles(tribbles) //test user1 addsubscription user2 status, err = client.AddSubscription("1", "2") fmt.Printf("status:%d\n", status) // //test user1 getsubscription // users, status, err := client.GetSubscriptions("1") // fmt.Printf("status:%d\n", status) // fmt.Println(strings.Join(users, ",")) //test GetTribblesBySubscription tribbles, status, err = client.GetTribblesBySubscription("1") fmt.Printf("status:%d\n", status) PrintTribbles(tribbles) //test removesubscription status, err = client.RemoveSubscription("1", "2") fmt.Printf("status:%d\n", status) //test GetTribblesBySubscription tribbles, status, err = client.GetTribblesBySubscription("1") fmt.Printf("status:%d\n", status) PrintTribbles(tribbles) }