func (m *MysqlProxy) DeleteTable(table *schema.MysqlTable) { curTables := []*schema.MysqlTable{} curTableIds := []string{} for _, one := range m.Tables { if one.Name != table.Name { curTables = append(curTables, one) } } for _, one := range m.TableIds { if one != table.Id { curTableIds = append(curTableIds, one) } } // delete the relations. m.TableIds = curTableIds m.Tables = curTables err := redis.UpdateDB("main", redis.EncodeData(m), "MysqlProxy") if err != nil { fmt.Printf("Delete table error when write redis: %s\n", err) return } schema.Tables = curTables // delete selfs. table.Destroy() }
// build a new shard DB after more the limit // or no any one shard DB. func buildNewShardDB(grp *host.Group) (*MysqlShardDB, error) { mut.Lock() defer mut.Unlock() shardDBName := "shard" + strconv.Itoa(ShardDBCnt+1) // to check this new shard db has been exists. isExists := IsExistsShardDB(shardDBName) if isExists != nil { return isExists, nil } newShardDBId := redis.BuildPrimaryKey(shardDBName, true) shardDB := &MysqlShardDB{ Id: newShardDBId, Name: shardDBName, TableTotal: uint64(0), SizeTotal: uint64(0), HostGroupId: grp.Id, Created: time.Now().Unix(), HostGroup: grp, } // create the database to host. // master := host.GetBetterHost(grp.Master, "master") db, err := (&master).ConnToDB("mysql") if err != nil { return nil, err } stmt, err := db.Prepare(fmt.Sprintf("CREATE DATABASE `%s` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci", shardDBName)) if err != nil { return nil, err } _, err = stmt.Exec() if err != nil { return nil, err } stmt.Close() db.Close() // to write the new shard db to redis // err = redis.WriteDB(newShardDBId, redis.EncodeData(shardDB), "MysqlShardDB") if err != nil { return nil, err } // notice Mysql Project object to add a new shard db memery. NewShardDBCh <- shardDB return shardDB, nil }
// get the table status. func (m *MysqlProxy) GetStatus() (map[string]interface{}, error) { result := map[string]interface{}{} result["main"] = redis.EncodeData(m) tables := []string{} shardDB := []string{} for _, table := range m.Tables { tables = append(tables, redis.EncodeData(table)) } for _, db := range m.ShardDBs { shardDB = append(shardDB, redis.EncodeData(db)) } result["tables"] = tables result["sharddbs"] = shardDB return result, nil }
func (tbl *MysqlTable) GetGId() string { curId := tbl.CurGId tbl.CurGId++ err := redis.UpdateDB(tbl.Id, redis.EncodeData(tbl), "MysqlTable") if err != nil { log.Printf("get gid error: %s", err) } return strconv.FormatUint(curId, 10) }
// To init the necessary data. func (m *MysqlProxy) Init() { m.InitMain() m.InitMysqlDB() m.InitMysqlTable() m.InitConnPooling() if isUpdated { // save mysql proxy. err := redis.UpdateDB("main", redis.EncodeData(m), "MysqlProxy") CheckError(err) } // panic(fmt.Sprintf("OK: %#v", m)) }
func (m *MysqlProxy) BuildNewShardDB(group *host.Group, name string) (*schema.MysqlShardDB, error) { if name == "" { return nil, errors.New("Sorry, can not build the no name databases") } // init the shard db to host. master := group.Master[0] db, err := (&master).ConnToDB("mysql") if err != nil { return nil, err } stmt, err := db.Prepare(fmt.Sprintf("CREATE DATABASE `%s` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci", name)) if err != nil { return nil, err } _, err = stmt.Exec() if err != nil { return nil, err } stmt.Close() shardDbId := redis.BuildPrimaryKey(name, true) shardDb := &schema.MysqlShardDB{ Id: shardDbId, Name: name, TableTotal: 0, SizeTotal: 0, HostGroupId: group.Id, Created: redis.GetCurTime(), HostGroup: group, } // save this new shard database to tracker. err = redis.WriteDB(shardDbId, redis.EncodeData(shardDb), "MysqlShardDB") if err != nil { return nil, err } (&master).CloseDB() schema.ShardDBCnt++ return shardDb, nil }
func (sdb *MysqlShardDB) InitShardTable(tName string) (*MysqlShardTable, error) { shardTabId := redis.BuildPrimaryKey(tName, true) newSTable := &MysqlShardTable{ Id: shardTabId, Name: tName + "_shard1", RowTotal: 0, ShardDBId: sdb.Id, Created: time.Now().Unix(), ShardDB: sdb, } err := redis.WriteDB(shardTabId, redis.EncodeData(newSTable), "MysqlShardTable") if err != nil { return nil, err } return newSTable, nil }
func (sdb *MysqlShardDB) InitTable(tName string, sql string) (*MysqlTable, error) { // 为了避免高并发时,整体tabletotal延迟执行导致的total数据不准确, // 所有在后面如果出现错误时, 需要将此添加回退. sdb.TableTotal += 1 tableId := redis.BuildPrimaryKey(tName, true) newTable := &MysqlTable{ Id: tableId, Name: tName, CurGId: 1, RowTotal: 0, Created: time.Now().Unix(), // Columns: make([]TableColumn, 0, 16), Indexes: make([]*Index, 0, 8), } newShardTable, err := sdb.InitShardTable(tName) if err != nil { sdb.TableTotal -= 1 return nil, err } newTable.ShardIds = []string{newShardTable.Id} newTable.Shards = []*MysqlShardTable{newShardTable} // add column data to memery. newTable.RestoreColumnsByDB() err = redis.WriteDB(tableId, redis.EncodeData(newTable), "MysqlTable") if err != nil { sdb.TableTotal -= 1 return nil, err } sdb.UpdateToRedisDB() return newTable, nil }
func (m *MysqlProxy) UpdateToRedisDB() error { return redis.UpdateDB("main", redis.EncodeData(m), "MysqlProxy") }
// get the current db cluster data infomations func (m *MysqlProxy) InitMysqlDB() { // panic(fmt.Sprintf("%#v, %#v", m.ShardDBIds, len(m.ShardDBIds))) if len(m.ShardDBIds) == 0 { // init the shard DB shardDBs := []*schema.MysqlShardDB{} shardDBIds := []string{} m.ShardDBCnt = 0 for _, group := range host.Groups { m.ShardDBCnt++ shardDb, err := m.BuildNewShardDB(&group, "shard"+strconv.Itoa(m.ShardDBCnt)) CheckError(err) shardDBs = append(shardDBs, shardDb) shardDBIds = append(shardDBIds, shardDb.Id) } m.ShardDBs = shardDBs m.ShardDBIds = shardDBIds // to prepare save new data. isUpdated = true // add shard dbs map. schema.Sdbs = shardDBs } else { // 分析数据,并恢复至MysqlProxy结构体中. shardDBs := []*schema.MysqlShardDB{} for _, sid := range m.ShardDBIds { dbs, err := redis.ReadDB("MysqlShardDB", sid) CheckError(err) if len(dbs) != 1 { panic("no found relation shard db for id:" + sid) } sdb := dbs[0][sid].(map[string]interface{}) groupId := sdb["HostGroupId"].(string) curGroup, err := host.GetHostGroupById(groupId) CheckError(err) shardDB := &schema.MysqlShardDB{ Id: sdb["Id"].(string), Name: sdb["Name"].(string), TableTotal: uint64(sdb["TableTotal"].(float64)), SizeTotal: uint64(sdb["SizeTotal"].(float64)), HostGroupId: groupId, Created: int64(sdb["Created"].(float64)), HostGroup: curGroup, } shardDBs = append(shardDBs, shardDB) } m.ShardDBs = shardDBs // add shard dbs map. schema.Sdbs = shardDBs } // listen the sharddb change status. locker := &sync.Mutex{} go func() { for { newShardDB := <-schema.NewShardDBCh locker.Lock() defer locker.Unlock() m.ShardDBIds = append(m.ShardDBIds, newShardDB.Id) m.ShardDBs = append(m.ShardDBs, newShardDB) schema.Sdbs = m.ShardDBs err := redis.UpdateDB("main", redis.EncodeData(m), "MysqlProxy") if err != nil { log.Printf("new shard db listener error:%s", err) } m.ShardDBCnt++ schema.ShardDBCnt = m.ShardDBCnt fmt.Printf("current shard total: %d\n", schema.ShardDBCnt) } }() // listen the table drop action. go func() { for { dropedTable := <-schema.DropedTableCh m.DeleteTable(dropedTable) } }() // panic(fmt.Sprintf("in init shard db: %#v, %#v", m)) }
func (stb *MysqlShardTable) UpdateToRedisDB() error { return redis.UpdateDB(stb.Id, redis.EncodeData(stb), "MysqlShardTable") }
func (sdb *MysqlShardDB) UpdateToRedisDB() error { return redis.UpdateDB(sdb.Id, redis.EncodeData(sdb), "MysqlShardDB") }
func (tbl *MysqlTable) UpdateToRedisDB() error { return redis.UpdateDB(tbl.Id, redis.EncodeData(tbl), "MysqlTable") }
// restore the schema ddl. func (tbl *MysqlTable) BuildNewShardTable() (*MysqlShardTable, error) { curSharded := len(tbl.Shards) tTableName := tbl.Name + "_shard" + strconv.Itoa(curSharded+1) newTabId := redis.BuildPrimaryKey(tTableName, true) shardTable := &MysqlShardTable{ Id: newTabId, Name: tTableName, RowTotal: uint64(0), ShardDBId: "", Created: time.Now().Unix(), ShardDB: nil, } // get bettet group. group := host.GetBetterMasterGroup() shardDB, err := tbl.GetMasterShardDBByGroup(group) if err != nil { return nil, err } shardTable.ShardDBId = shardDB.Id shardTable.ShardDB = shardDB betterHost := host.GetBetterHost(group.Master, "master") ddlSql, err := tbl.GetSchemaDDLByDb() if err != nil { return nil, err } ddlSql = strings.Replace(ddlSql, tbl.Shards[0].Name, tTableName, -1) db, err := betterHost.ConnToDB(shardDB.Name) if err != nil { return nil, err } stmt, err := db.Prepare(ddlSql) if err != nil { return nil, err } _, err = stmt.Exec() if err != nil { return nil, err } stmt.Close() // write the new shard table to redis err = redis.WriteDB(newTabId, redis.EncodeData(shardTable), "MysqlShardTable") if err != nil { return nil, err } tbl.Shards = append(tbl.Shards, shardTable) tbl.ShardIds = append(tbl.ShardIds, newTabId) err = redis.UpdateDB(tbl.Id, redis.EncodeData(tbl), "MysqlTable") if err != nil { return nil, err } return shardTable, nil }