Created
August 20, 2025 09:30
-
-
Save tiancaiamao/5268f66e11cb549d227fd66a9f5941e0 to your computer and use it in GitHub Desktop.
reproduce fk conflict in tidb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "database/sql" | |
| "fmt" | |
| "log" | |
| "math/rand" | |
| "sync" | |
| "time" | |
| _ "github.com/go-sql-driver/mysql" | |
| ) | |
| const ( | |
| dsn = "root@tcp(127.0.0.1:4000)/test?parseTime=true" | |
| concurrency = 600 | |
| parentID = "ZF897PAF4N3DSHJVDPA15HF6RXEMWBCM" | |
| maxChildren = 1000000 | |
| ) | |
| func prepareTable(db *sql.DB) { | |
| _, err := db.Exec(`create table if not exists hosted_zone ( | |
| id varchar(64), | |
| name varchar(1024), | |
| owner varchar(64), | |
| key(id))`) | |
| if err != nil { | |
| log.Fatalf("create table hosted_zone err %s\n", err.Error()) | |
| } | |
| _, err = db.Exec(`create table if not exists geolocation ( | |
| _id bigint(20) unsigned primary key)`) | |
| if err != nil { | |
| log.Fatalf("create table geolocation err %s\n", err.Error()) | |
| } | |
| _, err = db.Exec(`create table if not exists health_check (id varchar(64), key(id))`) | |
| if err != nil { | |
| log.Fatalf("create table geolocation err %s\n", err.Error()) | |
| } | |
| _, err = db.Exec("CREATE TABLE if not exists `resource_record_set` (" + | |
| "`_hosted_zone_id` varchar(64) NOT NULL," + | |
| "`_owner` varchar(64) NOT NULL," + | |
| "`name` varchar(124) NOT NULL," + | |
| "`identifier` varchar(128) NOT NULL DEFAULT 'SIMPLE'," + | |
| "`_name_reversed` varchar(1024) NOT NULL," + | |
| "`_geolocation_id` bigint(20) unsigned DEFAULT NULL," + | |
| "`health_check_id` varchar(64) DEFAULT NULL," + | |
| "`type` enum('SOA','A','TXT','NS','CNAME','MX','NAPTR','PTR','SRV','SPF','AAAA','CAA','DNSKEY','RRSIG','DS','NSEC','NSEC3','CDNSKEY','CDS') NOT NULL," + | |
| "`last_updated_time` timestamp(3) NOT NULL DEFAULT current_timestamp(3)," + | |
| "PRIMARY KEY (`_hosted_zone_id`,`name`,`identifier`,`type`)," + | |
| "CONSTRAINT `resource_record_set_ibfk_2` FOREIGN KEY (`_geolocation_id`) REFERENCES `geolocation` (`_id`) ON DELETE SET NULL," + | |
| "CONSTRAINT `resource_record_set_ibfk_3` FOREIGN KEY (`health_check_id`) REFERENCES `health_check` (`id`) ON DELETE SET NULL," + | |
| "CONSTRAINT `resource_record_set_ibfk_1` FOREIGN KEY (`_hosted_zone_id`) REFERENCES `hosted_zone` (`id`) ON DELETE CASCADE)") | |
| if err != nil { | |
| log.Fatalf("create table resource_record_set err %s\n", err.Error()) | |
| } | |
| } | |
| func main() { | |
| db, err := sql.Open("mysql", dsn) | |
| if err != nil { | |
| log.Fatal(err) | |
| } | |
| defer db.Close() | |
| prepareTable(db); | |
| // ensure the parent record exist | |
| ensureParent(db, parentID) | |
| var wg sync.WaitGroup | |
| wg.Add(concurrency) | |
| for i := 0; i < concurrency; i++ { | |
| go func(worker int) { | |
| defer wg.Done() | |
| stmt, err := db.Prepare(`INSERT INTO resource_record_set | |
| (_hosted_zone_id, name, identifier, type, | |
| _name_reversed, _owner, last_updated_time, _geolocation_id, health_check_id) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`); | |
| if err != nil { | |
| log.Printf("prepare stmt error %v\n", err); | |
| return | |
| } | |
| for j := 0; j < maxChildren; j++ { | |
| name := fmt.Sprintf("%d_child_%d_%d.example.com", worker, j, rand.Intn(1000000)) | |
| reversed := fmt.Sprintf("%s.reversed", name) | |
| typeVal := "A" | |
| owner := "000000000001" | |
| identifier := "SIMPLE" | |
| _, err := stmt.Exec(parentID, name, identifier, typeVal, | |
| reversed, owner, time.Now(), | |
| rand.Intn(10), fmt.Sprintf("%d.health_check", rand.Intn(10))) | |
| if err != nil { | |
| log.Printf("[worker %d] insert error: %v\n", worker, err) | |
| } | |
| } | |
| }(i) | |
| } | |
| wg.Wait() | |
| fmt.Println("All insertions done.") | |
| } | |
| func ensureParent(db *sql.DB, id string) { | |
| _, err := db.Exec(` | |
| INSERT INTO hosted_zone (id, name, owner) | |
| VALUES (?, ?, ?) | |
| ON DUPLICATE KEY UPDATE name=name | |
| `, id, "test_zone", "000000000001") | |
| if err != nil { | |
| log.Fatalf("failed to ensure parent: %v", err) | |
| } | |
| for i:=0; i<10; i++ { | |
| _, err = db.Exec(`INSERT ignore INTO geolocation VALUES (?)`, i) | |
| if err != nil { | |
| log.Fatalf("failed to ensure parent geolocation: %v", err) | |
| } | |
| } | |
| for i:=0; i<10; i++ { | |
| _, err = db.Exec(fmt.Sprintf(`INSERT ignore INTO health_check VALUES ('%d.health_check')`, i)) | |
| if err != nil { | |
| log.Fatalf("failed to ensure parent health_check: %v", err) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment