shopping

package
v0.0.0-...-9789875 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2021 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package shopping provides rush shopping backend service.

Requirements

The RESTful API is identified in spec.md, including the URL, logic semantics, request format and response status.

Some important constrains of rush shopping are highlighted as follows.

  • Every item has a limited stock and can't be oversold. The stock constraint should be guaranteed when the order is made instead of managing the cart.
  • Every user can create more than one cart, but the total of items in it must not more than three.
  • Every user can't make more than one order.

The normal actions for a user to finish purchasing the order are as follows.

                                 | /carts/xxx |
/login --- /items --- /carts --- | /carts/xxx | --- /orders --- /pay
                                 | /carts/xxx |

Actually, a user could create carts before querying the items. Of course, a user could add items to cart or discard items by /carts/xxx in any times. Just make sure the total of items in the cart must not more than three.

The admin username and password are as follows.

| admin | username | password |
| value | root     | root     |

And the username with the prefix "zero" means the corresponding the user's balance is zero, so she/he can't afford any item.

The CSV format for the users is the following.

| id  | username | password | balance |
| int | string   | string   | int     |

The CSV format for the items is the following.

| id  | price | stock |
| int | int   | int   |

An implementation in our project

We assume the followings:

  • The IDs of items are increasing from 1 continuously.

  • The ID of the (root) administrator user is 0.

  • The IDs of normal users are increasing from 1 continuously.

  • CartID is auto-increased from 1.

    The data format in KV-Store could be referred in shop_kvformat.md.

Index

Constants

View Source
const (
	URLLogin              = "/login"
	URLQueryItem          = "/items"
	URLCreateCart         = "/carts"
	URLAddItem            = "/carts/"
	URLSubmitOrQueryOrder = "/orders"
	URLPayOrder           = "/pay"
	URLQueryAllOrders     = "/admin/orders"
)

API URLs

View Source
const (
	TokenKeyPrefix      = "token:"
	OrderKeyPrefix      = "order:"
	ItemsStockKeyPrefix = "items_stock:"
	ItemsPriceKeyPrefix = "items_price:"
	BalanceKeyPrefix    = "balance:"

	CartIDMaxKey = "cartID"
	ItemsSizeKey = "items_size"
)

Keys of kvstore.

View Source
const (
	OrderPaidFlag   = "P" // have been paid
	OrderUnpaidFlag = "W" // wait to be paid
)

Flags for paid or unpaid status.

View Source
const (
	TxnOK       = 0
	TxnNotFound = 1 << (iota - 1) // iota == 1
	TxnNotAuth
	TxnCartEmpyt
	TxnOutOfStock      // out of stock
	TxnItemOutOfLimit  // most 3 items
	TxnOrderOutOfLimit // most one order for one person
	TxnOrderPaid
	TxnBalanceInsufficient
)

Trans status.

View Source
const DefaultCoordClientPoolMaxSize = 100

DefaultCoordClientPoolMaxSize is the default size of connection pool for the Coordinator in 2pc.

View Source
const DefaultShardClientPoolMaxSize = 100

DefaultShardClientPoolMaxSize is the default size of connection pool for every shard of the whole KV-store.

View Source
const DefaultTaskMaxSize = 10000

DefaultTaskMaxSize is the maximum of TxnTasks waiting to be processed one by one.

View Source
const RootUserID = 0

RootUserID is specified.

Variables

View Source
var (
	UserAuthFailMsg       = []byte("{\"code\":\"USER_AUTH_FAIL\",\"message\":\"用户名或密码错误\"}")
	MalformedJSONMsg      = []byte("{\"code\": \"MALFORMED_JSON\",\"message\": \"格式错误\"}")
	EmptyRequestMsg       = []byte("{\"code\": \"EMPTY_REQUEST\",\"message\": \"请求体为空\"}")
	InvalidAccessTokenMsg = []byte("{\"code\": \"INVALID_ACCESS_TOKEN\",\"message\": \"无效的令牌\"}")
	CartNotFoundMsg       = []byte("{\"code\": \"CART_NOT_FOUND\", \"message\": \"篮子不存在\"}")
	CartEmptyMsg          = []byte("{\"code\": \"CART_EMPTY\", \"message\": \"购物车为空\"}")
	NotAuthorizedCartMsg  = []byte("{\"code\": \"NOT_AUTHORIZED_TO_ACCESS_CART\",\"message\": \"无权限访问指定的篮子\"}")
	ItemOutOfLimitMsg     = []byte("{\"code\": \"ITEM_OUT_OF_LIMIT\",\"message\": \"篮子中物品数量超过了三个\"}")
	ItemNotFoundMsg       = []byte("{\"code\": \"ITEM_NOT_FOUND\",\"message\": \"物品不存在\"}")
	ItemOutOfStockMsg     = []byte("{\"code\": \"ITEM_OUT_OF_STOCK\", \"message\": \"物品库存不足\"}")
	OrderOutOfLimitMsg    = []byte("{\"code\": \"ORDER_OUT_OF_LIMIT\",\"message\": \"每个用户只能下一单\"}")

	OrderNotFoundMsg       = []byte("{\"code\": \"ORDER_NOT_FOUND\", \"message\": \"篮子不存在\"}")
	NotAuthorizedOrderMsg  = []byte("{\"code\": \"NOT_AUTHORIZED_TO_ACCESS_ORDER\",\"message\": \"无权限访问指定的订单\"}")
	OrderPaidMsg           = []byte("{\"code\": \"ORDER_PAID\",\"message\": \"订单已支付\"}")
	BalanceInsufficientMsg = []byte("{\"code\": \"BALANCE_INSUFFICIENT\",\"message\": \"余额不足\"}")
)

JSON-format msgs for requests.

View Source
var RootUserToken = userID2Token(RootUserID)

RootUserToken is token for the root user.

Functions

func AddItemTxnInit

func AddItemTxnInit(args interface{}) (ret interface{}, errCode int)

AddItemTxnInit is the initial function for AddItem txn.

func PayOrderTxnInit

func PayOrderTxnInit(args interface{}) (ret interface{}, errCode int)

PayOrderTxnInit is the initial function for PayOrder txn.

func SubmitOrderTxnInit

func SubmitOrderTxnInit(args interface{}) (ret interface{}, errCode int)

SubmitOrderTxnInit is the initial function for SubmitOrder txn.

Types

type AddItemArgs

type AddItemArgs struct {
	CartIDStr  string
	UserToken  string
	ItemID     int
	AddItemCnt int
}

AddItemArgs is the argument of the AddItemTrans function.

type AddItemTxnInitArgs

type AddItemTxnInitArgs struct {
	OrderKey   string
	CartKey    string
	CartIDStr  string
	ItemID     int
	AddItemCnt int
}

AddItemTxnInitArgs is intial args for AddItem txn's initialization.

type AddItemTxnInitRet

type AddItemTxnInitRet AddItemTxnInitArgs

AddItemTxnInitRet is return value for AddItem txn's initialization.

type CartIDJson

type CartIDJson struct {
	IDStr string `json:"cart_id"`
}

type CoordClients

type CoordClients struct {
	// contains filtered or unexported fields
}

CoordClients is the clients to connect to Coordinator.

func NewCoordClients

func NewCoordClients(network, addr string, size int) *CoordClients

NewCoordClients inits a new coordinator.

func (*CoordClients) AsyncAddItemTxn

func (cs *CoordClients) AsyncAddItemTxn(cartIDStr, userToken string, itemID,
	addItemCnt int) (ok bool, txnID string)

AsyncAddItemTxn submits AddItem Txn and returns immediately.

func (*CoordClients) AsyncPayOrderTxn

func (cs *CoordClients) AsyncPayOrderTxn(orderIDStr,
	userToken string, delta int) (ok bool, txnID string)

AsyncPayOrderTxn submits PayOrder Txn and returns immediately.

func (*CoordClients) AsyncSubmitOrderTxn

func (cs *CoordClients) AsyncSubmitOrderTxn(cartIDStr,
	userToken string) (ok bool, txnID string)

AsyncSubmitOrderTxn submits SubmitOrder Txn and returns immediately.

func (*CoordClients) LoadItemList

func (cs *CoordClients) LoadItemList(itemsCnt int) (ok bool)

LoadItemList makes the coordinator load items records into the database.

func (*CoordClients) SyncTxn

func (cs *CoordClients) SyncTxn(txnID string) (errCode int)

SyncTxn returns until the corresponding Txn get ended.

type Item

type Item struct {
	ID    int `json:"id"`
	Price int `json:"price"`
	Stock int `json:"stock"`
}

type ItemCount

type ItemCount struct {
	ItemID int `json:"item_id"`
	Count  int `json:"count"`
}

type LoginJson

type LoginJson struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Order

type Order struct {
	// if total < 0, then is a order
	IDStr   string      `json:"id"`
	Items   []ItemCount `json:"items"`
	Total   int         `json:"total"`
	HasPaid bool        `json:"paid"`
}

type OrderDetail

type OrderDetail struct {
	Order
	UserID int `json:"user_id"`
}

OrderDetail is for GET /admin/orders

type OrderIDJson

type OrderIDJson struct {
	IDStr string `json:"order_id"`
}

type PayOrderArgs

type PayOrderArgs struct {
	OrderIDStr string
	UserToken  string
	Delta      int
}

PayOrderArgs is the args for PayOrder txn.

type PayOrderTxnInitArgs

type PayOrderTxnInitArgs struct {
	OrderKey       string
	BalanceKey     string
	RootBalanceKey string
	Delta          int
	// contains filtered or unexported fields
}

PayOrderTxnInitArgs is initial args for PayOrder txn's initialization.

type PayOrderTxnInitRet

type PayOrderTxnInitRet PayOrderTxnInitArgs

PayOrderTxnInitRet is return value for PayOrder txn's initialization.

type ShardsClientHub

type ShardsClientHub struct {
	// contains filtered or unexported fields
}

ShardsClientHub is the client hub to connect to the databases directly.

func NewShardsClientHub

func NewShardsClientHub(network string, srvAddrs []string,
	keyHashFunc twopc.KeyHashFunc, maxSizeForOne int) *ShardsClientHub

NewShardsClientHub inits a new ShardsClientHub.

func (*ShardsClientHub) Get

func (h *ShardsClientHub) Get(key string) (ok bool, reply kv.Reply)

Get commands a get operation onto the specific shard.

func (*ShardsClientHub) Incr

func (h *ShardsClientHub) Incr(key string, delta int) (ok bool, reply kv.Reply)

Incr commands a incr operation onto the specific shard.

func (*ShardsClientHub) Put

func (h *ShardsClientHub) Put(key string, value string) (ok bool, reply kv.Reply)

Put commands a put operation onto the specific shard.

type ShopServer

type ShopServer struct {

	// All the followings are in the resident memory.
	// Item start from index 1.
	ItemListCache []Item
	ItemLock      sync.Mutex

	// ItemsJSONCache is cache for querying items.
	ItemsJSONCache []byte

	// UserMap is the users' information.
	UserMap map[string]UserIDAndPass

	// MaxItemID is the same with the number of types of items.
	MaxItemID int

	// MaxUserID is the same with the number of normal users.
	MaxUserID int
	// contains filtered or unexported fields
}

ShopServer is the web service for rush shopping.

func InitService

func InitService(network, appAddr, coordAddr, userCsv, itemCsv string,
	kvstoreAddrs []string, keyHashFunc twopc.KeyHashFunc) *ShopServer

InitService inits the rush shopping web service and starts the service. Network is "tcp" or "unix" for the whole system. CoordAddr and kvstoreAddrs communication addresses for the Coordinator and shards. UserCsv and itemCsv is the CSV file path for users and items. KeyHashFunc is the hash function to distribute the key-value pair to the specific shard.

func (*ShopServer) Kill

func (ss *ShopServer) Kill()

Kill kills the shopping service for a test.

type ShoppingTxnCoordinator

type ShoppingTxnCoordinator struct {
	// contains filtered or unexported fields
}

ShoppingTxnCoordinator wraps the Coordinator with the RPC services to serve the txn logics.

func NewShoppingTxnCoordinator

func NewShoppingTxnCoordinator(network, coord string, ppts []string,
	keyHashFunc twopc.KeyHashFunc, timeoutMs int64) *ShoppingTxnCoordinator

NewShoppingTxnCoordinator inits ShoppingTxnCoordinator service.

func (*ShoppingTxnCoordinator) AsyncAddItemTxn

func (stc *ShoppingTxnCoordinator) AsyncAddItemTxn(args *AddItemArgs, txnID *string) error

AsyncAddItemTxn submits the AddItem txn to the tasks list, and then returns immediately.

func (*ShoppingTxnCoordinator) AsyncPayOrderTxn

func (stc *ShoppingTxnCoordinator) AsyncPayOrderTxn(args *PayOrderArgs, txnID *string) error

AsyncPayOrderTxn submits PayOrder txn to the task list.

func (*ShoppingTxnCoordinator) AsyncSubmitOrderTxn

func (stc *ShoppingTxnCoordinator) AsyncSubmitOrderTxn(args *SubmitOrderArgs, txnID *string) error

AsyncSubmitOrderTxn submits SubmitOrder txn to the task list.

func (*ShoppingTxnCoordinator) LoadItemList

func (stc *ShoppingTxnCoordinator) LoadItemList(itemsSize *int, reply *struct{}) error

LoadItemList loads item info into the cahce for the slater rapid visiting.

func (*ShoppingTxnCoordinator) Run

func (stc *ShoppingTxnCoordinator) Run()

Run executes the txns one by one from the task list.

type ShoppingTxnKVStore

type ShoppingTxnKVStore struct {
	kv.KVStoreService
	// contains filtered or unexported fields
}

ShoppingTxnKVStore supports the shopping transations. It wraps the KV-store with the shopping txn logics. The logics will be registered into the 2pc service, so the txns could be managed by the Coordinator and the Parcipants.

func NewShoppingTxnKVStore

func NewShoppingTxnKVStore() *ShoppingTxnKVStore

NewShoppingTxnKVStore inits a new ShoppingTxnKVStore.

func (*ShoppingTxnKVStore) CartAddItem

func (skv *ShoppingTxnKVStore) CartAddItem(initRet interface{}) (errCode int,
	rbf twopc.Rollbacker)

CartAddItem is the subruntine as a part of txn, to add or discard some items to a specific cart.

func (*ShoppingTxnKVStore) CartExist

func (skv *ShoppingTxnKVStore) CartExist(initRet interface{}) (errCode int, rbf twopc.Rollbacker)

CartExist is the subruntine as a part of txn, to check whether the cart exists.

func (*ShoppingTxnKVStore) ItemsStockMinus

func (skv *ShoppingTxnKVStore) ItemsStockMinus(initRet interface{}) (errCode int, rbf twopc.Rollbacker)

ItemsStockMinus is the subruntine as a part of txn, to minus the stock of one item when a order is made.

The subruntine is executed in a broadcast way, i.e. all the shards will execute it.

func (*ShoppingTxnKVStore) OrderRecord

func (skv *ShoppingTxnKVStore) OrderRecord(initRet interface{}) (errCode int, rbf twopc.Rollbacker)

OrderRecord is the subruntine as a part of txn, to record the order when a order is made.

func (*ShoppingTxnKVStore) PayAdd

func (skv *ShoppingTxnKVStore) PayAdd(initRet interface{}) (errCode int, rbf twopc.Rollbacker)

PayAdd is the subruntine as a part of txn, to increase the root's balance when a order is paid.

func (*ShoppingTxnKVStore) PayMinus

func (skv *ShoppingTxnKVStore) PayMinus(initRet interface{}) (errCode int, rbf twopc.Rollbacker)

PayMinus is the subruntine as a part of txn, to decrease the user's balance when a order is paid.

func (*ShoppingTxnKVStore) PayRecord

func (skv *ShoppingTxnKVStore) PayRecord(initRet interface{}) (errCode int, rbf twopc.Rollbacker)

PayRecord is the subruntine as a part of txn, to record the payment when a order is paid.

type ShoppingTxnKVStoreService

type ShoppingTxnKVStoreService struct {
	*ShoppingTxnKVStore
	// contains filtered or unexported fields
}

ShoppingTxnKVStoreService is the service wrapping the ShoppingTxnKVStore and one partipant of 2pc.

func NewShoppingTxnKVStoreService

func NewShoppingTxnKVStoreService(network, addr, coordAddr string) *ShoppingTxnKVStoreService

NewShoppingTxnKVStoreService starts the transaction-enabled kvstore.

func (*ShoppingTxnKVStoreService) Serve

func (service *ShoppingTxnKVStoreService) Serve()

Serve starts the KV-store service.

type SubmitOrderArgs

type SubmitOrderArgs struct {
	CartIDStr string
	UserToken string
}

SubmitOrderArgs is the args for the SubmitOrder txn.

type SubmitOrderTxnInitArgs

type SubmitOrderTxnInitArgs struct {
	OrderKey  string
	CartIDStr string
	CartKey   string
	// contains filtered or unexported fields
}

SubmitOrderTxnInitArgs is intial args for SubmitOrder txn's initialization.

type SubmitOrderTxnInitRet

type SubmitOrderTxnInitRet struct {
	SubmitOrderTxnInitArgs
	CartValue string
	Price     int
}

SubmitOrderTxnInitRet is return value for SubmitOrder txn's initialization.

type TxnTask

type TxnTask struct {
	// contains filtered or unexported fields
}

TxnTask records a txn and its initial args and return code.

type UserIDAndPass

type UserIDAndPass struct {
	ID       int
	Password string
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL