Advertisement
Guest User

Untitled

a guest
May 6th, 2017
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.15 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4. "fmt"
  5.  
  6. "github.com/go-pg/pg"
  7. "github.com/go-pg/pg/orm"
  8. "github.com/go-pg/sharding"
  9. )
  10.  
  11. // Parrots are sharded by AccountId, i.e. parrots with same account id are
  12. // placed on the same shard.
  13. type Parrot struct {
  14. TableName string `sql:"?shard.parrots"`
  15.  
  16. Id int64
  17. AccountId int64
  18. Name string
  19. Tele *Tele
  20. Emails []string
  21. }
  22.  
  23. type Tele struct {
  24. TableName string `sql:"?shard.teles"`
  25.  
  26. Id int64
  27. AccountId int64
  28. Number int
  29. ParrotId int64
  30. }
  31.  
  32. func (u Parrot) String() string {
  33. return u.Name
  34. }
  35.  
  36. // CreateParrot picks shard by account id and creates parrot in the shard.
  37. func CreateParrot(cluster *sharding.Cluster, parrot *Parrot) error {
  38. return cluster.Shard(parrot.AccountId).Insert(parrot)
  39. }
  40.  
  41. // CreateParrot picks shard by account id and creates parrot in the shard.
  42. func CreateTele(cluster *sharding.Cluster, tele *Tele) error {
  43. return cluster.Shard(tele.AccountId).Insert(tele)
  44. }
  45.  
  46. // GetParrot splits shard from parrot id and fetches parrot from the shard.
  47. func GetParrot(cluster *sharding.Cluster, id int64) (*Parrot, error) {
  48. var parrot Parrot
  49. err := cluster.SplitShard(id).Model(&parrot).
  50. //Column("parrot.name", "Tele").
  51. Where("id = ?", id).Select()
  52. return &parrot, err
  53. }
  54.  
  55. // GetParrots picks shard by account id and fetches parrots from the shard.
  56. func GetParrots(cluster *sharding.Cluster, accountId int64) ([]Parrot, error) {
  57. var parrots []Parrot
  58. err := cluster.Shard(accountId).Model(&parrots).Where("account_id = ?", accountId).Select()
  59. return parrots, err
  60. }
  61.  
  62. type tmpParrot struct {
  63. Number int
  64. Name string
  65. }
  66.  
  67. // select p.name, t.number from shard0.parrots AS p, shard0.teles as t where t.parrot_id = p.id
  68. func GetShardedParrots(db *pg.DB) ([]tmpParrot, error) {
  69. var parrots []tmpParrot
  70. _, err := db.Query(&parrots, `select p.name, t.number from shard0.parrots AS p, shard0.teles as t where t.parrot_id = p.id`)
  71. return parrots, err
  72. }
  73.  
  74. // createShard creates database schema for a given shard.
  75. func createShard(shard *pg.DB) error {
  76. for _, model := range []interface{}{&Parrot{}} {
  77. err := shard.CreateTable(model, &orm.CreateTableOptions{
  78. IfNotExists: true,
  79. })
  80. if err != nil {
  81. fmt.Printf("\n CREATE TABLES ERROR > %q for %T", err, model)
  82. }
  83.  
  84. }
  85. queries := []string{
  86. `DROP SCHEMA IF EXISTS ?shard CASCADE`,
  87. `CREATE SCHEMA ?shard`,
  88. sqlFuncs,
  89. `CREATE TABLE ?shard.parrots (id bigint DEFAULT ?shard.next_id(), account_id int, name text, emails jsonb)`,
  90. `CREATE TABLE ?shard.teles (id bigint DEFAULT ?shard.next_id(), parrot_id bigint, account_id int, number int)`,
  91. }
  92.  
  93. for _, q := range queries {
  94. _, err := shard.Exec(q)
  95. if err != nil {
  96. return err
  97. }
  98. }
  99.  
  100. return nil
  101. }
  102.  
  103. func ExampleCluster() {
  104. db := pg.Connect(&pg.Options{
  105. User: "user",
  106. Password: "pass",
  107. Database: "pgdb",
  108. TLSConfig: nil,
  109. })
  110.  
  111. dbs := []*pg.DB{db} // list of physical PostgreSQL servers
  112. nshards := 2 // 2 logical shards
  113. // Create cluster with 1 physical server and 2 logical shards.
  114. cluster := sharding.NewCluster(dbs, nshards)
  115.  
  116. // Create database schema for our logical shards.
  117. for i := 0; i < nshards; i++ {
  118. if err := createShard(cluster.Shard(int64(i))); err != nil {
  119. fmt.Println(err)
  120. }
  121. }
  122.  
  123. // parrot1 will be created in shard1 because AccountId % nshards = shard1.
  124. parrot1 := &Parrot{
  125. Name: "parrot1",
  126. AccountId: 1,
  127. Emails: []string{"parrot1@domain"},
  128. }
  129. err := CreateParrot(cluster, parrot1)
  130. if err != nil {
  131. fmt.Println(err)
  132. }
  133.  
  134. // parrot2 will be created in shard1 too because AccountId is the same.
  135. parrot2 := &Parrot{
  136. Name: "parrot2",
  137. AccountId: 1,
  138. Emails: []string{"parrot2@domain"},
  139. }
  140. err = CreateParrot(cluster, parrot2)
  141. if err != nil {
  142. fmt.Println(err)
  143. }
  144.  
  145. // parrot3 will be created in shard0 because AccountId % nshards = shard0.
  146. parrot3 := &Parrot{
  147. Name: "parrot3",
  148. AccountId: 2,
  149. Emails: []string{"parrot3@domain"},
  150. }
  151. err = CreateParrot(cluster, parrot3)
  152. if err != nil {
  153. fmt.Println(err)
  154. }
  155. tele3 := &Tele{AccountId: 2, ParrotId: parrot3.Id, Number: 98776655}
  156. err = CreateTele(cluster, tele3)
  157. if err != nil {
  158. fmt.Println(err)
  159. }
  160. parrot, err := GetParrot(cluster, parrot3.Id)
  161. if err != nil {
  162. fmt.Println(err)
  163. }
  164.  
  165. parrots, err := GetParrots(cluster, 2)
  166. if err != nil {
  167. fmt.Println(err)
  168. }
  169.  
  170. fmt.Println(parrot)
  171. fmt.Println(parrots[0].Tele)
  172. // Output: parrot1
  173. // parrot1 parrot2
  174. parrots3, err := GetShardedParrots(db)
  175. if err != nil {
  176. fmt.Println(err)
  177. }
  178. fmt.Println(parrots3[0])
  179. }
  180.  
  181. const sqlFuncs = `
  182. CREATE SEQUENCE ?shard.id_seq;
  183.  
  184. -- _next_id returns unique sortable id.
  185. CREATE FUNCTION ?shard._next_id(tm timestamptz, shard_id int, seq_id bigint)
  186. RETURNS bigint AS $$
  187. DECLARE
  188. max_shard_id CONSTANT bigint := 2048;
  189. max_seq_id CONSTANT bigint := 4096;
  190. id bigint;
  191. BEGIN
  192. shard_id := shard_id % max_shard_id;
  193. seq_id := seq_id % max_seq_id;
  194. id := (floor(extract(epoch FROM tm) * 1000)::bigint - ?epoch) << 23;
  195. id := id | (shard_id << 12);
  196. id := id | seq_id;
  197. RETURN id;
  198. END;
  199. $$
  200. LANGUAGE plpgsql
  201. IMMUTABLE;
  202.  
  203. CREATE FUNCTION ?shard.next_id()
  204. RETURNS bigint AS $$
  205. BEGIN
  206. RETURN ?shard._next_id(clock_timestamp(), ?shard_id, nextval('?shard.id_seq'));
  207. END;
  208. $$
  209. LANGUAGE plpgsql;
  210. `
  211.  
  212. func main() {
  213. // Postgres needs permission
  214. ExampleCluster()
  215. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement