From d67cc556489ec400e10569028ee5745c88d5ce8a Mon Sep 17 00:00:00 2001 From: Lucy Zhang Date: Wed, 24 Feb 2021 23:02:45 -0500 Subject: [PATCH] sql,schemachanger: disallow concurrent execution for new schema changes This PR prevents new-style schema changes from running concurrently with any other schema changes, in two ways: 1. If there are mutations in progress (from either new or old schema changes) when attempting to plan a new-style schema change, we wait and poll until there are no mutations, and then restart the transaction. 2. If we try to write an old-style schema change job while there is a new-style schema change on the table, which is detected via a new field on the table descriptor for the new-style schema change job ID, an error is returned. This effectively prevents all schema changes, even the ones without mutations. Most of this commit consists of testing. Testing knobs for the new schema changer are introduced. We also now accumulate the statements involved in the schema change, as strings, in the schema changer state in `extraTxnState`. The executor now takes an argument to inject more relevant state into the testing knobs, including the aforementioned statements. Release justification: Non-production code change (the new schema changer is disabled for 21.1) Release note: None --- pkg/BUILD.bazel | 1 + pkg/base/testing_knobs.go | 1 + pkg/server/BUILD.bazel | 4 +- pkg/server/server_sql.go | 6 + pkg/sql/catalog/descpb/structured.pb.go | 819 +++++++++--------- pkg/sql/catalog/descpb/structured.proto | 6 + pkg/sql/catalog/tabledesc/structured.go | 11 + pkg/sql/catalog/tabledesc/validate_test.go | 1 + pkg/sql/conn_executor.go | 53 +- pkg/sql/drop_table.go | 12 + pkg/sql/exec_util.go | 3 +- .../testdata/show_trace_nonmetamorphic | 12 +- pkg/sql/schema_change_plan_node.go | 76 +- pkg/sql/schema_changer_state.go | 4 + pkg/sql/schemachanger/BUILD.bazel | 37 + pkg/sql/schemachanger/main_test.go | 33 + pkg/sql/schemachanger/scbuild/builder.go | 67 +- pkg/sql/schemachanger/scexec/BUILD.bazel | 1 + pkg/sql/schemachanger/scexec/executor.go | 85 +- .../scexec/executor_external_test.go | 18 +- pkg/sql/schemachanger/schemachanger_test.go | 417 +++++++++ pkg/sql/schemachanger/scjob/BUILD.bazel | 1 + pkg/sql/schemachanger/scjob/job.go | 28 +- pkg/sql/table.go | 10 + 24 files changed, 1271 insertions(+), 435 deletions(-) create mode 100644 pkg/sql/schemachanger/BUILD.bazel create mode 100644 pkg/sql/schemachanger/main_test.go create mode 100644 pkg/sql/schemachanger/schemachanger_test.go diff --git a/pkg/BUILD.bazel b/pkg/BUILD.bazel index bd6eda8a3bb2..1d0ea5da1325 100644 --- a/pkg/BUILD.bazel +++ b/pkg/BUILD.bazel @@ -236,6 +236,7 @@ ALL_TESTS = [ "//pkg/sql/schemachanger/scbuild:scbuild_test", "//pkg/sql/schemachanger/scexec:scexec_test", "//pkg/sql/schemachanger/scpb:scpb_test", + "//pkg/sql/schemachanger:schemachanger_test", "//pkg/sql/sem/builtins:builtins_test", "//pkg/sql/sem/tree/eval_test:eval_test_test", "//pkg/sql/sem/tree:tree_test", diff --git a/pkg/base/testing_knobs.go b/pkg/base/testing_knobs.go index 541827910bba..a1302fa0d973 100644 --- a/pkg/base/testing_knobs.go +++ b/pkg/base/testing_knobs.go @@ -25,6 +25,7 @@ type TestingKnobs struct { SQLExecutor ModuleTestingKnobs SQLLeaseManager ModuleTestingKnobs SQLSchemaChanger ModuleTestingKnobs + SQLNewSchemaChanger ModuleTestingKnobs SQLTypeSchemaChanger ModuleTestingKnobs GCJob ModuleTestingKnobs PGWireTestingKnobs ModuleTestingKnobs diff --git a/pkg/server/BUILD.bazel b/pkg/server/BUILD.bazel index 65cdb1528d3b..8d8d896b3412 100644 --- a/pkg/server/BUILD.bazel +++ b/pkg/server/BUILD.bazel @@ -119,6 +119,7 @@ go_library( "//pkg/sql/physicalplan", "//pkg/sql/querycache", "//pkg/sql/roleoption", + "//pkg/sql/schemachanger/scexec", "//pkg/sql/schemachanger/scjob", "//pkg/sql/sem/tree", "//pkg/sql/sessiondata", @@ -232,7 +233,6 @@ go_library( go_test( name = "server_test", - size = "medium", srcs = [ "admin_cluster_test.go", "admin_test.go", @@ -265,8 +265,6 @@ go_test( ], data = glob(["testdata/**"]), embed = [":server"], - shard_count = 16, - tags = ["broken_in_bazel"], deps = [ "//pkg/base", "//pkg/build", diff --git a/pkg/server/server_sql.go b/pkg/server/server_sql.go index 3c1d82782ba4..62043187beaf 100644 --- a/pkg/server/server_sql.go +++ b/pkg/server/server_sql.go @@ -56,6 +56,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/optionalnodeliveness" "github.com/cockroachdb/cockroach/pkg/sql/pgwire" "github.com/cockroachdb/cockroach/pkg/sql/querycache" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scexec" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" "github.com/cockroachdb/cockroach/pkg/sql/sessiondatapb" @@ -544,6 +545,11 @@ func newSQLServer(ctx context.Context, cfg sqlServerArgs) (*SQLServer, error) { } else { execCfg.SchemaChangerTestingKnobs = new(sql.SchemaChangerTestingKnobs) } + if sqlNewSchemaChangerTestingKnobs := cfg.TestingKnobs.SQLNewSchemaChanger; sqlNewSchemaChangerTestingKnobs != nil { + execCfg.NewSchemaChangerTestingKnobs = sqlNewSchemaChangerTestingKnobs.(*scexec.NewSchemaChangerTestingKnobs) + } else { + execCfg.NewSchemaChangerTestingKnobs = new(scexec.NewSchemaChangerTestingKnobs) + } if sqlTypeSchemaChangerTestingKnobs := cfg.TestingKnobs.SQLTypeSchemaChanger; sqlTypeSchemaChangerTestingKnobs != nil { execCfg.TypeSchemaChangerTestingKnobs = sqlTypeSchemaChangerTestingKnobs.(*sql.TypeSchemaChangerTestingKnobs) } else { diff --git a/pkg/sql/catalog/descpb/structured.pb.go b/pkg/sql/catalog/descpb/structured.pb.go index 096af5762117..bc76e6c01964 100644 --- a/pkg/sql/catalog/descpb/structured.pb.go +++ b/pkg/sql/catalog/descpb/structured.pb.go @@ -75,7 +75,7 @@ func (x *ConstraintValidity) UnmarshalJSON(data []byte) error { return nil } func (ConstraintValidity) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{0} + return fileDescriptor_structured_f098f06e2df5476a, []int{0} } // SystemColumnKind is an enum representing the different kind of system @@ -120,7 +120,7 @@ func (x *SystemColumnKind) UnmarshalJSON(data []byte) error { return nil } func (SystemColumnKind) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{1} + return fileDescriptor_structured_f098f06e2df5476a, []int{1} } // State indicates whether a descriptor is public (i.e., normally visible, @@ -172,7 +172,7 @@ func (x *DescriptorState) UnmarshalJSON(data []byte) error { return nil } func (DescriptorState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{2} + return fileDescriptor_structured_f098f06e2df5476a, []int{2} } // SurvivalGoal is the survival goal for a database. @@ -211,7 +211,7 @@ func (x *SurvivalGoal) UnmarshalJSON(data []byte) error { return nil } func (SurvivalGoal) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{3} + return fileDescriptor_structured_f098f06e2df5476a, []int{3} } type ForeignKeyReference_Action int32 @@ -256,7 +256,7 @@ func (x *ForeignKeyReference_Action) UnmarshalJSON(data []byte) error { return nil } func (ForeignKeyReference_Action) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{0, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{0, 0} } // Match is the algorithm used to compare composite keys. @@ -296,7 +296,7 @@ func (x *ForeignKeyReference_Match) UnmarshalJSON(data []byte) error { return nil } func (ForeignKeyReference_Match) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{0, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{0, 1} } // The direction of a column in the index. @@ -333,7 +333,7 @@ func (x *IndexDescriptor_Direction) UnmarshalJSON(data []byte) error { return nil } func (IndexDescriptor_Direction) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{8, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{8, 0} } // The type of the index. @@ -370,7 +370,7 @@ func (x *IndexDescriptor_Type) UnmarshalJSON(data []byte) error { return nil } func (IndexDescriptor_Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{8, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{8, 1} } type ConstraintToUpdate_ConstraintType int32 @@ -416,7 +416,7 @@ func (x *ConstraintToUpdate_ConstraintType) UnmarshalJSON(data []byte) error { return nil } func (ConstraintToUpdate_ConstraintType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{9, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{9, 0} } // A descriptor within a mutation is unavailable for reads, writes @@ -481,7 +481,7 @@ func (x *DescriptorMutation_State) UnmarshalJSON(data []byte) error { return nil } func (DescriptorMutation_State) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{13, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{13, 0} } // Direction of mutation. @@ -524,7 +524,7 @@ func (x *DescriptorMutation_Direction) UnmarshalJSON(data []byte) error { return nil } func (DescriptorMutation_Direction) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{13, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{13, 1} } // AuditMode indicates which auditing actions to take when this table is used. @@ -561,7 +561,7 @@ func (x *TableDescriptor_AuditMode) UnmarshalJSON(data []byte) error { return nil } func (TableDescriptor_AuditMode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 0} } // Represents the kind of type that this type descriptor represents. @@ -606,7 +606,7 @@ func (x *TypeDescriptor_Kind) UnmarshalJSON(data []byte) error { return nil } func (TypeDescriptor_Kind) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{17, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{17, 0} } // Represents what operations are allowed on this ENUM member. @@ -647,7 +647,7 @@ func (x *TypeDescriptor_EnumMember_Capability) UnmarshalJSON(data []byte) error return nil } func (TypeDescriptor_EnumMember_Capability) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{17, 0, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{17, 0, 0} } type TypeDescriptor_EnumMember_Direction int32 @@ -689,7 +689,7 @@ func (x *TypeDescriptor_EnumMember_Direction) UnmarshalJSON(data []byte) error { return nil } func (TypeDescriptor_EnumMember_Direction) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{17, 0, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{17, 0, 1} } // ForeignKeyReference is deprecated, replaced by ForeignKeyConstraint in v19.2 @@ -719,7 +719,7 @@ func (m *ForeignKeyReference) Reset() { *m = ForeignKeyReference{} } func (m *ForeignKeyReference) String() string { return proto.CompactTextString(m) } func (*ForeignKeyReference) ProtoMessage() {} func (*ForeignKeyReference) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{0} + return fileDescriptor_structured_f098f06e2df5476a, []int{0} } func (m *ForeignKeyReference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -767,7 +767,7 @@ func (m *ForeignKeyConstraint) Reset() { *m = ForeignKeyConstraint{} } func (m *ForeignKeyConstraint) String() string { return proto.CompactTextString(m) } func (*ForeignKeyConstraint) ProtoMessage() {} func (*ForeignKeyConstraint) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{1} + return fileDescriptor_structured_f098f06e2df5476a, []int{1} } func (m *ForeignKeyConstraint) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -809,7 +809,7 @@ func (m *UniqueWithoutIndexConstraint) Reset() { *m = UniqueWithoutIndex func (m *UniqueWithoutIndexConstraint) String() string { return proto.CompactTextString(m) } func (*UniqueWithoutIndexConstraint) ProtoMessage() {} func (*UniqueWithoutIndexConstraint) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{2} + return fileDescriptor_structured_f098f06e2df5476a, []int{2} } func (m *UniqueWithoutIndexConstraint) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -877,7 +877,7 @@ func (m *ColumnDescriptor) Reset() { *m = ColumnDescriptor{} } func (m *ColumnDescriptor) String() string { return proto.CompactTextString(m) } func (*ColumnDescriptor) ProtoMessage() {} func (*ColumnDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{3} + return fileDescriptor_structured_f098f06e2df5476a, []int{3} } func (m *ColumnDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -933,7 +933,7 @@ func (m *ColumnFamilyDescriptor) Reset() { *m = ColumnFamilyDescriptor{} func (m *ColumnFamilyDescriptor) String() string { return proto.CompactTextString(m) } func (*ColumnFamilyDescriptor) ProtoMessage() {} func (*ColumnFamilyDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{4} + return fileDescriptor_structured_f098f06e2df5476a, []int{4} } func (m *ColumnFamilyDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -979,7 +979,7 @@ func (m *InterleaveDescriptor) Reset() { *m = InterleaveDescriptor{} } func (m *InterleaveDescriptor) String() string { return proto.CompactTextString(m) } func (*InterleaveDescriptor) ProtoMessage() {} func (*InterleaveDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{5} + return fileDescriptor_structured_f098f06e2df5476a, []int{5} } func (m *InterleaveDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1023,7 +1023,7 @@ func (m *InterleaveDescriptor_Ancestor) Reset() { *m = InterleaveDescrip func (m *InterleaveDescriptor_Ancestor) String() string { return proto.CompactTextString(m) } func (*InterleaveDescriptor_Ancestor) ProtoMessage() {} func (*InterleaveDescriptor_Ancestor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{5, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{5, 0} } func (m *InterleaveDescriptor_Ancestor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1078,7 +1078,7 @@ func (m *ShardedDescriptor) Reset() { *m = ShardedDescriptor{} } func (m *ShardedDescriptor) String() string { return proto.CompactTextString(m) } func (*ShardedDescriptor) ProtoMessage() {} func (*ShardedDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{6} + return fileDescriptor_structured_f098f06e2df5476a, []int{6} } func (m *ShardedDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1129,7 +1129,7 @@ func (m *PartitioningDescriptor) Reset() { *m = PartitioningDescriptor{} func (m *PartitioningDescriptor) String() string { return proto.CompactTextString(m) } func (*PartitioningDescriptor) ProtoMessage() {} func (*PartitioningDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{7} + return fileDescriptor_structured_f098f06e2df5476a, []int{7} } func (m *PartitioningDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1172,7 +1172,7 @@ func (m *PartitioningDescriptor_List) Reset() { *m = PartitioningDescrip func (m *PartitioningDescriptor_List) String() string { return proto.CompactTextString(m) } func (*PartitioningDescriptor_List) ProtoMessage() {} func (*PartitioningDescriptor_List) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{7, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{7, 0} } func (m *PartitioningDescriptor_List) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1217,7 +1217,7 @@ func (m *PartitioningDescriptor_Range) Reset() { *m = PartitioningDescri func (m *PartitioningDescriptor_Range) String() string { return proto.CompactTextString(m) } func (*PartitioningDescriptor_Range) ProtoMessage() {} func (*PartitioningDescriptor_Range) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{7, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{7, 1} } func (m *PartitioningDescriptor_Range) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1384,7 +1384,7 @@ func (m *IndexDescriptor) Reset() { *m = IndexDescriptor{} } func (m *IndexDescriptor) String() string { return proto.CompactTextString(m) } func (*IndexDescriptor) ProtoMessage() {} func (*IndexDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{8} + return fileDescriptor_structured_f098f06e2df5476a, []int{8} } func (m *IndexDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1436,7 +1436,7 @@ func (m *ConstraintToUpdate) Reset() { *m = ConstraintToUpdate{} } func (m *ConstraintToUpdate) String() string { return proto.CompactTextString(m) } func (*ConstraintToUpdate) ProtoMessage() {} func (*ConstraintToUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{9} + return fileDescriptor_structured_f098f06e2df5476a, []int{9} } func (m *ConstraintToUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1487,7 +1487,7 @@ func (m *PrimaryKeySwap) Reset() { *m = PrimaryKeySwap{} } func (m *PrimaryKeySwap) String() string { return proto.CompactTextString(m) } func (*PrimaryKeySwap) ProtoMessage() {} func (*PrimaryKeySwap) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{10} + return fileDescriptor_structured_f098f06e2df5476a, []int{10} } func (m *PrimaryKeySwap) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1535,7 +1535,7 @@ func (m *PrimaryKeySwap_LocalityConfigSwap) Reset() { *m = PrimaryKeySwa func (m *PrimaryKeySwap_LocalityConfigSwap) String() string { return proto.CompactTextString(m) } func (*PrimaryKeySwap_LocalityConfigSwap) ProtoMessage() {} func (*PrimaryKeySwap_LocalityConfigSwap) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{10, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{10, 0} } func (m *PrimaryKeySwap_LocalityConfigSwap) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1575,7 +1575,7 @@ func (m *ComputedColumnSwap) Reset() { *m = ComputedColumnSwap{} } func (m *ComputedColumnSwap) String() string { return proto.CompactTextString(m) } func (*ComputedColumnSwap) ProtoMessage() {} func (*ComputedColumnSwap) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{11} + return fileDescriptor_structured_f098f06e2df5476a, []int{11} } func (m *ComputedColumnSwap) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1623,7 +1623,7 @@ func (m *MaterializedViewRefresh) Reset() { *m = MaterializedViewRefresh func (m *MaterializedViewRefresh) String() string { return proto.CompactTextString(m) } func (*MaterializedViewRefresh) ProtoMessage() {} func (*MaterializedViewRefresh) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{12} + return fileDescriptor_structured_f098f06e2df5476a, []int{12} } func (m *MaterializedViewRefresh) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1680,7 +1680,7 @@ func (m *DescriptorMutation) Reset() { *m = DescriptorMutation{} } func (m *DescriptorMutation) String() string { return proto.CompactTextString(m) } func (*DescriptorMutation) ProtoMessage() {} func (*DescriptorMutation) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{13} + return fileDescriptor_structured_f098f06e2df5476a, []int{13} } func (m *DescriptorMutation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2018,7 +2018,7 @@ func (m *NameInfo) Reset() { *m = NameInfo{} } func (m *NameInfo) String() string { return proto.CompactTextString(m) } func (*NameInfo) ProtoMessage() {} func (*NameInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{14} + return fileDescriptor_structured_f098f06e2df5476a, []int{14} } func (m *NameInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2146,6 +2146,10 @@ type TableDescriptor struct { // Mutation jobs queued for execution in a FIFO order. Remains synchronized // with the mutations list. MutationJobs []TableDescriptor_MutationJob `protobuf:"bytes,27,rep,name=mutationJobs" json:"mutationJobs"` + // The job associated with a schema change job run in the new schema changer + // (in sql/schemachanger), if one exists. Only one such job can exist at a + // time. + NewSchemaChangeJobID int64 `protobuf:"varint,45,opt,name=new_schema_change_job_id,json=newSchemaChangeJobId" json:"new_schema_change_job_id"` // The presence of sequence_opts indicates that this descriptor is for a sequence. SequenceOpts *TableDescriptor_SequenceOpts `protobuf:"bytes,28,opt,name=sequence_opts,json=sequenceOpts" json:"sequence_opts,omitempty"` // The drop time is set when a table is truncated or dropped, @@ -2208,7 +2212,7 @@ func (m *TableDescriptor) Reset() { *m = TableDescriptor{} } func (m *TableDescriptor) String() string { return proto.CompactTextString(m) } func (*TableDescriptor) ProtoMessage() {} func (*TableDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15} + return fileDescriptor_structured_f098f06e2df5476a, []int{15} } func (m *TableDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2423,6 +2427,13 @@ func (m *TableDescriptor) GetMutationJobs() []TableDescriptor_MutationJob { return nil } +func (m *TableDescriptor) GetNewSchemaChangeJobID() int64 { + if m != nil { + return m.NewSchemaChangeJobID + } + return 0 +} + func (m *TableDescriptor) GetSequenceOpts() *TableDescriptor_SequenceOpts { if m != nil { return m.SequenceOpts @@ -2536,7 +2547,7 @@ func (m *TableDescriptor_SchemaChangeLease) Reset() { *m = TableDescript func (m *TableDescriptor_SchemaChangeLease) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_SchemaChangeLease) ProtoMessage() {} func (*TableDescriptor_SchemaChangeLease) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 0} } func (m *TableDescriptor_SchemaChangeLease) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2582,7 +2593,7 @@ func (m *TableDescriptor_CheckConstraint) Reset() { *m = TableDescriptor func (m *TableDescriptor_CheckConstraint) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_CheckConstraint) ProtoMessage() {} func (*TableDescriptor_CheckConstraint) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 1} } func (m *TableDescriptor_CheckConstraint) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2627,7 +2638,7 @@ func (m *TableDescriptor_Reference) Reset() { *m = TableDescriptor_Refer func (m *TableDescriptor_Reference) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_Reference) ProtoMessage() {} func (*TableDescriptor_Reference) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 2} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 2} } func (m *TableDescriptor_Reference) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2665,7 +2676,7 @@ func (m *TableDescriptor_MutationJob) Reset() { *m = TableDescriptor_Mut func (m *TableDescriptor_MutationJob) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_MutationJob) ProtoMessage() {} func (*TableDescriptor_MutationJob) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 3} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 3} } func (m *TableDescriptor_MutationJob) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2711,7 +2722,7 @@ func (m *TableDescriptor_SequenceOpts) Reset() { *m = TableDescriptor_Se func (m *TableDescriptor_SequenceOpts) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_SequenceOpts) ProtoMessage() {} func (*TableDescriptor_SequenceOpts) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 4} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 4} } func (m *TableDescriptor_SequenceOpts) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2751,7 +2762,7 @@ func (m *TableDescriptor_SequenceOpts_SequenceOwner) String() string { } func (*TableDescriptor_SequenceOpts_SequenceOwner) ProtoMessage() {} func (*TableDescriptor_SequenceOpts_SequenceOwner) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 4, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 4, 0} } func (m *TableDescriptor_SequenceOpts_SequenceOwner) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2791,7 +2802,7 @@ func (m *TableDescriptor_Replacement) Reset() { *m = TableDescriptor_Rep func (m *TableDescriptor_Replacement) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_Replacement) ProtoMessage() {} func (*TableDescriptor_Replacement) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 5} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 5} } func (m *TableDescriptor_Replacement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2828,7 +2839,7 @@ func (m *TableDescriptor_GCDescriptorMutation) Reset() { *m = TableDescr func (m *TableDescriptor_GCDescriptorMutation) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_GCDescriptorMutation) ProtoMessage() {} func (*TableDescriptor_GCDescriptorMutation) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 6} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 6} } func (m *TableDescriptor_GCDescriptorMutation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2865,7 +2876,7 @@ func (m *TableDescriptor_LocalityConfig) Reset() { *m = TableDescriptor_ func (m *TableDescriptor_LocalityConfig) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_LocalityConfig) ProtoMessage() {} func (*TableDescriptor_LocalityConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 7} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 7} } func (m *TableDescriptor_LocalityConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3059,7 +3070,7 @@ func (m *TableDescriptor_LocalityConfig_RegionalByTable) String() string { } func (*TableDescriptor_LocalityConfig_RegionalByTable) ProtoMessage() {} func (*TableDescriptor_LocalityConfig_RegionalByTable) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 7, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 7, 0} } func (m *TableDescriptor_LocalityConfig_RegionalByTable) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3097,7 +3108,7 @@ func (m *TableDescriptor_LocalityConfig_RegionalByRow) String() string { } func (*TableDescriptor_LocalityConfig_RegionalByRow) ProtoMessage() {} func (*TableDescriptor_LocalityConfig_RegionalByRow) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 7, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 7, 1} } func (m *TableDescriptor_LocalityConfig_RegionalByRow) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3129,7 +3140,7 @@ func (m *TableDescriptor_LocalityConfig_Global) Reset() { *m = TableDesc func (m *TableDescriptor_LocalityConfig_Global) String() string { return proto.CompactTextString(m) } func (*TableDescriptor_LocalityConfig_Global) ProtoMessage() {} func (*TableDescriptor_LocalityConfig_Global) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{15, 7, 2} + return fileDescriptor_structured_f098f06e2df5476a, []int{15, 7, 2} } func (m *TableDescriptor_LocalityConfig_Global) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3180,7 +3191,7 @@ func (m *DatabaseDescriptor) Reset() { *m = DatabaseDescriptor{} } func (m *DatabaseDescriptor) String() string { return proto.CompactTextString(m) } func (*DatabaseDescriptor) ProtoMessage() {} func (*DatabaseDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{16} + return fileDescriptor_structured_f098f06e2df5476a, []int{16} } func (m *DatabaseDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3288,7 +3299,7 @@ func (m *DatabaseDescriptor_SchemaInfo) Reset() { *m = DatabaseDescripto func (m *DatabaseDescriptor_SchemaInfo) String() string { return proto.CompactTextString(m) } func (*DatabaseDescriptor_SchemaInfo) ProtoMessage() {} func (*DatabaseDescriptor_SchemaInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{16, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{16, 0} } func (m *DatabaseDescriptor_SchemaInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3328,7 +3339,7 @@ func (m *DatabaseDescriptor_RegionConfig) Reset() { *m = DatabaseDescrip func (m *DatabaseDescriptor_RegionConfig) String() string { return proto.CompactTextString(m) } func (*DatabaseDescriptor_RegionConfig) ProtoMessage() {} func (*DatabaseDescriptor_RegionConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{16, 2} + return fileDescriptor_structured_f098f06e2df5476a, []int{16, 2} } func (m *DatabaseDescriptor_RegionConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3363,7 +3374,7 @@ func (m *DatabaseDescriptor_RegionConfig_Region) Reset() { func (m *DatabaseDescriptor_RegionConfig_Region) String() string { return proto.CompactTextString(m) } func (*DatabaseDescriptor_RegionConfig_Region) ProtoMessage() {} func (*DatabaseDescriptor_RegionConfig_Region) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{16, 2, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{16, 2, 0} } func (m *DatabaseDescriptor_RegionConfig_Region) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3426,7 +3437,7 @@ func (m *TypeDescriptor) Reset() { *m = TypeDescriptor{} } func (m *TypeDescriptor) String() string { return proto.CompactTextString(m) } func (*TypeDescriptor) ProtoMessage() {} func (*TypeDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{17} + return fileDescriptor_structured_f098f06e2df5476a, []int{17} } func (m *TypeDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3575,7 +3586,7 @@ func (m *TypeDescriptor_EnumMember) Reset() { *m = TypeDescriptor_EnumMe func (m *TypeDescriptor_EnumMember) String() string { return proto.CompactTextString(m) } func (*TypeDescriptor_EnumMember) ProtoMessage() {} func (*TypeDescriptor_EnumMember) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{17, 0} + return fileDescriptor_structured_f098f06e2df5476a, []int{17, 0} } func (m *TypeDescriptor_EnumMember) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3611,7 +3622,7 @@ func (m *TypeDescriptor_RegionConfig) Reset() { *m = TypeDescriptor_Regi func (m *TypeDescriptor_RegionConfig) String() string { return proto.CompactTextString(m) } func (*TypeDescriptor_RegionConfig) ProtoMessage() {} func (*TypeDescriptor_RegionConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{17, 1} + return fileDescriptor_structured_f098f06e2df5476a, []int{17, 1} } func (m *TypeDescriptor_RegionConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3659,7 +3670,7 @@ func (m *SchemaDescriptor) Reset() { *m = SchemaDescriptor{} } func (m *SchemaDescriptor) String() string { return proto.CompactTextString(m) } func (*SchemaDescriptor) ProtoMessage() {} func (*SchemaDescriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{18} + return fileDescriptor_structured_f098f06e2df5476a, []int{18} } func (m *SchemaDescriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3762,7 +3773,7 @@ func (m *Descriptor) Reset() { *m = Descriptor{} } func (m *Descriptor) String() string { return proto.CompactTextString(m) } func (*Descriptor) ProtoMessage() {} func (*Descriptor) Descriptor() ([]byte, []int) { - return fileDescriptor_structured_712f2ac8323ba095, []int{19} + return fileDescriptor_structured_f098f06e2df5476a, []int{19} } func (m *Descriptor) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5192,6 +5203,9 @@ func (this *TableDescriptor) Equal(that interface{}) bool { return false } } + if this.NewSchemaChangeJobID != that1.NewSchemaChangeJobID { + return false + } if !this.SequenceOpts.Equal(that1.SequenceOpts) { return false } @@ -7650,6 +7664,11 @@ func (m *TableDescriptor) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0 } i++ + dAtA[i] = 0xe8 + i++ + dAtA[i] = 0x2 + i++ + i = encodeVarintStructured(dAtA, i, uint64(m.NewSchemaChangeJobID)) return i, nil } @@ -9229,6 +9248,7 @@ func (m *TableDescriptor) Size() (n int) { } } n += 3 + n += 2 + sovStructured(uint64(m.NewSchemaChangeJobID)) return n } @@ -15306,6 +15326,25 @@ func (m *TableDescriptor) Unmarshal(dAtA []byte) error { } } m.PartitionAllBy = bool(v != 0) + case 45: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NewSchemaChangeJobID", wireType) + } + m.NewSchemaChangeJobID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowStructured + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NewSchemaChangeJobID |= (int64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipStructured(dAtA[iNdEx:]) @@ -18794,344 +18833,346 @@ var ( ) func init() { - proto.RegisterFile("sql/catalog/descpb/structured.proto", fileDescriptor_structured_712f2ac8323ba095) + proto.RegisterFile("sql/catalog/descpb/structured.proto", fileDescriptor_structured_f098f06e2df5476a) } -var fileDescriptor_structured_712f2ac8323ba095 = []byte{ - // 5354 bytes of a gzipped FileDescriptorProto +var fileDescriptor_structured_f098f06e2df5476a = []byte{ + // 5384 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x3c, 0xcb, 0x73, 0x1b, 0xe7, 0x7d, 0xc4, 0x1b, 0xf8, 0xe1, 0xb5, 0xfc, 0x44, 0x49, 0x30, 0x63, 0x93, 0x14, 0x64, 0xd9, 0xb4, 0x1c, 0x53, 0x32, 0xed, 0x38, 0xb2, 0x1d, 0xa7, 0x06, 0x09, 0x50, 0x84, 0x44, 0x02, 0xf4, 0x92, 0x94, 0x9c, 0xa4, 0xc9, 0x66, 0x89, 0xfd, 0x00, 0xae, 0xb5, 0xd8, 0x85, 0x76, 0x17, 0x22, 0x91, 0xe9, 0xa1, 0x93, 0x53, 0x4f, 0x7d, 0x1c, 0x7a, 0xea, 0x64, 0x9a, 0xe9, 0x64, 0xa6, 0xb9, 0x65, - 0x32, 0x9d, 0x69, 0x6f, 0xbd, 0x36, 0xc7, 0x74, 0x3a, 0x93, 0xc9, 0x89, 0xd3, 0xd2, 0x3d, 0xf4, - 0x0f, 0xe8, 0xa1, 0xe3, 0xe9, 0xa1, 0xf3, 0xbd, 0xf6, 0x81, 0x97, 0x40, 0xd2, 0xcd, 0xc1, 0x1e, - 0xee, 0xef, 0xf5, 0xbd, 0x7e, 0xef, 0xef, 0x83, 0xe0, 0xb6, 0xf3, 0xdc, 0xb8, 0xd7, 0x52, 0x5d, - 0xd5, 0xb0, 0x3a, 0xf7, 0x34, 0xec, 0xb4, 0x7a, 0x47, 0xf7, 0x1c, 0xd7, 0xee, 0xb7, 0xdc, 0xbe, - 0x8d, 0xb5, 0xb5, 0x9e, 0x6d, 0xb9, 0x16, 0xba, 0xde, 0xb2, 0x5a, 0xcf, 0x6c, 0x4b, 0x6d, 0x1d, - 0xaf, 0x39, 0xcf, 0x0d, 0xf2, 0xdf, 0x91, 0xea, 0xe0, 0xc5, 0x52, 0xdf, 0xd5, 0x8d, 0x7b, 0xc7, - 0x46, 0xeb, 0x9e, 0xab, 0x77, 0xb1, 0xe3, 0xaa, 0xdd, 0x1e, 0x63, 0x58, 0x2c, 0x8f, 0x91, 0xda, - 0xb3, 0xf5, 0x17, 0xba, 0x81, 0x3b, 0x98, 0xd3, 0x5c, 0x27, 0x34, 0xee, 0xa0, 0x87, 0x1d, 0xf6, - 0x7f, 0x0e, 0x7e, 0xa5, 0x83, 0xad, 0x7b, 0x1d, 0x6c, 0xe9, 0xa6, 0x86, 0x4f, 0xef, 0xb5, 0x2c, - 0xb3, 0xad, 0x77, 0x38, 0x6a, 0xa1, 0x63, 0x75, 0x2c, 0xfa, 0xe7, 0x3d, 0xf2, 0x17, 0x83, 0x96, - 0x7f, 0x9a, 0x80, 0x6b, 0x5b, 0x96, 0x8d, 0xf5, 0x8e, 0xf9, 0x18, 0x0f, 0x64, 0xdc, 0xc6, 0x36, - 0x36, 0x5b, 0x18, 0xad, 0x40, 0xc2, 0x55, 0x8f, 0x0c, 0x5c, 0x8a, 0xac, 0x44, 0x56, 0xf3, 0x1b, - 0xf0, 0x9b, 0xb3, 0xe5, 0xb9, 0xaf, 0xce, 0x96, 0xa3, 0xf5, 0xaa, 0xcc, 0x10, 0xe8, 0x0e, 0x24, - 0xe8, 0x28, 0xa5, 0x28, 0xa5, 0x28, 0x72, 0x8a, 0x54, 0x9d, 0x00, 0x09, 0x19, 0xc5, 0xa2, 0x12, - 0xc4, 0x4d, 0xb5, 0x8b, 0x4b, 0xb1, 0x95, 0xc8, 0x6a, 0x66, 0x23, 0x4e, 0xa8, 0x64, 0x0a, 0x41, - 0x8f, 0x21, 0xfd, 0x42, 0x35, 0x74, 0x4d, 0x77, 0x07, 0xa5, 0xf8, 0x4a, 0x64, 0xb5, 0xb0, 0xfe, - 0xd6, 0xda, 0xd8, 0xad, 0x5a, 0xdb, 0xb4, 0x4c, 0xc7, 0xb5, 0x55, 0xdd, 0x74, 0x9f, 0x70, 0x06, - 0x2e, 0xc8, 0x13, 0x80, 0xee, 0xc3, 0xbc, 0x73, 0xac, 0xda, 0x58, 0x53, 0x7a, 0x36, 0x6e, 0xeb, - 0xa7, 0x8a, 0x81, 0xcd, 0x52, 0x62, 0x25, 0xb2, 0x9a, 0xe0, 0xa4, 0x45, 0x86, 0xde, 0xa3, 0xd8, - 0x1d, 0x6c, 0xa2, 0x03, 0xc8, 0x58, 0xa6, 0xa2, 0x61, 0x03, 0xbb, 0xb8, 0x94, 0xa4, 0xe3, 0xbf, - 0x3b, 0x61, 0xfc, 0x31, 0x1b, 0xb4, 0x56, 0x69, 0xb9, 0xba, 0x65, 0x8a, 0x79, 0x58, 0x66, 0x95, - 0x0a, 0xe2, 0x52, 0xfb, 0x3d, 0x4d, 0x75, 0x71, 0x29, 0x75, 0x65, 0xa9, 0x87, 0x54, 0x10, 0xda, - 0x81, 0x44, 0x57, 0x75, 0x5b, 0xc7, 0xa5, 0x34, 0x95, 0x78, 0xff, 0x02, 0x12, 0x77, 0x09, 0x1f, - 0x17, 0xc8, 0x84, 0x94, 0x9f, 0x42, 0x92, 0x8d, 0x83, 0xf2, 0x90, 0x69, 0x34, 0x95, 0xca, 0xe6, - 0x41, 0xbd, 0xd9, 0x90, 0xe6, 0x50, 0x0e, 0xd2, 0x72, 0x6d, 0xff, 0x40, 0xae, 0x6f, 0x1e, 0x48, - 0x11, 0xf2, 0xb5, 0x5f, 0x3b, 0x50, 0x1a, 0x87, 0x3b, 0x3b, 0x52, 0x14, 0x15, 0x21, 0x4b, 0xbe, - 0xaa, 0xb5, 0xad, 0xca, 0xe1, 0xce, 0x81, 0x14, 0x43, 0x59, 0x48, 0x6d, 0x56, 0xf6, 0x37, 0x2b, - 0xd5, 0x9a, 0x14, 0x5f, 0x8c, 0xff, 0xf2, 0x17, 0x4b, 0x73, 0xe5, 0xfb, 0x90, 0xa0, 0xc3, 0x21, - 0x80, 0xe4, 0x7e, 0x7d, 0x77, 0x6f, 0xa7, 0x26, 0xcd, 0xa1, 0x34, 0xc4, 0xb7, 0x88, 0x88, 0x08, - 0xe1, 0xd8, 0xab, 0xc8, 0x07, 0xf5, 0xca, 0x8e, 0x14, 0x65, 0x1c, 0x1f, 0xc5, 0xff, 0xeb, 0xe7, - 0xcb, 0x91, 0xf2, 0xbf, 0x26, 0x60, 0xc1, 0x9f, 0xbb, 0x7f, 0xda, 0x68, 0x13, 0x8a, 0x96, 0xad, - 0x77, 0x74, 0x53, 0xa1, 0x3a, 0xa7, 0xe8, 0x1a, 0xd7, 0xc7, 0x6f, 0x90, 0xf5, 0x9c, 0x9f, 0x2d, - 0xe7, 0x9b, 0x14, 0x7d, 0x40, 0xb0, 0xf5, 0x2a, 0x57, 0xd0, 0xbc, 0x15, 0x00, 0x6a, 0xe8, 0x31, - 0xcc, 0x73, 0x21, 0x2d, 0xcb, 0xe8, 0x77, 0x4d, 0x45, 0xd7, 0x9c, 0x52, 0x74, 0x25, 0xb6, 0x9a, - 0xdf, 0x58, 0x3e, 0x3f, 0x5b, 0x2e, 0x32, 0x11, 0x9b, 0x14, 0x57, 0xaf, 0x3a, 0x5f, 0x9d, 0x2d, - 0xa7, 0xc5, 0x87, 0xcc, 0x87, 0xe7, 0xdf, 0x9a, 0x83, 0x9e, 0xc2, 0x75, 0x5b, 0xec, 0xad, 0x16, - 0x14, 0x18, 0xa3, 0x02, 0x6f, 0x9f, 0x9f, 0x2d, 0x5f, 0xf3, 0x36, 0x5f, 0x1b, 0x2f, 0xf4, 0x9a, - 0x3d, 0x4c, 0xa0, 0x39, 0xa8, 0x09, 0x01, 0xb0, 0xbf, 0xdc, 0x38, 0x5d, 0xee, 0x32, 0x5f, 0xee, - 0xbc, 0x2f, 0x3a, 0xbc, 0xe4, 0x79, 0x7b, 0x08, 0xa1, 0x79, 0x86, 0x97, 0x98, 0x6a, 0x78, 0xc9, - 0xab, 0x1a, 0x5e, 0xc8, 0x8c, 0x52, 0xff, 0x2f, 0x66, 0x94, 0xfe, 0xda, 0xcd, 0x28, 0xf3, 0x35, - 0x98, 0x11, 0xd3, 0xdd, 0x47, 0xf1, 0x34, 0x48, 0xd9, 0x47, 0xf1, 0x74, 0x56, 0xca, 0x3d, 0x8a, - 0xa7, 0x73, 0x52, 0xfe, 0x51, 0x3c, 0x9d, 0x97, 0x0a, 0xe5, 0xbf, 0x89, 0xc2, 0xab, 0x87, 0xa6, - 0xfe, 0xbc, 0x8f, 0x9f, 0xea, 0xee, 0xb1, 0xd5, 0x77, 0xa9, 0x5f, 0x0c, 0xe8, 0xf6, 0x7d, 0x48, - 0x0f, 0x29, 0xf5, 0x75, 0x7e, 0xca, 0xa9, 0xf0, 0xd9, 0xa6, 0x5c, 0x7e, 0xa2, 0x0f, 0x00, 0x46, - 0x34, 0xf8, 0x95, 0xf3, 0xb3, 0xe5, 0xcc, 0x78, 0x35, 0xcb, 0xb4, 0x3c, 0xe5, 0xfa, 0x03, 0x39, - 0xe1, 0x32, 0x64, 0x7a, 0x36, 0xd6, 0xf4, 0x16, 0x39, 0xb5, 0xa0, 0xde, 0xf9, 0x60, 0x6e, 0xf1, - 0x7f, 0x95, 0x00, 0x89, 0x4d, 0xb4, 0x8a, 0x9d, 0x96, 0xad, 0xf7, 0x5c, 0xcb, 0xf6, 0x66, 0x19, - 0x19, 0x99, 0xe5, 0x1b, 0x10, 0xd5, 0x35, 0x1e, 0x68, 0x6e, 0xf0, 0x5d, 0x8a, 0xd2, 0x0d, 0xf2, - 0x97, 0x1b, 0xd5, 0x35, 0xb4, 0x06, 0x71, 0x12, 0x0d, 0xe9, 0x3a, 0xb3, 0xeb, 0x8b, 0xc3, 0x2b, - 0xc1, 0xdd, 0x35, 0x16, 0x2c, 0x0f, 0x64, 0x4a, 0x87, 0x56, 0x20, 0x6d, 0xf6, 0x0d, 0x83, 0x06, - 0x3a, 0xb2, 0xfa, 0xb4, 0x58, 0x92, 0x80, 0xa2, 0x5b, 0x90, 0xd3, 0x70, 0x5b, 0xed, 0x1b, 0xae, - 0x82, 0x4f, 0x7b, 0x36, 0x5b, 0x95, 0x9c, 0xe5, 0xb0, 0xda, 0x69, 0xcf, 0x46, 0xaf, 0x42, 0xf2, - 0x58, 0xd7, 0x34, 0x6c, 0x52, 0x63, 0x12, 0x22, 0x38, 0x0c, 0xad, 0xc3, 0x7c, 0xdf, 0xc1, 0x8e, - 0xe2, 0xe0, 0xe7, 0x7d, 0xa2, 0x49, 0xf4, 0xec, 0x80, 0x9e, 0x5d, 0x92, 0x1f, 0x70, 0x91, 0x10, - 0xec, 0x73, 0x3c, 0x39, 0xae, 0x5b, 0x90, 0x6b, 0x59, 0xdd, 0x5e, 0xdf, 0xc5, 0x6c, 0xd0, 0x2c, - 0x1b, 0x94, 0xc3, 0xe8, 0xa0, 0xeb, 0x30, 0x6f, 0x9d, 0x98, 0x43, 0x62, 0x73, 0x61, 0xb1, 0x84, - 0x20, 0x28, 0xf6, 0x53, 0x90, 0x7a, 0x1d, 0x45, 0x75, 0x5d, 0x5b, 0x3f, 0x22, 0xb2, 0xcd, 0x7e, - 0xb7, 0x94, 0x0f, 0xed, 0x69, 0x61, 0xef, 0x61, 0x45, 0xa0, 0x1b, 0xfd, 0xae, 0x5c, 0xe8, 0x75, - 0x82, 0xdf, 0x68, 0x0b, 0x5e, 0x53, 0x0d, 0x17, 0xdb, 0xc2, 0xf1, 0x91, 0x4d, 0x54, 0x74, 0x53, - 0xe9, 0xd9, 0x56, 0xc7, 0xc6, 0x8e, 0x53, 0x2a, 0x04, 0x76, 0xe0, 0x15, 0x4a, 0xca, 0xce, 0xe7, - 0x60, 0xd0, 0xc3, 0x75, 0x73, 0x8f, 0x93, 0xa1, 0x1f, 0x00, 0x72, 0x06, 0x8e, 0x8b, 0xbb, 0x42, - 0xd0, 0x33, 0xdd, 0xd4, 0x4a, 0x45, 0xaa, 0x7f, 0x6f, 0x4e, 0xd0, 0xbf, 0x7d, 0xca, 0xc0, 0xc4, - 0x3d, 0xd6, 0x4d, 0x8d, 0x8f, 0x22, 0x39, 0x43, 0x70, 0xb4, 0x04, 0xa9, 0x17, 0xba, 0xed, 0xf6, - 0x55, 0xa3, 0x24, 0x05, 0xa6, 0x23, 0x80, 0x9e, 0xdd, 0xa6, 0xa5, 0xcc, 0xa3, 0x78, 0x3a, 0x23, - 0xc1, 0xa3, 0x78, 0x3a, 0x25, 0xa5, 0xcb, 0x7f, 0x1e, 0x85, 0x1b, 0x4c, 0xcc, 0x96, 0xda, 0xd5, - 0x8d, 0xc1, 0x55, 0x35, 0x93, 0x49, 0xe1, 0x9a, 0x49, 0x8f, 0x94, 0x2e, 0x95, 0xb0, 0xb1, 0x70, - 0x41, 0x8f, 0x94, 0xc0, 0x1a, 0x04, 0x34, 0x64, 0xde, 0xf1, 0x0b, 0x98, 0x77, 0x13, 0xe6, 0x85, - 0x92, 0x7a, 0x12, 0xa8, 0xa6, 0xe6, 0x37, 0x6e, 0xf3, 0x39, 0x15, 0xab, 0x8c, 0x40, 0xb0, 0x87, - 0xa3, 0x9c, 0x16, 0x42, 0x6a, 0xdc, 0x48, 0xff, 0x29, 0x0a, 0x0b, 0x75, 0xd3, 0xc5, 0xb6, 0x81, - 0xd5, 0x17, 0x38, 0xb0, 0x1d, 0x9f, 0x43, 0x46, 0x35, 0x5b, 0xd8, 0x71, 0x2d, 0xdb, 0x29, 0x45, - 0x56, 0x62, 0xab, 0xd9, 0xf5, 0xf7, 0x27, 0x9c, 0xda, 0x38, 0xfe, 0xb5, 0x0a, 0x67, 0x16, 0xde, - 0xc1, 0x13, 0xb6, 0xf8, 0xcf, 0x11, 0x48, 0x0b, 0xec, 0x25, 0x3c, 0xe4, 0xb7, 0x20, 0x4d, 0xb3, - 0x4e, 0xc5, 0x3b, 0x93, 0x45, 0xc1, 0xc1, 0xd3, 0xd2, 0x60, 0x86, 0x9a, 0xa2, 0xb4, 0x75, 0x0d, - 0x6d, 0x8e, 0x4b, 0x1e, 0x63, 0x94, 0xff, 0xa6, 0xd8, 0xbf, 0xfd, 0x70, 0xfa, 0x38, 0x92, 0x4f, - 0xb2, 0x3d, 0xe3, 0x3b, 0xf7, 0x8f, 0x11, 0x98, 0x27, 0x0c, 0x1a, 0xd6, 0x02, 0xdb, 0x76, 0x1b, - 0x40, 0x77, 0x14, 0x87, 0xc1, 0xe9, 0x8a, 0x84, 0x6e, 0x66, 0x74, 0x87, 0x93, 0x7b, 0xaa, 0x16, - 0x1d, 0x51, 0xb5, 0x0f, 0x21, 0x4f, 0x79, 0x95, 0xa3, 0x7e, 0xeb, 0x19, 0x76, 0x1d, 0x3a, 0xc3, - 0xc4, 0xc6, 0x02, 0x9f, 0x61, 0x8e, 0x4a, 0xd8, 0x60, 0x38, 0x39, 0xe7, 0x04, 0xbe, 0x46, 0xb4, - 0x2f, 0x3e, 0xa2, 0x7d, 0x7c, 0xe2, 0xbf, 0x8a, 0xc3, 0x8d, 0x3d, 0xd5, 0x76, 0x75, 0x12, 0x3f, - 0x75, 0xb3, 0x13, 0x98, 0xfd, 0x1d, 0xc8, 0x9a, 0x7d, 0x61, 0xb0, 0x0e, 0x3f, 0x10, 0x36, 0x3f, - 0x30, 0xfb, 0xdc, 0x00, 0x1d, 0xb4, 0x03, 0x71, 0x43, 0x77, 0x5c, 0x1a, 0x9e, 0xb2, 0xeb, 0xeb, - 0x13, 0xd4, 0x62, 0xfc, 0x18, 0x6b, 0x3b, 0xba, 0xe3, 0x8a, 0x35, 0x13, 0x29, 0xa8, 0x09, 0x09, - 0x5b, 0x35, 0x3b, 0x98, 0xda, 0x4b, 0x76, 0xfd, 0xbd, 0x8b, 0x89, 0x93, 0x09, 0xab, 0x08, 0xda, - 0x54, 0x0e, 0xfa, 0x00, 0x16, 0xc8, 0x2a, 0xf4, 0x6e, 0xcf, 0xd0, 0x5b, 0xba, 0xeb, 0x2d, 0x27, - 0x1e, 0x58, 0x0e, 0x32, 0xfb, 0xdd, 0x3a, 0x27, 0xe0, 0xcb, 0x5a, 0xfc, 0x59, 0x04, 0xe2, 0x64, - 0x76, 0x53, 0x5c, 0xc1, 0x0d, 0x48, 0xbe, 0x50, 0x8d, 0x3e, 0x66, 0xa1, 0x39, 0x27, 0xf3, 0x2f, - 0xf4, 0x43, 0x28, 0x3a, 0xfd, 0xa3, 0x5e, 0x60, 0x8a, 0x3c, 0x3e, 0xbd, 0x73, 0xa1, 0xd5, 0x78, - 0x75, 0x4c, 0x58, 0x16, 0x3b, 0xb8, 0xc5, 0xe7, 0x90, 0xa0, 0xab, 0x9d, 0x32, 0xbf, 0x5b, 0x90, - 0x73, 0x2d, 0x05, 0x9f, 0xb6, 0x8c, 0xbe, 0xa3, 0xbf, 0x60, 0x1a, 0x96, 0x93, 0xb3, 0xae, 0x55, - 0x13, 0x20, 0x74, 0x07, 0x0a, 0x6d, 0xdb, 0xea, 0x2a, 0xba, 0x29, 0x88, 0x62, 0x94, 0x28, 0x4f, - 0xa0, 0x75, 0x01, 0x0c, 0xa9, 0xfa, 0x5f, 0xe7, 0xa0, 0x48, 0x0d, 0x6a, 0x26, 0x77, 0x79, 0x27, - 0xe0, 0x2e, 0xaf, 0x87, 0xdc, 0xa5, 0x67, 0x95, 0xc4, 0x5b, 0xbe, 0x0a, 0xc9, 0x3e, 0xcd, 0x9d, - 0xe8, 0xf8, 0x5e, 0x48, 0x65, 0xb0, 0x19, 0xb4, 0x19, 0x7d, 0x13, 0x10, 0x71, 0x21, 0x58, 0x09, - 0x11, 0x26, 0x28, 0xa1, 0x44, 0x31, 0x9b, 0x13, 0x3d, 0x6f, 0xf2, 0x02, 0x9e, 0x77, 0x1b, 0x24, - 0x7c, 0xea, 0xda, 0x6a, 0xb0, 0x12, 0x48, 0x51, 0xfe, 0x25, 0x12, 0x4e, 0x6b, 0x04, 0x37, 0x5e, - 0x48, 0x01, 0x07, 0x70, 0x1a, 0xd1, 0x92, 0x79, 0x2e, 0x43, 0xd3, 0x6d, 0x4c, 0xf3, 0x57, 0xa7, - 0x94, 0x5e, 0x89, 0x4d, 0xc9, 0x53, 0x87, 0xb6, 0x7d, 0xad, 0x2a, 0x18, 0x65, 0x89, 0x89, 0xf2, - 0x00, 0x0e, 0xda, 0x87, 0x6c, 0x9b, 0xa5, 0xb5, 0xca, 0x33, 0x3c, 0xa0, 0x09, 0x70, 0x76, 0xfd, - 0xee, 0xec, 0x09, 0xf0, 0x46, 0x92, 0x1c, 0x41, 0x29, 0x22, 0x43, 0xdb, 0x43, 0xa2, 0xa7, 0x90, - 0x0f, 0xd4, 0x2c, 0x47, 0x03, 0x9a, 0xd7, 0x5c, 0x4e, 0x6c, 0xce, 0x17, 0xb4, 0x31, 0x40, 0x9f, - 0x01, 0xe8, 0x5e, 0xe0, 0xa0, 0xe9, 0x4f, 0x76, 0xfd, 0xed, 0x0b, 0x44, 0x18, 0xe1, 0x97, 0x7c, - 0x21, 0xe8, 0x29, 0x14, 0xfc, 0x2f, 0x3a, 0xd9, 0xdc, 0x85, 0x27, 0xcb, 0xa4, 0xe6, 0x03, 0x72, - 0x36, 0x48, 0x01, 0xb4, 0x40, 0x12, 0x33, 0xcb, 0xd1, 0x5d, 0x1c, 0x54, 0x83, 0x3c, 0x55, 0x83, - 0xf2, 0xf9, 0xd9, 0x32, 0xda, 0x14, 0xf8, 0xf1, 0xaa, 0x80, 0x5a, 0x43, 0x78, 0xa6, 0x58, 0x21, - 0x05, 0x26, 0x12, 0x0b, 0xbe, 0x62, 0xed, 0xfb, 0x2a, 0x3c, 0xa2, 0x58, 0x01, 0xf5, 0x66, 0x15, - 0x6b, 0x2e, 0xe4, 0x7b, 0x8a, 0x97, 0xf7, 0x3d, 0x21, 0x41, 0xa8, 0xc6, 0x93, 0x6d, 0x89, 0xa6, - 0x6d, 0x6f, 0xcf, 0xa8, 0xa4, 0x24, 0x13, 0x14, 0x2e, 0x81, 0xe6, 0xe0, 0xef, 0x01, 0x6a, 0xd9, - 0x58, 0x75, 0xb1, 0x46, 0x92, 0x5d, 0xea, 0x74, 0x8d, 0x41, 0x69, 0x3e, 0x60, 0xf7, 0xf3, 0x1c, - 0x5f, 0xf3, 0xd0, 0xe8, 0x01, 0xa4, 0x5e, 0x60, 0xdb, 0xd1, 0x2d, 0xb3, 0x84, 0xa8, 0x33, 0x59, - 0xe2, 0xed, 0xa7, 0x1b, 0x43, 0xe3, 0x3d, 0x61, 0x54, 0xb2, 0x20, 0x47, 0xdb, 0x90, 0xc7, 0x66, - 0xcb, 0xd2, 0x74, 0xb3, 0x43, 0xd3, 0xd7, 0xd2, 0x35, 0x3f, 0x4f, 0xfa, 0xea, 0x6c, 0xf9, 0x1b, - 0x43, 0xfc, 0x35, 0x4e, 0x4b, 0xa6, 0x2d, 0xe7, 0x70, 0xe0, 0x0b, 0x6d, 0x43, 0x4a, 0xc4, 0xf2, - 0x05, 0xba, 0xa7, 0xab, 0x93, 0x32, 0xd7, 0xe1, 0x4c, 0x40, 0x64, 0xa4, 0x9c, 0x9d, 0x94, 0x21, - 0x9a, 0xee, 0x90, 0x1c, 0x46, 0x2b, 0x5d, 0x0f, 0x96, 0x21, 0x02, 0x8a, 0x36, 0x01, 0x3a, 0xd8, - 0x52, 0x58, 0x43, 0xaf, 0x74, 0x83, 0x0e, 0xb7, 0x14, 0x18, 0xae, 0x83, 0xad, 0x35, 0xd1, 0xf6, - 0x23, 0x95, 0x5a, 0x5b, 0xef, 0x88, 0xd4, 0xa2, 0x83, 0x2d, 0x06, 0x08, 0x97, 0x67, 0x37, 0xc7, - 0x96, 0x67, 0xe5, 0x25, 0xc8, 0x78, 0x5e, 0x03, 0xa5, 0x20, 0x56, 0xd9, 0xdf, 0x64, 0x3d, 0x9c, - 0x6a, 0x6d, 0x7f, 0x53, 0x8a, 0x94, 0x6f, 0x41, 0x9c, 0x2e, 0x3e, 0x0b, 0xa9, 0xad, 0xa6, 0xfc, - 0xb4, 0x22, 0x57, 0x59, 0xdf, 0xa8, 0xde, 0x78, 0x52, 0x93, 0x0f, 0x6a, 0x55, 0x49, 0xc4, 0x85, - 0xb3, 0x38, 0x20, 0xbf, 0x64, 0x3c, 0xb0, 0x78, 0x09, 0xde, 0x81, 0x62, 0xcb, 0x83, 0xb2, 0x03, - 0x88, 0xac, 0x44, 0x57, 0x0b, 0xeb, 0x0f, 0x5e, 0x5a, 0x76, 0x0a, 0x19, 0x41, 0x90, 0xaf, 0x4c, - 0x85, 0x56, 0x08, 0x1a, 0xc8, 0xa3, 0xa2, 0x43, 0x31, 0x48, 0x86, 0x44, 0xeb, 0x18, 0xb7, 0x9e, - 0xf1, 0x28, 0xfc, 0xc1, 0x84, 0x81, 0x69, 0x8a, 0x19, 0x50, 0xdc, 0x4d, 0xc2, 0xe3, 0x0f, 0x2d, - 0xd2, 0x0a, 0x2a, 0x0a, 0xc9, 0x61, 0xf7, 0x1a, 0x9f, 0xea, 0xb1, 0xc6, 0xb5, 0xba, 0x84, 0xc7, - 0x0a, 0x78, 0xd7, 0x07, 0x50, 0x34, 0x2d, 0x57, 0x21, 0xa5, 0x28, 0xf7, 0x02, 0xb4, 0xc0, 0xcc, - 0x6f, 0x48, 0x5c, 0x57, 0x7d, 0x9b, 0xcf, 0x9b, 0x96, 0xdb, 0xe8, 0x1b, 0x06, 0x03, 0xa0, 0x3f, - 0x8d, 0xc0, 0x32, 0x8b, 0x95, 0xca, 0x09, 0x6b, 0x3e, 0x28, 0x2c, 0x2d, 0xf6, 0xf7, 0x88, 0xb6, - 0x6a, 0x26, 0x27, 0x54, 0xd3, 0x3a, 0x17, 0x7c, 0xaa, 0xaf, 0xf6, 0xa7, 0xd0, 0x94, 0x0f, 0xa0, - 0x10, 0x3e, 0x26, 0x94, 0x81, 0xc4, 0xe6, 0x76, 0x6d, 0xf3, 0xb1, 0x34, 0x87, 0x8a, 0x90, 0xdd, - 0x6a, 0xca, 0xb5, 0xfa, 0xc3, 0x86, 0xf2, 0xb8, 0xf6, 0x3d, 0xd6, 0x6a, 0x6c, 0x34, 0xbd, 0x56, - 0x63, 0x09, 0x16, 0x0e, 0x1b, 0xf5, 0xcf, 0x0e, 0x6b, 0xca, 0xd3, 0xfa, 0xc1, 0x76, 0xf3, 0xf0, - 0x40, 0xa9, 0x37, 0xaa, 0xb5, 0xcf, 0xa5, 0x98, 0x57, 0xba, 0x25, 0xa4, 0x64, 0xf9, 0xdf, 0x92, - 0x50, 0xd8, 0xb3, 0xf5, 0xae, 0x6a, 0x0f, 0x1e, 0xe3, 0xc1, 0xfe, 0x89, 0xda, 0x43, 0x9f, 0xc2, - 0x82, 0x89, 0x4f, 0x94, 0x1e, 0x83, 0x2a, 0x5e, 0x29, 0x10, 0x19, 0xdf, 0xa1, 0x9e, 0x37, 0xf1, - 0x09, 0x97, 0x50, 0xe7, 0x95, 0xc0, 0x37, 0x21, 0x6b, 0x19, 0x1a, 0xe3, 0xc4, 0xa2, 0xc7, 0x92, - 0x0d, 0x32, 0x81, 0x65, 0x68, 0x75, 0x86, 0x26, 0xd4, 0x64, 0x3c, 0x41, 0x1d, 0x1b, 0x43, 0x6d, - 0xe2, 0x13, 0x41, 0xfd, 0x29, 0x2c, 0x10, 0xd9, 0x23, 0xb3, 0x8b, 0x4f, 0x98, 0x9d, 0x65, 0x68, - 0x43, 0xb3, 0xfb, 0x10, 0x6e, 0x8c, 0xae, 0x6f, 0xa4, 0xc9, 0x77, 0x6d, 0x68, 0x59, 0x24, 0xc7, - 0x41, 0x5f, 0xc0, 0x82, 0x61, 0xb5, 0x54, 0x43, 0x77, 0x07, 0xdc, 0x8b, 0x28, 0xce, 0x89, 0xda, - 0xa3, 0x1a, 0x95, 0x9d, 0x68, 0x7c, 0xe1, 0xfd, 0x5d, 0xdb, 0xe1, 0x12, 0x98, 0x3f, 0x21, 0x20, - 0x19, 0x19, 0x23, 0xb0, 0xc5, 0x7f, 0x88, 0x01, 0x1a, 0x25, 0x45, 0xcf, 0xe0, 0x1a, 0x59, 0xff, - 0xd0, 0x34, 0xe8, 0xe1, 0x64, 0xd7, 0xbf, 0x35, 0xa3, 0x15, 0x86, 0xe5, 0x8a, 0x00, 0x61, 0x19, - 0x5a, 0x18, 0x41, 0x06, 0x23, 0x5b, 0x35, 0x3c, 0x58, 0xf4, 0x6b, 0x18, 0xcc, 0xc4, 0x27, 0x43, - 0x83, 0xe9, 0xf0, 0x1a, 0x19, 0xcc, 0xc6, 0x1d, 0xdd, 0x32, 0x55, 0x43, 0x39, 0x1a, 0x28, 0xb6, - 0x75, 0x12, 0xa8, 0xc5, 0x59, 0x2d, 0xb9, 0x7a, 0x7e, 0xb6, 0x5c, 0x6a, 0xe0, 0x13, 0x99, 0xd3, - 0x6d, 0x0c, 0x64, 0xeb, 0x64, 0x6c, 0x41, 0x5e, 0x32, 0xc7, 0x53, 0x69, 0x48, 0x86, 0x37, 0xa7, - 0x0c, 0x15, 0x6a, 0x55, 0xc5, 0x69, 0xd7, 0xe8, 0xd6, 0x78, 0x51, 0x55, 0xbf, 0x81, 0x15, 0x4a, - 0xe7, 0x7f, 0x15, 0x01, 0x9a, 0xae, 0xf4, 0x5d, 0xd1, 0x9c, 0xa6, 0x67, 0xf7, 0x3e, 0xe4, 0xc9, - 0xb0, 0xfe, 0x8a, 0x22, 0x13, 0x3c, 0x11, 0x31, 0x08, 0x6f, 0xb2, 0xef, 0x43, 0x9e, 0x9c, 0xb8, - 0xcf, 0x15, 0x9d, 0xc4, 0x65, 0x19, 0x5e, 0x2b, 0x1c, 0xbd, 0x09, 0x39, 0xdd, 0x24, 0xe1, 0x9a, - 0x77, 0xbf, 0x82, 0x4d, 0xcb, 0x2c, 0xc7, 0xf8, 0xf3, 0x2e, 0xff, 0x3a, 0x0a, 0x37, 0x77, 0x55, - 0x17, 0xdb, 0xba, 0x6a, 0xe8, 0x3f, 0xc1, 0xda, 0x13, 0x9d, 0x2c, 0xb8, 0x6d, 0x63, 0xe7, 0x18, - 0x7d, 0x0e, 0xf3, 0x23, 0x06, 0xc3, 0x15, 0xee, 0x8d, 0xd9, 0xf2, 0x15, 0x51, 0x75, 0x0d, 0xd9, - 0x14, 0xda, 0x0d, 0x9b, 0x3e, 0xab, 0x76, 0x2f, 0x26, 0x33, 0xe8, 0x1b, 0x1e, 0x40, 0x42, 0x75, - 0x14, 0xab, 0xcd, 0x63, 0xd2, 0x6b, 0x01, 0x41, 0x7d, 0x57, 0x37, 0xd6, 0x8e, 0x8d, 0xd6, 0xda, - 0x81, 0xb8, 0x26, 0x14, 0xd1, 0x4c, 0x75, 0x9a, 0x6d, 0xf4, 0x0e, 0x14, 0x9d, 0x63, 0xab, 0x6f, - 0x68, 0xca, 0x91, 0xda, 0x7a, 0xd6, 0xd6, 0x0d, 0x23, 0xd4, 0xc9, 0x2c, 0x30, 0xe4, 0x06, 0xc7, - 0xf1, 0x3d, 0xfb, 0x8b, 0x14, 0x20, 0x7f, 0x3e, 0xbb, 0x7d, 0x57, 0xa5, 0xf1, 0xbe, 0x02, 0x49, - 0x1e, 0x68, 0xd8, 0x1e, 0xbd, 0x39, 0x31, 0x26, 0x87, 0x3b, 0xb7, 0xdb, 0x73, 0x32, 0x67, 0x44, - 0xdf, 0x0d, 0xde, 0x0a, 0xce, 0xbc, 0x23, 0xdb, 0x73, 0xe2, 0xba, 0xf0, 0x31, 0x24, 0x1c, 0x97, - 0xe4, 0x27, 0x31, 0x9a, 0x55, 0xde, 0x9b, 0xc0, 0x3f, 0x3a, 0xf9, 0xb5, 0x7d, 0xc2, 0x26, 0xa2, - 0x32, 0x95, 0x81, 0x9e, 0x42, 0xc6, 0x2b, 0xa6, 0x78, 0x77, 0xfb, 0xbd, 0xd9, 0x05, 0x7a, 0x79, - 0x90, 0xc8, 0x92, 0x3c, 0x59, 0xa8, 0x02, 0xd9, 0x2e, 0x27, 0xf3, 0x5b, 0x6d, 0x2b, 0xbc, 0x9e, - 0x05, 0x21, 0x81, 0x1a, 0x75, 0xe0, 0x4b, 0x06, 0xc1, 0x54, 0xa7, 0x39, 0x9f, 0x6d, 0x19, 0x06, - 0x39, 0x34, 0x1a, 0x8b, 0xbd, 0x9c, 0x4f, 0x40, 0xd1, 0x63, 0x52, 0x95, 0x7a, 0xf1, 0x3a, 0x4d, - 0xf7, 0xf3, 0xad, 0x99, 0xb3, 0xa4, 0xed, 0x39, 0x39, 0xc0, 0x8e, 0x9a, 0x50, 0xe8, 0x85, 0x9c, - 0x39, 0x2f, 0x01, 0xef, 0xcc, 0xe4, 0xf9, 0xb7, 0xe7, 0xe4, 0x21, 0x76, 0xf4, 0x03, 0x40, 0xad, - 0x11, 0x3f, 0x51, 0x82, 0x97, 0xcc, 0x72, 0x98, 0x61, 0x7b, 0x4e, 0x1e, 0x23, 0x06, 0x7d, 0x01, - 0x37, 0xbb, 0xe3, 0x4d, 0x9a, 0x17, 0x83, 0x6b, 0x13, 0x46, 0x98, 0xe0, 0x08, 0xb6, 0xe7, 0xe4, - 0x49, 0x02, 0xcb, 0x9f, 0x42, 0x82, 0xaa, 0x0e, 0x49, 0x69, 0x0f, 0x1b, 0x8f, 0x1b, 0xcd, 0xa7, - 0x0d, 0x96, 0xa2, 0x54, 0x6b, 0x3b, 0xb5, 0x83, 0x9a, 0xd2, 0x6c, 0xec, 0x90, 0x14, 0xe5, 0x15, - 0xb8, 0xce, 0x01, 0x95, 0x46, 0x55, 0x79, 0x2a, 0xd7, 0x05, 0x2a, 0x5a, 0x5e, 0x0d, 0xe6, 0xcc, - 0x69, 0x88, 0x37, 0x9a, 0x8d, 0x9a, 0x34, 0x47, 0xb3, 0xe7, 0x6a, 0x55, 0x8a, 0xd0, 0xec, 0x59, - 0x6e, 0xee, 0x49, 0x51, 0x66, 0x7d, 0x1b, 0x39, 0x00, 0xcd, 0x53, 0xb7, 0x47, 0xf1, 0x74, 0x52, - 0x4a, 0x95, 0xff, 0x3e, 0x02, 0x69, 0x12, 0xa8, 0xeb, 0x66, 0xdb, 0x42, 0xef, 0x41, 0xa6, 0xa7, - 0xda, 0xd8, 0x74, 0x7d, 0x4f, 0x2b, 0x7a, 0xcb, 0xe9, 0x3d, 0x8a, 0xf0, 0x5a, 0x9f, 0x69, 0x46, - 0x58, 0x9f, 0xd6, 0x38, 0xdc, 0x02, 0x89, 0x8b, 0x73, 0x5a, 0xc7, 0xb8, 0xab, 0xfa, 0x11, 0xe9, - 0x55, 0xaf, 0xef, 0x4f, 0xf1, 0xfb, 0x14, 0xed, 0xc9, 0x2e, 0xf4, 0x82, 0x50, 0xd1, 0x15, 0xfe, - 0xdf, 0x37, 0xa1, 0x38, 0x14, 0x28, 0xa7, 0x34, 0x7c, 0x56, 0x68, 0xc3, 0x27, 0xe6, 0xfb, 0x7d, - 0xaf, 0xe1, 0x13, 0xe5, 0xbd, 0x9e, 0xd0, 0x62, 0xe3, 0x33, 0x2e, 0xf6, 0x3d, 0xbf, 0xfe, 0x63, - 0xc6, 0xf7, 0x0a, 0x8f, 0x29, 0xf3, 0x53, 0x4a, 0xbf, 0x3d, 0x98, 0xef, 0x5a, 0x9a, 0xde, 0x26, - 0x95, 0x0e, 0xb1, 0x5c, 0x57, 0xef, 0x62, 0x9e, 0x07, 0xcf, 0xe4, 0x70, 0xa5, 0x20, 0x37, 0x41, - 0xa2, 0x87, 0x90, 0x12, 0x0d, 0xc4, 0x34, 0x8d, 0x00, 0xb3, 0x7a, 0x4c, 0x51, 0x01, 0x72, 0x6e, - 0xb4, 0x05, 0x05, 0x13, 0x9f, 0x06, 0xdb, 0xf7, 0x99, 0x90, 0x4f, 0xc9, 0x35, 0xf0, 0xe9, 0xf8, - 0xde, 0x7d, 0xce, 0xf4, 0x31, 0x1a, 0xfa, 0x0c, 0xf2, 0xe1, 0x60, 0x07, 0x97, 0x08, 0x76, 0xb9, - 0x5e, 0x30, 0xd2, 0x6d, 0x41, 0x4a, 0x44, 0xb9, 0xec, 0x25, 0xa2, 0x9c, 0x60, 0x46, 0x1b, 0x24, - 0x85, 0x38, 0x75, 0xfd, 0xbc, 0x37, 0xe7, 0x17, 0xee, 0xe7, 0x67, 0xcb, 0x59, 0xb2, 0xc2, 0x31, - 0x4d, 0xfa, 0xac, 0xe9, 0xc1, 0x35, 0xf4, 0x08, 0xc0, 0x7b, 0x08, 0xe3, 0xd0, 0xbb, 0xab, 0xc9, - 0x0d, 0x9c, 0x3d, 0x41, 0xe8, 0x4f, 0x49, 0x0e, 0x70, 0xa3, 0x5d, 0xc8, 0x08, 0x77, 0xcc, 0x5a, - 0x2b, 0x93, 0xfd, 0xd6, 0x68, 0x70, 0x10, 0x21, 0xc1, 0x93, 0x40, 0xaa, 0x4a, 0x03, 0xab, 0x0e, - 0xe6, 0xfd, 0x95, 0x07, 0x33, 0xa6, 0x98, 0xcc, 0xb8, 0x36, 0x8f, 0x55, 0xb3, 0x83, 0x77, 0x08, - 0xff, 0x46, 0xb4, 0x14, 0x91, 0x99, 0x28, 0xd4, 0x00, 0x89, 0x6e, 0x59, 0x30, 0xd6, 0x48, 0x74, - 0xd7, 0x5e, 0x17, 0x86, 0x4b, 0x76, 0x6d, 0x62, 0xbc, 0xa1, 0x3a, 0xb5, 0xeb, 0xc7, 0x9c, 0xef, - 0x40, 0xa1, 0x6d, 0xd9, 0x5d, 0xd5, 0x55, 0x84, 0xf1, 0xcc, 0xfb, 0x9d, 0xd8, 0xaf, 0xce, 0x96, - 0xf3, 0x5b, 0x14, 0x2b, 0x0c, 0x27, 0xdf, 0x0e, 0x7e, 0xa2, 0x0d, 0x11, 0x9a, 0xaf, 0xd1, 0x48, - 0xfa, 0xc6, 0x4b, 0x37, 0x6b, 0x4c, 0x44, 0x6e, 0x40, 0x92, 0x16, 0xcc, 0x4e, 0x69, 0x81, 0xee, - 0xf8, 0x25, 0x8b, 0x6f, 0x99, 0x4b, 0x41, 0x3b, 0x50, 0xd0, 0x08, 0x44, 0x37, 0x3b, 0xbc, 0xc7, - 0x7b, 0x9d, 0xca, 0x5d, 0x9e, 0x20, 0x57, 0xb8, 0x58, 0xd1, 0xca, 0x13, 0xcc, 0xac, 0x0f, 0xdc, - 0x84, 0x74, 0x5b, 0xed, 0xea, 0x86, 0x8e, 0x9d, 0xd2, 0x0d, 0x2a, 0xe7, 0x9d, 0xa9, 0xf6, 0x3c, - 0x7c, 0x4f, 0x28, 0x42, 0xb8, 0x10, 0xe2, 0x99, 0x35, 0x05, 0x0c, 0xc8, 0xf1, 0xdd, 0x1c, 0x35, - 0x6b, 0x71, 0x4f, 0x18, 0xba, 0x33, 0xa4, 0x66, 0xcd, 0xbf, 0x34, 0x74, 0x1b, 0xe0, 0x85, 0x8e, - 0x4f, 0x94, 0xe7, 0x7d, 0x6c, 0x0f, 0x4a, 0xa5, 0x60, 0xeb, 0x86, 0xc0, 0x3f, 0x23, 0x60, 0xf4, - 0x2e, 0x64, 0x34, 0xdc, 0xc3, 0xa6, 0xe6, 0x34, 0xcd, 0xd2, 0x2b, 0xb4, 0x16, 0xbd, 0x76, 0x7e, - 0xb6, 0x9c, 0xa9, 0x0a, 0x20, 0xf7, 0xa2, 0x3e, 0x15, 0xfa, 0x02, 0x72, 0xec, 0x03, 0x6b, 0x4d, - 0x73, 0x63, 0x50, 0x5a, 0xa4, 0x8b, 0xbe, 0x3f, 0xe3, 0xa1, 0xf8, 0x8d, 0x51, 0xef, 0x0e, 0xaa, - 0x1a, 0x90, 0x26, 0x87, 0x64, 0xa3, 0x3f, 0x86, 0x9c, 0xd0, 0xe3, 0x47, 0xd6, 0x91, 0x53, 0xfa, - 0xc6, 0xd4, 0x0b, 0xa2, 0xe1, 0xb1, 0x76, 0x7d, 0x56, 0xe1, 0xa5, 0x82, 0xd2, 0xd0, 0xe7, 0x90, - 0xf7, 0xae, 0xc2, 0xad, 0x9e, 0xeb, 0x94, 0x5e, 0x9d, 0xda, 0xdf, 0x18, 0x31, 0x43, 0xce, 0xdb, - 0xec, 0xd1, 0xbb, 0xb3, 0xc0, 0x17, 0xba, 0x05, 0x19, 0xcd, 0xb6, 0x7a, 0x2c, 0x5a, 0xbc, 0xb6, - 0x12, 0x59, 0x8d, 0x79, 0xdd, 0x39, 0xdb, 0xea, 0xd1, 0x30, 0xa0, 0x40, 0xc1, 0xc6, 0x3d, 0x43, - 0x6d, 0xe1, 0x2e, 0x89, 0x63, 0x56, 0xbb, 0xb4, 0x44, 0x47, 0x5f, 0x9f, 0x79, 0x23, 0x3d, 0x66, - 0xa1, 0x98, 0x01, 0x79, 0xcd, 0x36, 0x3a, 0x04, 0x50, 0xfb, 0x9a, 0xee, 0x2a, 0x5d, 0x4b, 0xc3, - 0xa5, 0xe5, 0xa9, 0xaf, 0x57, 0x86, 0x85, 0x57, 0x08, 0xe3, 0xae, 0xa5, 0x61, 0xef, 0xb6, 0x55, - 0x00, 0xd0, 0xbb, 0x90, 0xa5, 0x4b, 0xfb, 0xc2, 0x3a, 0x22, 0xba, 0xb9, 0x42, 0x17, 0x37, 0xcf, - 0xcf, 0x32, 0x53, 0xb5, 0xad, 0xde, 0x23, 0xeb, 0x88, 0x6a, 0x0c, 0xff, 0x53, 0x43, 0x0e, 0xe4, - 0x3a, 0x2d, 0xc5, 0x77, 0x9c, 0xb7, 0xe8, 0x29, 0x7e, 0x3c, 0xe3, 0x5c, 0x1e, 0x6e, 0x8e, 0x71, - 0xa5, 0xd7, 0x44, 0x04, 0x78, 0xb8, 0x29, 0x60, 0x8e, 0x9c, 0xed, 0xb4, 0xbc, 0x0f, 0x52, 0x11, - 0xb2, 0x16, 0x30, 0x37, 0x80, 0x72, 0xb0, 0x22, 0x64, 0x18, 0x66, 0x02, 0x0d, 0xe0, 0xbd, 0x62, - 0x85, 0x56, 0x53, 0xec, 0xcc, 0x6e, 0xcf, 0x1e, 0xe1, 0x0b, 0x8c, 0xbb, 0xe2, 0x34, 0xdb, 0xf4, - 0x60, 0x5b, 0x90, 0xb3, 0xfa, 0xee, 0x91, 0xd5, 0x37, 0x35, 0xa5, 0xfd, 0xcc, 0x29, 0xbd, 0x4e, - 0x57, 0x7b, 0xa1, 0xbe, 0x9e, 0xb7, 0xba, 0x26, 0x17, 0xb4, 0xf5, 0xd8, 0x91, 0xb3, 0x42, 0xea, - 0xd6, 0x33, 0x07, 0xfd, 0x18, 0xb2, 0xba, 0xe9, 0x8f, 0x71, 0xe7, 0xe2, 0x63, 0x20, 0x51, 0x79, - 0xd4, 0x4d, 0x6f, 0x08, 0xe0, 0x32, 0xc9, 0x08, 0x6f, 0x43, 0xc1, 0x6a, 0xb7, 0x0d, 0xdd, 0xc4, - 0x8a, 0x8d, 0x55, 0xc7, 0x32, 0x4b, 0x6f, 0x04, 0x76, 0x30, 0xcf, 0x71, 0x32, 0x45, 0xa1, 0x32, - 0x64, 0x5c, 0xdc, 0xed, 0x59, 0xb6, 0x6a, 0x0f, 0x4a, 0x6f, 0x06, 0x2f, 0xa9, 0x3d, 0x30, 0x3a, - 0x82, 0xc5, 0xbe, 0x89, 0x4f, 0x7b, 0x96, 0x83, 0x35, 0x65, 0x24, 0xb7, 0x5c, 0xa5, 0x3e, 0xee, - 0x0e, 0x9f, 0xd4, 0xcd, 0x43, 0x41, 0x39, 0x36, 0xc9, 0xbc, 0xd9, 0x1f, 0x8b, 0xd6, 0xd0, 0x07, - 0xb0, 0xa0, 0x3b, 0x4a, 0x30, 0x6b, 0x57, 0x88, 0xaf, 0x2b, 0xbd, 0x15, 0x98, 0x12, 0xd2, 0x9d, - 0xe1, 0x8c, 0x1f, 0xfd, 0x08, 0x8a, 0xc3, 0x5d, 0x9f, 0xbb, 0x57, 0xe8, 0xfa, 0xc8, 0x85, 0x70, - 0x87, 0x0b, 0xfd, 0x34, 0x02, 0x2b, 0x2f, 0x69, 0xae, 0x3a, 0xa5, 0xb7, 0xa7, 0x5e, 0x57, 0xcf, - 0xd0, 0x5d, 0x7d, 0x6d, 0x5a, 0x77, 0xd5, 0x41, 0x6b, 0x34, 0xa5, 0x67, 0x77, 0x31, 0x8a, 0x6a, - 0x18, 0xca, 0xd1, 0xa0, 0xf4, 0xcd, 0x60, 0xd9, 0xef, 0x61, 0x2b, 0x86, 0xb1, 0x31, 0x58, 0xfc, - 0x65, 0x04, 0xe6, 0x47, 0x52, 0x0d, 0xf4, 0x23, 0x48, 0x99, 0x96, 0x16, 0x78, 0x5f, 0x51, 0xe3, - 0x67, 0x96, 0x6c, 0x58, 0x1a, 0x7b, 0x5e, 0xf1, 0x5e, 0x47, 0x77, 0x8f, 0xfb, 0x47, 0x6b, 0x2d, - 0xab, 0x7b, 0xcf, 0x5b, 0x8c, 0x76, 0xe4, 0xff, 0x7d, 0xaf, 0xf7, 0xac, 0x73, 0x8f, 0xfe, 0xd5, - 0x3b, 0x5a, 0x63, 0x6c, 0x72, 0x92, 0x48, 0xad, 0x6b, 0xe8, 0x1d, 0x28, 0xe2, 0xd3, 0x9e, 0x6e, - 0x07, 0xd2, 0xed, 0x68, 0xc0, 0x81, 0x16, 0x7c, 0x24, 0xb1, 0x36, 0x7e, 0x93, 0xfd, 0xeb, 0x28, - 0x14, 0x87, 0xc2, 0x3d, 0xa9, 0x2f, 0x68, 0x2b, 0x28, 0x54, 0x5f, 0x10, 0xc8, 0x94, 0xaa, 0x27, - 0xf8, 0xb2, 0x2d, 0x76, 0xd5, 0x97, 0x6d, 0xe1, 0x1b, 0xe2, 0xc4, 0x05, 0x6e, 0x88, 0x3f, 0x84, - 0x1b, 0xba, 0xa3, 0x98, 0x96, 0x29, 0x1a, 0xf9, 0x5e, 0x45, 0x1f, 0x7c, 0x2d, 0x76, 0x4d, 0x77, - 0x1a, 0x96, 0xc9, 0x5a, 0xf8, 0xde, 0xaa, 0xfd, 0x87, 0x65, 0xa9, 0xd1, 0x87, 0x65, 0x5e, 0x2f, - 0x3c, 0x2e, 0x25, 0x16, 0xff, 0x25, 0x02, 0x99, 0xe0, 0xdb, 0xed, 0x68, 0xb8, 0x43, 0x37, 0x52, - 0x73, 0x5d, 0xf2, 0x9d, 0x4c, 0x78, 0x17, 0x62, 0x17, 0xd8, 0x85, 0x5b, 0x90, 0x38, 0x1a, 0x88, - 0x02, 0x2f, 0xbd, 0x91, 0xe3, 0xa3, 0xc5, 0x37, 0x48, 0xae, 0x13, 0x3f, 0x1a, 0x88, 0xea, 0x72, - 0xf1, 0x4f, 0x20, 0x1b, 0x08, 0xf5, 0xc3, 0x8d, 0x96, 0xc8, 0x25, 0x1a, 0x2d, 0xaf, 0x43, 0x92, - 0xc7, 0x37, 0xa6, 0x7b, 0x79, 0xce, 0x9d, 0x60, 0xb1, 0x2d, 0xf1, 0x05, 0x89, 0x6b, 0x7c, 0xf4, - 0xff, 0x8e, 0x41, 0x2e, 0x98, 0x0a, 0x10, 0x67, 0xa8, 0x9b, 0x2d, 0x9b, 0xc6, 0x61, 0x3a, 0x7a, - 0xcc, 0x7b, 0xb1, 0x23, 0xc0, 0x24, 0x41, 0xe8, 0xea, 0xa6, 0x42, 0x5f, 0x7b, 0x84, 0xf4, 0x3b, - 0xdd, 0xd5, 0xcd, 0x27, 0x04, 0x4a, 0x49, 0xd4, 0x53, 0x4e, 0x12, 0x0b, 0x91, 0xa8, 0xa7, 0x8c, - 0x64, 0x91, 0x66, 0xd7, 0xb6, 0x4b, 0x77, 0x28, 0x16, 0xc8, 0x9a, 0x6d, 0x37, 0xf8, 0xa2, 0x2d, - 0x31, 0xe6, 0x45, 0x1b, 0x32, 0xa1, 0xe0, 0x27, 0x3f, 0x27, 0x26, 0xb6, 0x79, 0x5b, 0xbf, 0x72, - 0x89, 0xec, 0xc7, 0xff, 0x20, 0x82, 0x44, 0x88, 0x70, 0x82, 0x40, 0x92, 0x8e, 0xb6, 0xd4, 0xd6, - 0x31, 0x56, 0x1c, 0xfd, 0x27, 0xac, 0x82, 0xf6, 0xb6, 0x85, 0xc2, 0xf7, 0xf5, 0x9f, 0xe0, 0xc5, - 0xbf, 0x8b, 0x40, 0x3e, 0x24, 0x0b, 0xd5, 0xa1, 0x48, 0x67, 0x37, 0xd2, 0x46, 0xbe, 0xe5, 0xbd, - 0xe6, 0x26, 0xe8, 0xb1, 0x65, 0x6e, 0xde, 0x0a, 0xa0, 0x34, 0xf4, 0x29, 0x14, 0x98, 0x28, 0xef, - 0x81, 0x58, 0x58, 0x8d, 0x73, 0x54, 0x52, 0xf8, 0x95, 0x58, 0xce, 0xf2, 0x61, 0x5a, 0xb0, 0xe9, - 0xbd, 0x68, 0x42, 0x36, 0x90, 0x82, 0xcd, 0x60, 0x3f, 0xdf, 0x86, 0xb8, 0xe7, 0xcd, 0x66, 0xed, - 0xd6, 0xba, 0xbe, 0x8b, 0xfb, 0x79, 0x04, 0x16, 0xc6, 0xa5, 0x42, 0x21, 0xbb, 0x64, 0xda, 0x36, - 0x93, 0x5d, 0xde, 0x0e, 0xa6, 0xa8, 0x4c, 0x03, 0xc5, 0xbb, 0x0a, 0x3f, 0x49, 0x7d, 0xc3, 0xb3, - 0x03, 0xa6, 0x80, 0xc5, 0x90, 0x1d, 0x90, 0xa2, 0x33, 0x68, 0x09, 0xbf, 0x8b, 0x41, 0x61, 0xe8, - 0x96, 0xe3, 0x09, 0x24, 0x3b, 0x86, 0x75, 0xa4, 0x1a, 0xbc, 0x3b, 0xfc, 0x9d, 0x4b, 0xc5, 0xd3, - 0xb5, 0x87, 0x54, 0xc6, 0xf6, 0x9c, 0xcc, 0xa5, 0x21, 0x07, 0xe6, 0x83, 0xd7, 0x19, 0xec, 0x67, - 0x27, 0x6c, 0x67, 0x6b, 0x97, 0x1b, 0xc2, 0xbf, 0xef, 0xa0, 0x84, 0xdb, 0x73, 0x72, 0xd1, 0x0e, - 0x83, 0x50, 0x17, 0x8a, 0x43, 0x77, 0x28, 0xbc, 0xf5, 0xbe, 0x79, 0xd5, 0x21, 0x65, 0xeb, 0x64, - 0x9b, 0x26, 0xf0, 0x01, 0xc0, 0xe2, 0x1f, 0x41, 0x71, 0x68, 0x52, 0xe4, 0x3c, 0x18, 0x0d, 0x8f, - 0x6a, 0x05, 0xe2, 0xc3, 0x18, 0x11, 0xa9, 0x46, 0x65, 0x8e, 0xe5, 0xe7, 0x71, 0x07, 0xf2, 0xa1, - 0x21, 0x50, 0x01, 0xa2, 0x2a, 0x7b, 0x85, 0x97, 0x91, 0xa3, 0x2a, 0x7f, 0xbf, 0xb7, 0x58, 0x80, - 0x24, 0xdb, 0xdf, 0xa0, 0x7e, 0x6f, 0x00, 0xa4, 0x45, 0x12, 0x53, 0x5e, 0x85, 0x8c, 0x57, 0x11, - 0xa0, 0x1c, 0xa4, 0xab, 0xf5, 0xfd, 0xca, 0xc6, 0x4e, 0xad, 0x2a, 0xcd, 0xa1, 0x3c, 0x64, 0xe4, - 0x5a, 0xa5, 0x4a, 0x7b, 0x9b, 0x52, 0xe4, 0xa3, 0xf4, 0x9f, 0xfd, 0x7c, 0x39, 0xc2, 0x83, 0x4c, - 0x52, 0x4a, 0x3d, 0x8a, 0xa7, 0x91, 0x74, 0xad, 0xfc, 0x9f, 0x19, 0x40, 0x55, 0xd5, 0x55, 0xc9, - 0xa6, 0x5c, 0xa0, 0x03, 0x18, 0x9d, 0x62, 0x4d, 0xe1, 0xae, 0x4e, 0xec, 0x4a, 0x5d, 0x9d, 0xb1, - 0x3d, 0xbe, 0xf8, 0x55, 0x7a, 0x7c, 0x97, 0x6a, 0x35, 0x8e, 0xf6, 0x25, 0x92, 0x57, 0xe8, 0x4b, - 0x3c, 0x81, 0x14, 0xcb, 0xae, 0xd9, 0xe3, 0xb2, 0xc9, 0x6d, 0x93, 0xd1, 0x83, 0xe1, 0x0d, 0x26, - 0xa7, 0x66, 0xba, 0xf6, 0xc0, 0x7b, 0x77, 0xc2, 0x60, 0x7e, 0x47, 0x27, 0x7d, 0xf9, 0x8e, 0xce, - 0x68, 0x6d, 0x91, 0x99, 0x5c, 0x5b, 0xfc, 0x00, 0xb8, 0x5d, 0x88, 0xcc, 0x1c, 0xa6, 0x3e, 0xc1, - 0x18, 0xb3, 0x1c, 0x66, 0x04, 0x3c, 0x35, 0xcf, 0xd9, 0x81, 0xaf, 0xc5, 0x03, 0x00, 0x5e, 0x3c, - 0x98, 0x6d, 0x6b, 0x06, 0x27, 0xbe, 0x04, 0x29, 0xe2, 0x1c, 0x7b, 0x98, 0x69, 0xa7, 0x17, 0x55, - 0x39, 0x90, 0x5b, 0x54, 0x0f, 0x72, 0xc1, 0x2d, 0x44, 0x12, 0xc4, 0x9e, 0xe1, 0x01, 0x37, 0x3c, - 0xf2, 0x27, 0x7a, 0x04, 0x09, 0x3f, 0xf6, 0x4f, 0x7e, 0x09, 0x3d, 0xf1, 0x6c, 0xc8, 0x74, 0x65, - 0x26, 0xe2, 0xa3, 0xe8, 0x83, 0xc8, 0xe2, 0xff, 0x44, 0x21, 0x17, 0x5c, 0x26, 0xfa, 0x21, 0xa4, - 0xd8, 0x42, 0xc5, 0x63, 0xeb, 0x4f, 0x2e, 0xb7, 0x5f, 0xfc, 0x43, 0xac, 0x93, 0xcb, 0x44, 0x0d, - 0xc8, 0x3b, 0x7d, 0xfb, 0x85, 0xfe, 0x42, 0x35, 0x94, 0x8e, 0xa5, 0x1a, 0x74, 0x1d, 0x85, 0xf5, - 0xdb, 0x93, 0x5e, 0x33, 0x71, 0xda, 0x87, 0x96, 0x6a, 0x88, 0x56, 0x8c, 0x13, 0x80, 0xa1, 0x0f, - 0xbd, 0xab, 0x26, 0x7e, 0x4d, 0xcd, 0x6f, 0x70, 0x11, 0xb7, 0x9b, 0xa0, 0x93, 0x13, 0xdd, 0x6a, - 0x06, 0x22, 0x61, 0x9d, 0xeb, 0x07, 0xa6, 0xaf, 0x74, 0xc5, 0x85, 0x80, 0x17, 0xd6, 0x19, 0x5d, - 0xcd, 0xec, 0x77, 0xfd, 0xb0, 0x6e, 0xfb, 0x30, 0x6d, 0xf1, 0x03, 0x48, 0x72, 0x59, 0x6f, 0x84, - 0x3c, 0xd2, 0xb8, 0xc1, 0x29, 0x3e, 0xe8, 0x28, 0x7d, 0x97, 0x57, 0xfe, 0x5d, 0x0e, 0x0a, 0x07, - 0x83, 0x5e, 0xd0, 0xc5, 0x5d, 0xea, 0x56, 0x66, 0xdc, 0xdd, 0x4b, 0xf4, 0xe2, 0x77, 0x2f, 0x53, - 0x7e, 0xc1, 0xc3, 0x14, 0x3d, 0x3e, 0x45, 0xd1, 0xab, 0x10, 0xa7, 0xbf, 0xaf, 0x48, 0xd0, 0x73, - 0x9d, 0xe4, 0x59, 0xc3, 0xab, 0x5d, 0x0b, 0xfc, 0xc4, 0x82, 0x72, 0xa3, 0xef, 0x41, 0x8e, 0x1e, - 0x4a, 0x17, 0x77, 0x8f, 0xb0, 0x2d, 0x1c, 0xda, 0xfd, 0xd9, 0xa4, 0x91, 0xd3, 0xd9, 0xa5, 0x8c, - 0xa2, 0x6d, 0x83, 0x3d, 0x88, 0x83, 0xee, 0x43, 0x42, 0x35, 0x74, 0xea, 0xdd, 0x5e, 0xf6, 0xbb, - 0x1d, 0x46, 0x88, 0x3e, 0x81, 0xbc, 0x6a, 0xdb, 0xea, 0x80, 0xff, 0x02, 0x45, 0xa3, 0x1e, 0x8c, - 0xbb, 0xe6, 0xf3, 0xb3, 0xe5, 0x6c, 0x85, 0x20, 0xe9, 0x8f, 0x4e, 0xc4, 0x46, 0x64, 0x55, 0x0f, - 0x14, 0xba, 0x3e, 0xca, 0x5c, 0xed, 0xfa, 0x08, 0xae, 0x12, 0x5a, 0x46, 0xa3, 0x44, 0xf6, 0x0a, - 0x51, 0xe2, 0xc7, 0xb0, 0x28, 0x1e, 0xd1, 0x12, 0x81, 0xfe, 0x15, 0x63, 0xe0, 0xb7, 0x41, 0xe5, - 0xf3, 0xb3, 0xe5, 0x92, 0xec, 0x53, 0xf9, 0xcb, 0x65, 0xc5, 0x1b, 0xd9, 0xa9, 0x92, 0x3d, 0x16, - 0xaf, 0x05, 0xe2, 0x45, 0xfe, 0xf2, 0xf1, 0x22, 0x1c, 0xec, 0x0b, 0x57, 0x0a, 0xf6, 0xa3, 0xb1, - 0xa7, 0x38, 0x39, 0xf6, 0x3c, 0x1d, 0x8e, 0x3d, 0xd2, 0xf4, 0x1e, 0x6d, 0x58, 0x81, 0xa7, 0xc4, - 0x9d, 0x9f, 0xc5, 0x00, 0x7c, 0xfd, 0x46, 0xdf, 0x86, 0x9b, 0xbd, 0xe3, 0x81, 0xa3, 0xb7, 0x54, - 0x43, 0xb1, 0x71, 0xcf, 0xc6, 0x0e, 0x36, 0x59, 0x7a, 0x4f, 0x9d, 0x46, 0x4e, 0xbe, 0x21, 0xd0, - 0x72, 0x08, 0x8b, 0x3e, 0x86, 0x1b, 0x86, 0xd5, 0x19, 0xc7, 0x17, 0x6c, 0x6e, 0x5c, 0xe7, 0x34, - 0x43, 0xcc, 0x2a, 0x29, 0xc9, 0x7a, 0xea, 0x91, 0x6e, 0xf8, 0xfd, 0x8e, 0x8f, 0x2f, 0x6a, 0x9b, - 0x6b, 0x9b, 0x9e, 0x08, 0xf1, 0x46, 0xc5, 0x17, 0x8a, 0x7e, 0x34, 0xfa, 0x9a, 0xe2, 0xa3, 0x0b, - 0x8f, 0x30, 0xf9, 0x51, 0x45, 0xf9, 0x75, 0x00, 0x7f, 0x7c, 0x7a, 0x7b, 0xbe, 0xb3, 0xe3, 0x67, - 0xa5, 0xfc, 0x1e, 0xbe, 0x7c, 0xf7, 0x25, 0x97, 0xed, 0x00, 0x49, 0xb9, 0xb6, 0xdb, 0x7c, 0x52, - 0x13, 0xd7, 0xed, 0x8b, 0xcd, 0xa1, 0x70, 0x3a, 0x1a, 0x9f, 0x22, 0x33, 0xc6, 0x27, 0x7e, 0x03, - 0xfe, 0x2e, 0xc4, 0xe9, 0x0f, 0xcd, 0xd2, 0x10, 0xaf, 0x35, 0x0e, 0x77, 0xa5, 0x39, 0x94, 0x81, - 0x44, 0x65, 0xa7, 0x5e, 0xd9, 0x97, 0x22, 0x68, 0x01, 0xa4, 0xdd, 0xc3, 0x9d, 0x83, 0xba, 0x5c, - 0x7b, 0x58, 0x6f, 0x36, 0x14, 0x4a, 0x10, 0x0d, 0x04, 0x96, 0xbf, 0x8d, 0x83, 0xc4, 0xbc, 0xfa, - 0x55, 0x43, 0xcb, 0xe4, 0xd6, 0xd7, 0xcb, 0x2f, 0xdd, 0xc3, 0x56, 0x18, 0xff, 0xfa, 0x53, 0xee, - 0xc4, 0xd7, 0x94, 0x72, 0x27, 0xaf, 0x90, 0x72, 0xa7, 0xae, 0xe0, 0x4c, 0xff, 0xd0, 0xa9, 0x71, - 0x40, 0x43, 0x7e, 0x11, 0x05, 0x08, 0xe8, 0xc6, 0x77, 0x83, 0xff, 0x12, 0xc3, 0xe4, 0xdb, 0xf7, - 0xa1, 0xfa, 0x74, 0x7b, 0x4e, 0xfc, 0x3b, 0x0d, 0x0f, 0x21, 0xad, 0xf1, 0xbc, 0x90, 0x67, 0xa8, - 0x6f, 0xcd, 0x9c, 0x3e, 0x6e, 0xcf, 0xc9, 0x1e, 0x33, 0xfa, 0x38, 0xf4, 0xe3, 0xda, 0x3b, 0x33, - 0x99, 0xfe, 0xb6, 0x78, 0xe5, 0x5f, 0x81, 0x24, 0x4b, 0x80, 0xb8, 0xb2, 0x4d, 0xfc, 0x95, 0xe7, - 0x90, 0x69, 0x6c, 0xcf, 0xc9, 0x9c, 0x91, 0xd7, 0xb2, 0x29, 0x48, 0xf4, 0x4d, 0xdd, 0x32, 0xef, - 0xca, 0xc1, 0xf7, 0xe5, 0xa2, 0x71, 0x4b, 0xbc, 0x05, 0xfd, 0x5b, 0x75, 0xb1, 0xc6, 0x9e, 0xf1, - 0x1c, 0x9a, 0x2f, 0x3c, 0x40, 0x04, 0x15, 0x00, 0x38, 0x5e, 0x37, 0x3b, 0x52, 0x94, 0x56, 0xc0, - 0x24, 0xdf, 0x27, 0x5f, 0xb1, 0xbb, 0x9f, 0x80, 0x34, 0xfc, 0x33, 0xd3, 0x80, 0x8f, 0x99, 0x87, - 0xfc, 0xee, 0x93, 0xcd, 0xcd, 0x83, 0xfa, 0x6e, 0x6d, 0xff, 0xa0, 0xb2, 0xbb, 0xc7, 0x1e, 0x2e, - 0x1f, 0x90, 0xf2, 0xb9, 0x59, 0xaf, 0x4a, 0xd1, 0xbb, 0x9f, 0x40, 0x71, 0x48, 0x21, 0x88, 0x3b, - 0xda, 0x3b, 0xdc, 0xd8, 0xa9, 0x6f, 0x8e, 0x7d, 0x10, 0x84, 0xb2, 0x90, 0x6a, 0x6e, 0x6d, 0xed, - 0xd4, 0x1b, 0x35, 0x29, 0x76, 0xf7, 0x7d, 0xc8, 0x05, 0x93, 0x6b, 0x24, 0x41, 0xee, 0xfb, 0xcd, - 0x46, 0x4d, 0xd9, 0xaa, 0xd4, 0x77, 0x0e, 0x65, 0x32, 0x03, 0x04, 0x05, 0xee, 0x57, 0x04, 0x2c, - 0xb2, 0xb1, 0xfa, 0x9b, 0xff, 0x58, 0x9a, 0xfb, 0xcd, 0xf9, 0x52, 0xe4, 0xb7, 0xe7, 0x4b, 0x91, - 0xdf, 0x9f, 0x2f, 0x45, 0xfe, 0xfd, 0x7c, 0x29, 0xf2, 0x97, 0x5f, 0x2e, 0xcd, 0xfd, 0xf6, 0xcb, - 0xa5, 0xb9, 0xdf, 0x7f, 0xb9, 0x34, 0xf7, 0xfd, 0x24, 0xfb, 0x37, 0x44, 0xfe, 0x2f, 0x00, 0x00, - 0xff, 0xff, 0xc0, 0xb2, 0xe3, 0xf9, 0xae, 0x44, 0x00, 0x00, + 0x32, 0x9d, 0x69, 0x6f, 0xbd, 0x36, 0xc7, 0xb4, 0x9d, 0xc9, 0xe4, 0xc4, 0x69, 0xe9, 0x1e, 0xfa, + 0x07, 0xf4, 0xd0, 0xf1, 0xa9, 0xf3, 0xbd, 0xf6, 0x81, 0x97, 0x40, 0xd2, 0xcd, 0xc1, 0x1e, 0xee, + 0xef, 0xf5, 0xbd, 0x7e, 0xef, 0xef, 0x83, 0xe0, 0xb6, 0xf3, 0xdc, 0xb8, 0xd7, 0x52, 0x5d, 0xd5, + 0xb0, 0x3a, 0xf7, 0x34, 0xec, 0xb4, 0x7a, 0x47, 0xf7, 0x1c, 0xd7, 0xee, 0xb7, 0xdc, 0xbe, 0x8d, + 0xb5, 0xb5, 0x9e, 0x6d, 0xb9, 0x16, 0xba, 0xde, 0xb2, 0x5a, 0xcf, 0x6c, 0x4b, 0x6d, 0x1d, 0xaf, + 0x39, 0xcf, 0x0d, 0xf2, 0xdf, 0x91, 0xea, 0xe0, 0xc5, 0x52, 0xdf, 0xd5, 0x8d, 0x7b, 0xc7, 0x46, + 0xeb, 0x9e, 0xab, 0x77, 0xb1, 0xe3, 0xaa, 0xdd, 0x1e, 0x63, 0x58, 0x2c, 0x8f, 0x91, 0xda, 0xb3, + 0xf5, 0x17, 0xba, 0x81, 0x3b, 0x98, 0xd3, 0x5c, 0x27, 0x34, 0xee, 0xa0, 0x87, 0x1d, 0xf6, 0x7f, + 0x0e, 0x7e, 0xa5, 0x83, 0xad, 0x7b, 0x1d, 0x6c, 0xe9, 0xa6, 0x86, 0x4f, 0xef, 0xb5, 0x2c, 0xb3, + 0xad, 0x77, 0x38, 0x6a, 0xa1, 0x63, 0x75, 0x2c, 0xfa, 0xe7, 0x3d, 0xf2, 0x17, 0x83, 0x96, 0x7f, + 0x9a, 0x80, 0x6b, 0x5b, 0x96, 0x8d, 0xf5, 0x8e, 0xf9, 0x18, 0x0f, 0x64, 0xdc, 0xc6, 0x36, 0x36, + 0x5b, 0x18, 0xad, 0x40, 0xc2, 0x55, 0x8f, 0x0c, 0x5c, 0x8a, 0xac, 0x44, 0x56, 0xf3, 0x1b, 0xf0, + 0x9b, 0xb3, 0xe5, 0xb9, 0xaf, 0xce, 0x96, 0xa3, 0xf5, 0xaa, 0xcc, 0x10, 0xe8, 0x0e, 0x24, 0xe8, + 0x28, 0xa5, 0x28, 0xa5, 0x28, 0x72, 0x8a, 0x54, 0x9d, 0x00, 0x09, 0x19, 0xc5, 0xa2, 0x12, 0xc4, + 0x4d, 0xb5, 0x8b, 0x4b, 0xb1, 0x95, 0xc8, 0x6a, 0x66, 0x23, 0x4e, 0xa8, 0x64, 0x0a, 0x41, 0x8f, + 0x21, 0xfd, 0x42, 0x35, 0x74, 0x4d, 0x77, 0x07, 0xa5, 0xf8, 0x4a, 0x64, 0xb5, 0xb0, 0xfe, 0xd6, + 0xda, 0xd8, 0xad, 0x5a, 0xdb, 0xb4, 0x4c, 0xc7, 0xb5, 0x55, 0xdd, 0x74, 0x9f, 0x70, 0x06, 0x2e, + 0xc8, 0x13, 0x80, 0xee, 0xc3, 0xbc, 0x73, 0xac, 0xda, 0x58, 0x53, 0x7a, 0x36, 0x6e, 0xeb, 0xa7, + 0x8a, 0x81, 0xcd, 0x52, 0x62, 0x25, 0xb2, 0x9a, 0xe0, 0xa4, 0x45, 0x86, 0xde, 0xa3, 0xd8, 0x1d, + 0x6c, 0xa2, 0x03, 0xc8, 0x58, 0xa6, 0xa2, 0x61, 0x03, 0xbb, 0xb8, 0x94, 0xa4, 0xe3, 0xbf, 0x3b, + 0x61, 0xfc, 0x31, 0x1b, 0xb4, 0x56, 0x69, 0xb9, 0xba, 0x65, 0x8a, 0x79, 0x58, 0x66, 0x95, 0x0a, + 0xe2, 0x52, 0xfb, 0x3d, 0x4d, 0x75, 0x71, 0x29, 0x75, 0x65, 0xa9, 0x87, 0x54, 0x10, 0xda, 0x81, + 0x44, 0x57, 0x75, 0x5b, 0xc7, 0xa5, 0x34, 0x95, 0x78, 0xff, 0x02, 0x12, 0x77, 0x09, 0x1f, 0x17, + 0xc8, 0x84, 0x94, 0x9f, 0x42, 0x92, 0x8d, 0x83, 0xf2, 0x90, 0x69, 0x34, 0x95, 0xca, 0xe6, 0x41, + 0xbd, 0xd9, 0x90, 0xe6, 0x50, 0x0e, 0xd2, 0x72, 0x6d, 0xff, 0x40, 0xae, 0x6f, 0x1e, 0x48, 0x11, + 0xf2, 0xb5, 0x5f, 0x3b, 0x50, 0x1a, 0x87, 0x3b, 0x3b, 0x52, 0x14, 0x15, 0x21, 0x4b, 0xbe, 0xaa, + 0xb5, 0xad, 0xca, 0xe1, 0xce, 0x81, 0x14, 0x43, 0x59, 0x48, 0x6d, 0x56, 0xf6, 0x37, 0x2b, 0xd5, + 0x9a, 0x14, 0x5f, 0x8c, 0xff, 0xf2, 0x17, 0x4b, 0x73, 0xe5, 0xfb, 0x90, 0xa0, 0xc3, 0x21, 0x80, + 0xe4, 0x7e, 0x7d, 0x77, 0x6f, 0xa7, 0x26, 0xcd, 0xa1, 0x34, 0xc4, 0xb7, 0x88, 0x88, 0x08, 0xe1, + 0xd8, 0xab, 0xc8, 0x07, 0xf5, 0xca, 0x8e, 0x14, 0x65, 0x1c, 0x1f, 0xc5, 0xff, 0xfb, 0xe7, 0xcb, + 0x91, 0xf2, 0xbf, 0x26, 0x60, 0xc1, 0x9f, 0xbb, 0x7f, 0xda, 0x68, 0x13, 0x8a, 0x96, 0xad, 0x77, + 0x74, 0x53, 0xa1, 0x3a, 0xa7, 0xe8, 0x1a, 0xd7, 0xc7, 0x6f, 0x90, 0xf5, 0x9c, 0x9f, 0x2d, 0xe7, + 0x9b, 0x14, 0x7d, 0x40, 0xb0, 0xf5, 0x2a, 0x57, 0xd0, 0xbc, 0x15, 0x00, 0x6a, 0xe8, 0x31, 0xcc, + 0x73, 0x21, 0x2d, 0xcb, 0xe8, 0x77, 0x4d, 0x45, 0xd7, 0x9c, 0x52, 0x74, 0x25, 0xb6, 0x9a, 0xdf, + 0x58, 0x3e, 0x3f, 0x5b, 0x2e, 0x32, 0x11, 0x9b, 0x14, 0x57, 0xaf, 0x3a, 0x5f, 0x9d, 0x2d, 0xa7, + 0xc5, 0x87, 0xcc, 0x87, 0xe7, 0xdf, 0x9a, 0x83, 0x9e, 0xc2, 0x75, 0x5b, 0xec, 0xad, 0x16, 0x14, + 0x18, 0xa3, 0x02, 0x6f, 0x9f, 0x9f, 0x2d, 0x5f, 0xf3, 0x36, 0x5f, 0x1b, 0x2f, 0xf4, 0x9a, 0x3d, + 0x4c, 0xa0, 0x39, 0xa8, 0x09, 0x01, 0xb0, 0xbf, 0xdc, 0x38, 0x5d, 0xee, 0x32, 0x5f, 0xee, 0xbc, + 0x2f, 0x3a, 0xbc, 0xe4, 0x79, 0x7b, 0x08, 0xa1, 0x79, 0x86, 0x97, 0x98, 0x6a, 0x78, 0xc9, 0xab, + 0x1a, 0x5e, 0xc8, 0x8c, 0x52, 0xff, 0x2f, 0x66, 0x94, 0xfe, 0xda, 0xcd, 0x28, 0xf3, 0x35, 0x98, + 0x11, 0xd3, 0xdd, 0x47, 0xf1, 0x34, 0x48, 0xd9, 0x47, 0xf1, 0x74, 0x56, 0xca, 0x3d, 0x8a, 0xa7, + 0x73, 0x52, 0xfe, 0x51, 0x3c, 0x9d, 0x97, 0x0a, 0xe5, 0xbf, 0x89, 0xc2, 0xab, 0x87, 0xa6, 0xfe, + 0xbc, 0x8f, 0x9f, 0xea, 0xee, 0xb1, 0xd5, 0x77, 0xa9, 0x5f, 0x0c, 0xe8, 0xf6, 0x7d, 0x48, 0x0f, + 0x29, 0xf5, 0x75, 0x7e, 0xca, 0xa9, 0xf0, 0xd9, 0xa6, 0x5c, 0x7e, 0xa2, 0x0f, 0x00, 0x46, 0x34, + 0xf8, 0x95, 0xf3, 0xb3, 0xe5, 0xcc, 0x78, 0x35, 0xcb, 0xb4, 0x3c, 0xe5, 0xfa, 0x03, 0x39, 0xe1, + 0x32, 0x64, 0x7a, 0x36, 0xd6, 0xf4, 0x16, 0x39, 0xb5, 0xa0, 0xde, 0xf9, 0x60, 0x6e, 0xf1, 0x7f, + 0x95, 0x00, 0x89, 0x4d, 0xb4, 0x8a, 0x9d, 0x96, 0xad, 0xf7, 0x5c, 0xcb, 0xf6, 0x66, 0x19, 0x19, + 0x99, 0xe5, 0x1b, 0x10, 0xd5, 0x35, 0x1e, 0x68, 0x6e, 0xf0, 0x5d, 0x8a, 0xd2, 0x0d, 0xf2, 0x97, + 0x1b, 0xd5, 0x35, 0xb4, 0x06, 0x71, 0x12, 0x0d, 0xe9, 0x3a, 0xb3, 0xeb, 0x8b, 0xc3, 0x2b, 0xc1, + 0xdd, 0x35, 0x16, 0x2c, 0x0f, 0x64, 0x4a, 0x87, 0x56, 0x20, 0x6d, 0xf6, 0x0d, 0x83, 0x06, 0x3a, + 0xb2, 0xfa, 0xb4, 0x58, 0x92, 0x80, 0xa2, 0x5b, 0x90, 0xd3, 0x70, 0x5b, 0xed, 0x1b, 0xae, 0x82, + 0x4f, 0x7b, 0x36, 0x5b, 0x95, 0x9c, 0xe5, 0xb0, 0xda, 0x69, 0xcf, 0x46, 0xaf, 0x42, 0xf2, 0x58, + 0xd7, 0x34, 0x6c, 0x52, 0x63, 0x12, 0x22, 0x38, 0x0c, 0xad, 0xc3, 0x7c, 0xdf, 0xc1, 0x8e, 0xe2, + 0xe0, 0xe7, 0x7d, 0xa2, 0x49, 0xf4, 0xec, 0x80, 0x9e, 0x5d, 0x92, 0x1f, 0x70, 0x91, 0x10, 0xec, + 0x73, 0x3c, 0x39, 0xae, 0x5b, 0x90, 0x6b, 0x59, 0xdd, 0x5e, 0xdf, 0xc5, 0x6c, 0xd0, 0x2c, 0x1b, + 0x94, 0xc3, 0xe8, 0xa0, 0xeb, 0x30, 0x6f, 0x9d, 0x98, 0x43, 0x62, 0x73, 0x61, 0xb1, 0x84, 0x20, + 0x28, 0xf6, 0x53, 0x90, 0x7a, 0x1d, 0x45, 0x75, 0x5d, 0x5b, 0x3f, 0x22, 0xb2, 0xcd, 0x7e, 0xb7, + 0x94, 0x0f, 0xed, 0x69, 0x61, 0xef, 0x61, 0x45, 0xa0, 0x1b, 0xfd, 0xae, 0x5c, 0xe8, 0x75, 0x82, + 0xdf, 0x68, 0x0b, 0x5e, 0x53, 0x0d, 0x17, 0xdb, 0xc2, 0xf1, 0x91, 0x4d, 0x54, 0x74, 0x53, 0xe9, + 0xd9, 0x56, 0xc7, 0xc6, 0x8e, 0x53, 0x2a, 0x04, 0x76, 0xe0, 0x15, 0x4a, 0xca, 0xce, 0xe7, 0x60, + 0xd0, 0xc3, 0x75, 0x73, 0x8f, 0x93, 0xa1, 0x1f, 0x00, 0x72, 0x06, 0x8e, 0x8b, 0xbb, 0x42, 0xd0, + 0x33, 0xdd, 0xd4, 0x4a, 0x45, 0xaa, 0x7f, 0x6f, 0x4e, 0xd0, 0xbf, 0x7d, 0xca, 0xc0, 0xc4, 0x3d, + 0xd6, 0x4d, 0x8d, 0x8f, 0x22, 0x39, 0x43, 0x70, 0xb4, 0x04, 0xa9, 0x17, 0xba, 0xed, 0xf6, 0x55, + 0xa3, 0x24, 0x05, 0xa6, 0x23, 0x80, 0x9e, 0xdd, 0xa6, 0xa5, 0xcc, 0xa3, 0x78, 0x3a, 0x23, 0xc1, + 0xa3, 0x78, 0x3a, 0x25, 0xa5, 0xcb, 0x7f, 0x1e, 0x85, 0x1b, 0x4c, 0xcc, 0x96, 0xda, 0xd5, 0x8d, + 0xc1, 0x55, 0x35, 0x93, 0x49, 0xe1, 0x9a, 0x49, 0x8f, 0x94, 0x2e, 0x95, 0xb0, 0xb1, 0x70, 0x41, + 0x8f, 0x94, 0xc0, 0x1a, 0x04, 0x34, 0x64, 0xde, 0xf1, 0x0b, 0x98, 0x77, 0x13, 0xe6, 0x85, 0x92, + 0x7a, 0x12, 0xa8, 0xa6, 0xe6, 0x37, 0x6e, 0xf3, 0x39, 0x15, 0xab, 0x8c, 0x40, 0xb0, 0x87, 0xa3, + 0x9c, 0x16, 0x42, 0x6a, 0xdc, 0x48, 0xff, 0x29, 0x0a, 0x0b, 0x75, 0xd3, 0xc5, 0xb6, 0x81, 0xd5, + 0x17, 0x38, 0xb0, 0x1d, 0x9f, 0x43, 0x46, 0x35, 0x5b, 0xd8, 0x71, 0x2d, 0xdb, 0x29, 0x45, 0x56, + 0x62, 0xab, 0xd9, 0xf5, 0xf7, 0x27, 0x9c, 0xda, 0x38, 0xfe, 0xb5, 0x0a, 0x67, 0x16, 0xde, 0xc1, + 0x13, 0xb6, 0xf8, 0xcf, 0x11, 0x48, 0x0b, 0xec, 0x25, 0x3c, 0xe4, 0xb7, 0x20, 0x4d, 0xb3, 0x4e, + 0xc5, 0x3b, 0x93, 0x45, 0xc1, 0xc1, 0xd3, 0xd2, 0x60, 0x86, 0x9a, 0xa2, 0xb4, 0x75, 0x0d, 0x6d, + 0x8e, 0x4b, 0x1e, 0x63, 0x94, 0xff, 0xa6, 0xd8, 0xbf, 0xfd, 0x70, 0xfa, 0x38, 0x92, 0x4f, 0xb2, + 0x3d, 0xe3, 0x3b, 0xf7, 0x8f, 0x11, 0x98, 0x27, 0x0c, 0x1a, 0xd6, 0x02, 0xdb, 0x76, 0x1b, 0x40, + 0x77, 0x14, 0x87, 0xc1, 0xe9, 0x8a, 0x84, 0x6e, 0x66, 0x74, 0x87, 0x93, 0x7b, 0xaa, 0x16, 0x1d, + 0x51, 0xb5, 0x0f, 0x21, 0x4f, 0x79, 0x95, 0xa3, 0x7e, 0xeb, 0x19, 0x76, 0x1d, 0x3a, 0xc3, 0xc4, + 0xc6, 0x02, 0x9f, 0x61, 0x8e, 0x4a, 0xd8, 0x60, 0x38, 0x39, 0xe7, 0x04, 0xbe, 0x46, 0xb4, 0x2f, + 0x3e, 0xa2, 0x7d, 0x7c, 0xe2, 0xbf, 0x8a, 0xc3, 0x8d, 0x3d, 0xd5, 0x76, 0x75, 0x12, 0x3f, 0x75, + 0xb3, 0x13, 0x98, 0xfd, 0x1d, 0xc8, 0x9a, 0x7d, 0x61, 0xb0, 0x0e, 0x3f, 0x10, 0x36, 0x3f, 0x30, + 0xfb, 0xdc, 0x00, 0x1d, 0xb4, 0x03, 0x71, 0x43, 0x77, 0x5c, 0x1a, 0x9e, 0xb2, 0xeb, 0xeb, 0x13, + 0xd4, 0x62, 0xfc, 0x18, 0x6b, 0x3b, 0xba, 0xe3, 0x8a, 0x35, 0x13, 0x29, 0xa8, 0x09, 0x09, 0x5b, + 0x35, 0x3b, 0x98, 0xda, 0x4b, 0x76, 0xfd, 0xbd, 0x8b, 0x89, 0x93, 0x09, 0xab, 0x08, 0xda, 0x54, + 0x0e, 0xfa, 0x00, 0x16, 0xc8, 0x2a, 0xf4, 0x6e, 0xcf, 0xd0, 0x5b, 0xba, 0xeb, 0x2d, 0x27, 0x1e, + 0x58, 0x0e, 0x32, 0xfb, 0xdd, 0x3a, 0x27, 0xe0, 0xcb, 0x5a, 0xfc, 0x59, 0x04, 0xe2, 0x64, 0x76, + 0x53, 0x5c, 0xc1, 0x0d, 0x48, 0xbe, 0x50, 0x8d, 0x3e, 0x66, 0xa1, 0x39, 0x27, 0xf3, 0x2f, 0xf4, + 0x43, 0x28, 0x3a, 0xfd, 0xa3, 0x5e, 0x60, 0x8a, 0x3c, 0x3e, 0xbd, 0x73, 0xa1, 0xd5, 0x78, 0x75, + 0x4c, 0x58, 0x16, 0x3b, 0xb8, 0xc5, 0xe7, 0x90, 0xa0, 0xab, 0x9d, 0x32, 0xbf, 0x5b, 0x90, 0x73, + 0x2d, 0x05, 0x9f, 0xb6, 0x8c, 0xbe, 0xa3, 0xbf, 0x60, 0x1a, 0x96, 0x93, 0xb3, 0xae, 0x55, 0x13, + 0x20, 0x74, 0x07, 0x0a, 0x6d, 0xdb, 0xea, 0x2a, 0xba, 0x29, 0x88, 0x62, 0x94, 0x28, 0x4f, 0xa0, + 0x75, 0x01, 0x0c, 0xa9, 0xfa, 0x5f, 0xe7, 0xa0, 0x48, 0x0d, 0x6a, 0x26, 0x77, 0x79, 0x27, 0xe0, + 0x2e, 0xaf, 0x87, 0xdc, 0xa5, 0x67, 0x95, 0xc4, 0x5b, 0xbe, 0x0a, 0xc9, 0x3e, 0xcd, 0x9d, 0xe8, + 0xf8, 0x5e, 0x48, 0x65, 0xb0, 0x19, 0xb4, 0x19, 0x7d, 0x13, 0x10, 0x71, 0x21, 0x58, 0x09, 0x11, + 0x26, 0x28, 0xa1, 0x44, 0x31, 0x9b, 0x13, 0x3d, 0x6f, 0xf2, 0x02, 0x9e, 0x77, 0x1b, 0x24, 0x7c, + 0xea, 0xda, 0x6a, 0xb0, 0x12, 0x48, 0x51, 0xfe, 0x25, 0x12, 0x4e, 0x6b, 0x04, 0x37, 0x5e, 0x48, + 0x01, 0x07, 0x70, 0x1a, 0xd1, 0x92, 0x79, 0x2e, 0x43, 0xd3, 0x6d, 0x4c, 0xf3, 0x57, 0xa7, 0x94, + 0x5e, 0x89, 0x4d, 0xc9, 0x53, 0x87, 0xb6, 0x7d, 0xad, 0x2a, 0x18, 0x65, 0x89, 0x89, 0xf2, 0x00, + 0x0e, 0xda, 0x87, 0x6c, 0x9b, 0xa5, 0xb5, 0xca, 0x33, 0x3c, 0xa0, 0x09, 0x70, 0x76, 0xfd, 0xee, + 0xec, 0x09, 0xf0, 0x46, 0x92, 0x1c, 0x41, 0x29, 0x22, 0x43, 0xdb, 0x43, 0xa2, 0xa7, 0x90, 0x0f, + 0xd4, 0x2c, 0x47, 0x03, 0x9a, 0xd7, 0x5c, 0x4e, 0x6c, 0xce, 0x17, 0xb4, 0x31, 0x40, 0x9f, 0x01, + 0xe8, 0x5e, 0xe0, 0xa0, 0xe9, 0x4f, 0x76, 0xfd, 0xed, 0x0b, 0x44, 0x18, 0xe1, 0x97, 0x7c, 0x21, + 0xe8, 0x29, 0x14, 0xfc, 0x2f, 0x3a, 0xd9, 0xdc, 0x85, 0x27, 0xcb, 0xa4, 0xe6, 0x03, 0x72, 0x36, + 0x48, 0x01, 0xb4, 0x40, 0x12, 0x33, 0xcb, 0xd1, 0x5d, 0x1c, 0x54, 0x83, 0x3c, 0x55, 0x83, 0xf2, + 0xf9, 0xd9, 0x32, 0xda, 0x14, 0xf8, 0xf1, 0xaa, 0x80, 0x5a, 0x43, 0x78, 0xa6, 0x58, 0x21, 0x05, + 0x26, 0x12, 0x0b, 0xbe, 0x62, 0xed, 0xfb, 0x2a, 0x3c, 0xa2, 0x58, 0x01, 0xf5, 0x66, 0x15, 0x6b, + 0x2e, 0xe4, 0x7b, 0x8a, 0x97, 0xf7, 0x3d, 0x21, 0x41, 0xa8, 0xc6, 0x93, 0x6d, 0x89, 0xa6, 0x6d, + 0x6f, 0xcf, 0xa8, 0xa4, 0x24, 0x13, 0x14, 0x2e, 0x81, 0xe6, 0xe0, 0xef, 0x01, 0x6a, 0xd9, 0x58, + 0x75, 0xb1, 0x46, 0x92, 0x5d, 0xea, 0x74, 0x8d, 0x41, 0x69, 0x3e, 0x60, 0xf7, 0xf3, 0x1c, 0x5f, + 0xf3, 0xd0, 0xe8, 0x01, 0xa4, 0x5e, 0x60, 0xdb, 0xd1, 0x2d, 0xb3, 0x84, 0xa8, 0x33, 0x59, 0xe2, + 0xed, 0xa7, 0x1b, 0x43, 0xe3, 0x3d, 0x61, 0x54, 0xb2, 0x20, 0x47, 0xdb, 0x90, 0xc7, 0x66, 0xcb, + 0xd2, 0x74, 0xb3, 0x43, 0xd3, 0xd7, 0xd2, 0x35, 0x3f, 0x4f, 0xfa, 0xea, 0x6c, 0xf9, 0x1b, 0x43, + 0xfc, 0x35, 0x4e, 0x4b, 0xa6, 0x2d, 0xe7, 0x70, 0xe0, 0x0b, 0x6d, 0x43, 0x4a, 0xc4, 0xf2, 0x05, + 0xba, 0xa7, 0xab, 0x93, 0x32, 0xd7, 0xe1, 0x4c, 0x40, 0x64, 0xa4, 0x9c, 0x9d, 0x94, 0x21, 0x9a, + 0xee, 0x90, 0x1c, 0x46, 0x2b, 0x5d, 0x0f, 0x96, 0x21, 0x02, 0x8a, 0x36, 0x01, 0x3a, 0xd8, 0x52, + 0x58, 0x43, 0xaf, 0x74, 0x83, 0x0e, 0xb7, 0x14, 0x18, 0xae, 0x83, 0xad, 0x35, 0xd1, 0xf6, 0x23, + 0x95, 0x5a, 0x5b, 0xef, 0x88, 0xd4, 0xa2, 0x83, 0x2d, 0x06, 0x08, 0x97, 0x67, 0x37, 0xc7, 0x96, + 0x67, 0xe5, 0x25, 0xc8, 0x78, 0x5e, 0x03, 0xa5, 0x20, 0x56, 0xd9, 0xdf, 0x64, 0x3d, 0x9c, 0x6a, + 0x6d, 0x7f, 0x53, 0x8a, 0x94, 0x6f, 0x41, 0x9c, 0x2e, 0x3e, 0x0b, 0xa9, 0xad, 0xa6, 0xfc, 0xb4, + 0x22, 0x57, 0x59, 0xdf, 0xa8, 0xde, 0x78, 0x52, 0x93, 0x0f, 0x6a, 0x55, 0x49, 0xc4, 0x85, 0xb3, + 0x38, 0x20, 0xbf, 0x64, 0x3c, 0xb0, 0x78, 0x09, 0xde, 0x81, 0x62, 0xcb, 0x83, 0xb2, 0x03, 0x88, + 0xac, 0x44, 0x57, 0x0b, 0xeb, 0x0f, 0x5e, 0x5a, 0x76, 0x0a, 0x19, 0x41, 0x90, 0xaf, 0x4c, 0x85, + 0x56, 0x08, 0x1a, 0xc8, 0xa3, 0xa2, 0x43, 0x31, 0x48, 0x86, 0x44, 0xeb, 0x18, 0xb7, 0x9e, 0xf1, + 0x28, 0xfc, 0xc1, 0x84, 0x81, 0x69, 0x8a, 0x19, 0x50, 0xdc, 0x4d, 0xc2, 0xe3, 0x0f, 0x2d, 0xd2, + 0x0a, 0x2a, 0x0a, 0xc9, 0x61, 0xf7, 0x1a, 0x9f, 0xea, 0xb1, 0xc6, 0xb5, 0xba, 0x84, 0xc7, 0x0a, + 0x78, 0xd7, 0x07, 0x50, 0x34, 0x2d, 0x57, 0x21, 0xa5, 0x28, 0xf7, 0x02, 0xb4, 0xc0, 0xcc, 0x6f, + 0x48, 0x5c, 0x57, 0x7d, 0x9b, 0xcf, 0x9b, 0x96, 0xdb, 0xe8, 0x1b, 0x06, 0x03, 0xa0, 0x3f, 0x8d, + 0xc0, 0x32, 0x8b, 0x95, 0xca, 0x09, 0x6b, 0x3e, 0x28, 0x2c, 0x2d, 0xf6, 0xf7, 0x88, 0xb6, 0x6a, + 0x26, 0x27, 0x54, 0xd3, 0x3a, 0x17, 0x7c, 0xaa, 0xaf, 0xf6, 0xa7, 0xd0, 0x94, 0x0f, 0xa0, 0x10, + 0x3e, 0x26, 0x94, 0x81, 0xc4, 0xe6, 0x76, 0x6d, 0xf3, 0xb1, 0x34, 0x87, 0x8a, 0x90, 0xdd, 0x6a, + 0xca, 0xb5, 0xfa, 0xc3, 0x86, 0xf2, 0xb8, 0xf6, 0x3d, 0xd6, 0x6a, 0x6c, 0x34, 0xbd, 0x56, 0x63, + 0x09, 0x16, 0x0e, 0x1b, 0xf5, 0xcf, 0x0e, 0x6b, 0xca, 0xd3, 0xfa, 0xc1, 0x76, 0xf3, 0xf0, 0x40, + 0xa9, 0x37, 0xaa, 0xb5, 0xcf, 0xa5, 0x98, 0x57, 0xba, 0x25, 0xa4, 0x64, 0xf9, 0xdf, 0x93, 0x50, + 0xd8, 0xb3, 0xf5, 0xae, 0x6a, 0x0f, 0x1e, 0xe3, 0xc1, 0xfe, 0x89, 0xda, 0x43, 0x9f, 0xc2, 0x82, + 0x89, 0x4f, 0x94, 0x1e, 0x83, 0x2a, 0x5e, 0x29, 0x10, 0x19, 0xdf, 0xa1, 0x9e, 0x37, 0xf1, 0x09, + 0x97, 0x50, 0xe7, 0x95, 0xc0, 0x37, 0x21, 0x6b, 0x19, 0x1a, 0xe3, 0xc4, 0xa2, 0xc7, 0x92, 0x0d, + 0x32, 0x81, 0x65, 0x68, 0x75, 0x86, 0x26, 0xd4, 0x64, 0x3c, 0x41, 0x1d, 0x1b, 0x43, 0x6d, 0xe2, + 0x13, 0x41, 0xfd, 0x29, 0x2c, 0x10, 0xd9, 0x23, 0xb3, 0x8b, 0x4f, 0x98, 0x9d, 0x65, 0x68, 0x43, + 0xb3, 0xfb, 0x10, 0x6e, 0x8c, 0xae, 0x6f, 0xa4, 0xc9, 0x77, 0x6d, 0x68, 0x59, 0x24, 0xc7, 0x41, + 0x5f, 0xc0, 0x82, 0x61, 0xb5, 0x54, 0x43, 0x77, 0x07, 0xdc, 0x8b, 0x28, 0xce, 0x89, 0xda, 0xa3, + 0x1a, 0x95, 0x9d, 0x68, 0x7c, 0xe1, 0xfd, 0x5d, 0xdb, 0xe1, 0x12, 0x98, 0x3f, 0x21, 0x20, 0x19, + 0x19, 0x23, 0xb0, 0xc5, 0x7f, 0x88, 0x01, 0x1a, 0x25, 0x45, 0xcf, 0xe0, 0x1a, 0x59, 0xff, 0xd0, + 0x34, 0xe8, 0xe1, 0x64, 0xd7, 0xbf, 0x35, 0xa3, 0x15, 0x86, 0xe5, 0x8a, 0x00, 0x61, 0x19, 0x5a, + 0x18, 0x41, 0x06, 0x23, 0x5b, 0x35, 0x3c, 0x58, 0xf4, 0x6b, 0x18, 0xcc, 0xc4, 0x27, 0x43, 0x83, + 0xe9, 0xf0, 0x1a, 0x19, 0xcc, 0xc6, 0x1d, 0xdd, 0x32, 0x55, 0x43, 0x39, 0x1a, 0x28, 0xb6, 0x75, + 0x12, 0xa8, 0xc5, 0x59, 0x2d, 0xb9, 0x7a, 0x7e, 0xb6, 0x5c, 0x6a, 0xe0, 0x13, 0x99, 0xd3, 0x6d, + 0x0c, 0x64, 0xeb, 0x64, 0x6c, 0x41, 0x5e, 0x32, 0xc7, 0x53, 0x69, 0x48, 0x86, 0x37, 0xa7, 0x0c, + 0x15, 0x6a, 0x55, 0xc5, 0x69, 0xd7, 0xe8, 0xd6, 0x78, 0x51, 0x55, 0xbf, 0x81, 0x15, 0x4a, 0xe7, + 0x7f, 0x15, 0x01, 0x9a, 0xae, 0xf4, 0x5d, 0xd1, 0x9c, 0xa6, 0x67, 0xf7, 0x3e, 0xe4, 0xc9, 0xb0, + 0xfe, 0x8a, 0x22, 0x13, 0x3c, 0x11, 0x31, 0x08, 0x6f, 0xb2, 0xef, 0x43, 0x9e, 0x9c, 0xb8, 0xcf, + 0x15, 0x9d, 0xc4, 0x65, 0x19, 0x5e, 0x2b, 0x1c, 0xbd, 0x09, 0x39, 0xdd, 0x24, 0xe1, 0x9a, 0x77, + 0xbf, 0x82, 0x4d, 0xcb, 0x2c, 0xc7, 0xf8, 0xf3, 0x2e, 0xff, 0x3a, 0x0a, 0x37, 0x77, 0x55, 0x17, + 0xdb, 0xba, 0x6a, 0xe8, 0x3f, 0xc1, 0xda, 0x13, 0x9d, 0x2c, 0xb8, 0x6d, 0x63, 0xe7, 0x18, 0x7d, + 0x0e, 0xf3, 0x23, 0x06, 0xc3, 0x15, 0xee, 0x8d, 0xd9, 0xf2, 0x15, 0x51, 0x75, 0x0d, 0xd9, 0x14, + 0xda, 0x0d, 0x9b, 0x3e, 0xab, 0x76, 0x2f, 0x26, 0x33, 0xe8, 0x1b, 0x1e, 0x40, 0x42, 0x75, 0x14, + 0xab, 0xcd, 0x63, 0xd2, 0x6b, 0x01, 0x41, 0x7d, 0x57, 0x37, 0xd6, 0x8e, 0x8d, 0xd6, 0xda, 0x81, + 0xb8, 0x26, 0x14, 0xd1, 0x4c, 0x75, 0x9a, 0x6d, 0xf4, 0x0e, 0x14, 0x9d, 0x63, 0xab, 0x6f, 0x68, + 0xca, 0x91, 0xda, 0x7a, 0xd6, 0xd6, 0x0d, 0x23, 0xd4, 0xc9, 0x2c, 0x30, 0xe4, 0x06, 0xc7, 0xf1, + 0x3d, 0xfb, 0x8b, 0x14, 0x20, 0x7f, 0x3e, 0xbb, 0x7d, 0x57, 0xa5, 0xf1, 0xbe, 0x02, 0x49, 0x1e, + 0x68, 0xd8, 0x1e, 0xbd, 0x39, 0x31, 0x26, 0x87, 0x3b, 0xb7, 0xdb, 0x73, 0x32, 0x67, 0x44, 0xdf, + 0x0d, 0xde, 0x0a, 0xce, 0xbc, 0x23, 0xdb, 0x73, 0xe2, 0xba, 0xf0, 0x31, 0x24, 0x1c, 0x97, 0xe4, + 0x27, 0x31, 0x9a, 0x55, 0xde, 0x9b, 0xc0, 0x3f, 0x3a, 0xf9, 0xb5, 0x7d, 0xc2, 0x26, 0xa2, 0x32, + 0x95, 0x81, 0x9e, 0x42, 0xc6, 0x2b, 0xa6, 0x78, 0x77, 0xfb, 0xbd, 0xd9, 0x05, 0x7a, 0x79, 0x90, + 0xc8, 0x92, 0x3c, 0x59, 0xa8, 0x02, 0xd9, 0x2e, 0x27, 0xf3, 0x5b, 0x6d, 0x2b, 0xbc, 0x9e, 0x05, + 0x21, 0x81, 0x1a, 0x75, 0xe0, 0x4b, 0x06, 0xc1, 0x54, 0xa7, 0x39, 0x9f, 0x6d, 0x19, 0x06, 0x39, + 0x34, 0x1a, 0x8b, 0xbd, 0x9c, 0x4f, 0x40, 0xd1, 0x63, 0x52, 0x95, 0x7a, 0xf1, 0x3a, 0x4d, 0xf7, + 0xf3, 0xad, 0x99, 0xb3, 0xa4, 0xed, 0x39, 0x39, 0xc0, 0x8e, 0x9a, 0x50, 0xe8, 0x85, 0x9c, 0x39, + 0x2f, 0x01, 0xef, 0xcc, 0xe4, 0xf9, 0xb7, 0xe7, 0xe4, 0x21, 0x76, 0xf4, 0x03, 0x40, 0xad, 0x11, + 0x3f, 0x51, 0x82, 0x97, 0xcc, 0x72, 0x98, 0x61, 0x7b, 0x4e, 0x1e, 0x23, 0x06, 0x7d, 0x01, 0x37, + 0xbb, 0xe3, 0x4d, 0x9a, 0x17, 0x83, 0x6b, 0x13, 0x46, 0x98, 0xe0, 0x08, 0xb6, 0xe7, 0xe4, 0x49, + 0x02, 0xcb, 0x9f, 0x42, 0x82, 0xaa, 0x0e, 0x49, 0x69, 0x0f, 0x1b, 0x8f, 0x1b, 0xcd, 0xa7, 0x0d, + 0x96, 0xa2, 0x54, 0x6b, 0x3b, 0xb5, 0x83, 0x9a, 0xd2, 0x6c, 0xec, 0x90, 0x14, 0xe5, 0x15, 0xb8, + 0xce, 0x01, 0x95, 0x46, 0x55, 0x79, 0x2a, 0xd7, 0x05, 0x2a, 0x5a, 0x5e, 0x0d, 0xe6, 0xcc, 0x69, + 0x88, 0x37, 0x9a, 0x8d, 0x9a, 0x34, 0x47, 0xb3, 0xe7, 0x6a, 0x55, 0x8a, 0xd0, 0xec, 0x59, 0x6e, + 0xee, 0x49, 0x51, 0x66, 0x7d, 0x1b, 0x39, 0x00, 0xcd, 0x53, 0xb7, 0x47, 0xf1, 0x74, 0x52, 0x4a, + 0x95, 0xff, 0x3e, 0x02, 0x69, 0x12, 0xa8, 0xeb, 0x66, 0xdb, 0x42, 0xef, 0x41, 0xa6, 0xa7, 0xda, + 0xd8, 0x74, 0x7d, 0x4f, 0x2b, 0x7a, 0xcb, 0xe9, 0x3d, 0x8a, 0xf0, 0x5a, 0x9f, 0x69, 0x46, 0x58, + 0x9f, 0xd6, 0x38, 0xdc, 0x02, 0x89, 0x8b, 0x73, 0x5a, 0xc7, 0xb8, 0xab, 0xfa, 0x11, 0xe9, 0x55, + 0xaf, 0xef, 0x4f, 0xf1, 0xfb, 0x14, 0xed, 0xc9, 0x2e, 0xf4, 0x82, 0x50, 0xd1, 0x15, 0xfe, 0xb7, + 0x55, 0x28, 0x0e, 0x05, 0xca, 0x29, 0x0d, 0x9f, 0x15, 0xda, 0xf0, 0x89, 0xf9, 0x7e, 0xdf, 0x6b, + 0xf8, 0x44, 0x79, 0xaf, 0x27, 0xb4, 0xd8, 0xf8, 0x8c, 0x8b, 0x7d, 0xcf, 0xaf, 0xff, 0x98, 0xf1, + 0xbd, 0xc2, 0x63, 0xca, 0xfc, 0x94, 0xd2, 0x6f, 0x0f, 0xe6, 0xbb, 0x96, 0xa6, 0xb7, 0x49, 0xa5, + 0x43, 0x2c, 0xd7, 0xd5, 0xbb, 0x98, 0xe7, 0xc1, 0x33, 0x39, 0x5c, 0x29, 0xc8, 0x4d, 0x90, 0xe8, + 0x21, 0xa4, 0x44, 0x03, 0x31, 0x4d, 0x23, 0xc0, 0xac, 0x1e, 0x53, 0x54, 0x80, 0x9c, 0x1b, 0x6d, + 0x41, 0xc1, 0xc4, 0xa7, 0xc1, 0xf6, 0x7d, 0x26, 0xe4, 0x53, 0x72, 0x0d, 0x7c, 0x3a, 0xbe, 0x77, + 0x9f, 0x33, 0x7d, 0x8c, 0x86, 0x3e, 0x83, 0x7c, 0x38, 0xd8, 0xc1, 0x25, 0x82, 0x5d, 0xae, 0x17, + 0x8c, 0x74, 0x5b, 0x90, 0x12, 0x51, 0x2e, 0x7b, 0x89, 0x28, 0x27, 0x98, 0xd1, 0x06, 0x49, 0x21, + 0x4e, 0x5d, 0x3f, 0xef, 0xcd, 0xf9, 0x85, 0xfb, 0xf9, 0xd9, 0x72, 0x96, 0xac, 0x70, 0x4c, 0x93, + 0x3e, 0x6b, 0x7a, 0x70, 0x0d, 0x3d, 0x02, 0xf0, 0x1e, 0xc2, 0x38, 0xf4, 0xee, 0x6a, 0x72, 0x03, + 0x67, 0x4f, 0x10, 0xfa, 0x53, 0x92, 0x03, 0xdc, 0x68, 0x17, 0x32, 0xc2, 0x1d, 0xb3, 0xd6, 0xca, + 0x64, 0xbf, 0x35, 0x1a, 0x1c, 0x44, 0x48, 0xf0, 0x24, 0x90, 0xaa, 0xd2, 0xc0, 0xaa, 0x83, 0x79, + 0x7f, 0xe5, 0xc1, 0x8c, 0x29, 0x26, 0x33, 0xae, 0xcd, 0x63, 0xd5, 0xec, 0xe0, 0x1d, 0xc2, 0xbf, + 0x11, 0x2d, 0x45, 0x64, 0x26, 0x0a, 0x35, 0x40, 0xa2, 0x5b, 0x16, 0x8c, 0x35, 0x12, 0xdd, 0xb5, + 0xd7, 0x85, 0xe1, 0x92, 0x5d, 0x9b, 0x18, 0x6f, 0xa8, 0x4e, 0xed, 0xfa, 0x31, 0xe7, 0x3b, 0x50, + 0x68, 0x5b, 0x76, 0x57, 0x75, 0x15, 0x61, 0x3c, 0xf3, 0x7e, 0x27, 0xf6, 0xab, 0xb3, 0xe5, 0xfc, + 0x16, 0xc5, 0x0a, 0xc3, 0xc9, 0xb7, 0x83, 0x9f, 0x68, 0x43, 0x84, 0xe6, 0x6b, 0x34, 0x92, 0xbe, + 0xf1, 0xd2, 0xcd, 0x1a, 0x13, 0x91, 0x1b, 0x90, 0xa4, 0x05, 0xb3, 0x53, 0x5a, 0xa0, 0x3b, 0x7e, + 0xc9, 0xe2, 0x5b, 0xe6, 0x52, 0xd0, 0x0e, 0x14, 0x34, 0x02, 0xd1, 0xcd, 0x0e, 0xef, 0xf1, 0x5e, + 0xa7, 0x72, 0x97, 0x27, 0xc8, 0x15, 0x2e, 0x56, 0xb4, 0xf2, 0x04, 0x33, 0xeb, 0x03, 0x37, 0x21, + 0xdd, 0x56, 0xbb, 0xba, 0xa1, 0x63, 0xa7, 0x74, 0x83, 0xca, 0x79, 0x67, 0xaa, 0x3d, 0x0f, 0xdf, + 0x13, 0x8a, 0x10, 0x2e, 0x84, 0x78, 0x66, 0x4d, 0x01, 0x03, 0x72, 0x7c, 0x37, 0x47, 0xcd, 0x5a, + 0xdc, 0x13, 0x86, 0xee, 0x0c, 0xa9, 0x59, 0xf3, 0x2f, 0x0d, 0xdd, 0x06, 0x78, 0xa1, 0xe3, 0x13, + 0xe5, 0x79, 0x1f, 0xdb, 0x83, 0x52, 0x29, 0xd8, 0xba, 0x21, 0xf0, 0xcf, 0x08, 0x18, 0xbd, 0x0b, + 0x19, 0x0d, 0xf7, 0xb0, 0xa9, 0x39, 0x4d, 0xb3, 0xf4, 0x0a, 0xad, 0x45, 0xaf, 0x9d, 0x9f, 0x2d, + 0x67, 0xaa, 0x02, 0xc8, 0xbd, 0xa8, 0x4f, 0x85, 0xbe, 0x80, 0x1c, 0xfb, 0xc0, 0x5a, 0xd3, 0xdc, + 0x18, 0x94, 0x16, 0xe9, 0xa2, 0xef, 0xcf, 0x78, 0x28, 0x7e, 0x63, 0xd4, 0xbb, 0x83, 0xaa, 0x06, + 0xa4, 0xc9, 0x21, 0xd9, 0xe8, 0x8f, 0x21, 0x27, 0xf4, 0xf8, 0x91, 0x75, 0xe4, 0x94, 0xbe, 0x31, + 0xf5, 0x82, 0x68, 0x78, 0xac, 0x5d, 0x9f, 0x55, 0x78, 0xa9, 0xa0, 0x34, 0xf4, 0x39, 0xe4, 0xbd, + 0xab, 0x70, 0xab, 0xe7, 0x3a, 0xa5, 0x57, 0xa7, 0xf6, 0x37, 0x46, 0xcc, 0x90, 0xf3, 0x36, 0x7b, + 0xf4, 0xee, 0x2c, 0xf0, 0x85, 0x6e, 0x41, 0x46, 0xb3, 0xad, 0x1e, 0x8b, 0x16, 0xaf, 0xad, 0x44, + 0x56, 0x63, 0x5e, 0x77, 0xce, 0xb6, 0x7a, 0x34, 0x0c, 0x28, 0x50, 0xb0, 0x71, 0xcf, 0x50, 0x5b, + 0xb8, 0x4b, 0xe2, 0x98, 0xd5, 0x2e, 0x2d, 0xd1, 0xd1, 0xd7, 0x67, 0xde, 0x48, 0x8f, 0x59, 0x28, + 0x66, 0x40, 0x5e, 0xb3, 0x8d, 0x0e, 0x01, 0xd4, 0xbe, 0xa6, 0xbb, 0x4a, 0xd7, 0xd2, 0x70, 0x69, + 0x79, 0xea, 0xeb, 0x95, 0x61, 0xe1, 0x15, 0xc2, 0xb8, 0x6b, 0x69, 0xd8, 0xbb, 0x6d, 0x15, 0x00, + 0xf4, 0x2e, 0x64, 0xe9, 0xd2, 0xbe, 0xb0, 0x8e, 0x88, 0x6e, 0xae, 0xd0, 0xc5, 0xcd, 0xf3, 0xb3, + 0xcc, 0x54, 0x6d, 0xab, 0xf7, 0xc8, 0x3a, 0xa2, 0x1a, 0xc3, 0xff, 0xd4, 0x90, 0x03, 0xb9, 0x4e, + 0x4b, 0xf1, 0x1d, 0xe7, 0x2d, 0x7a, 0x8a, 0x1f, 0xcf, 0x38, 0x97, 0x87, 0x9b, 0x63, 0x5c, 0xe9, + 0x35, 0x11, 0x01, 0x1e, 0x6e, 0x0a, 0x98, 0x23, 0x67, 0x3b, 0x2d, 0xef, 0x83, 0x54, 0x84, 0xac, + 0x05, 0xcc, 0x0d, 0xa0, 0x1c, 0xac, 0x08, 0x19, 0x86, 0x99, 0x40, 0x03, 0x78, 0xaf, 0x58, 0xa1, + 0xd5, 0x14, 0x3b, 0xb3, 0xdb, 0xb3, 0x47, 0xf8, 0x02, 0xe3, 0xae, 0x38, 0xcd, 0x36, 0x3d, 0xd8, + 0x16, 0xe4, 0xac, 0xbe, 0x7b, 0x64, 0xf5, 0x4d, 0x4d, 0x69, 0x3f, 0x73, 0x4a, 0xaf, 0xd3, 0xd5, + 0x5e, 0xa8, 0xaf, 0xe7, 0xad, 0xae, 0xc9, 0x05, 0x6d, 0x3d, 0x76, 0xe4, 0xac, 0x90, 0xba, 0xf5, + 0xcc, 0x41, 0x3f, 0x86, 0xac, 0x6e, 0xfa, 0x63, 0xdc, 0xb9, 0xf8, 0x18, 0x48, 0x54, 0x1e, 0x75, + 0xd3, 0x1b, 0x02, 0xb8, 0x4c, 0x32, 0xc2, 0xdb, 0x50, 0xb0, 0xda, 0x6d, 0x43, 0x37, 0xb1, 0x62, + 0x63, 0xd5, 0xb1, 0xcc, 0xd2, 0x1b, 0x81, 0x1d, 0xcc, 0x73, 0x9c, 0x4c, 0x51, 0xa8, 0x0c, 0x19, + 0x17, 0x77, 0x7b, 0x96, 0xad, 0xda, 0x83, 0xd2, 0x9b, 0xc1, 0x4b, 0x6a, 0x0f, 0x8c, 0x8e, 0x60, + 0xb1, 0x6f, 0xe2, 0xd3, 0x9e, 0xe5, 0x60, 0x4d, 0x19, 0xc9, 0x2d, 0x57, 0xa9, 0x8f, 0xbb, 0xc3, + 0x27, 0x75, 0xf3, 0x50, 0x50, 0x8e, 0x4d, 0x32, 0x6f, 0xf6, 0xc7, 0xa2, 0x35, 0xf4, 0x01, 0x2c, + 0xe8, 0x8e, 0x12, 0xcc, 0xda, 0x15, 0xe2, 0xeb, 0x4a, 0x6f, 0x05, 0xa6, 0x84, 0x74, 0x67, 0x38, + 0xe3, 0x47, 0x3f, 0x82, 0xe2, 0x70, 0xd7, 0xe7, 0xee, 0x15, 0xba, 0x3e, 0x72, 0x21, 0xdc, 0xe1, + 0x42, 0x3f, 0x8d, 0xc0, 0xca, 0x4b, 0x9a, 0xab, 0x4e, 0xe9, 0xed, 0xa9, 0xd7, 0xd5, 0x33, 0x74, + 0x57, 0x5f, 0x9b, 0xd6, 0x5d, 0x75, 0xd0, 0x1a, 0x4d, 0xe9, 0xd9, 0x5d, 0x8c, 0xa2, 0x1a, 0x86, + 0x72, 0x34, 0x28, 0x7d, 0x33, 0x58, 0xf6, 0x7b, 0xd8, 0x8a, 0x61, 0xd0, 0x4b, 0xaa, 0x92, 0x89, + 0x4f, 0xc4, 0x19, 0xb5, 0x68, 0xba, 0x21, 0xcc, 0xfe, 0x1d, 0x6a, 0xf6, 0xa2, 0x14, 0x58, 0x68, + 0xe0, 0x93, 0x60, 0x52, 0xc2, 0x3c, 0xc0, 0x82, 0x39, 0x0a, 0xd5, 0x16, 0x7f, 0x19, 0x81, 0xf9, + 0x91, 0x04, 0x06, 0xfd, 0x08, 0x52, 0xa6, 0xa5, 0x05, 0x5e, 0x6d, 0xd4, 0xb8, 0xe8, 0x64, 0xc3, + 0xd2, 0xd8, 0xa3, 0x8d, 0xf7, 0x3a, 0xba, 0x7b, 0xdc, 0x3f, 0x5a, 0x6b, 0x59, 0xdd, 0x7b, 0xde, + 0x16, 0x69, 0x47, 0xfe, 0xdf, 0xf7, 0x7a, 0xcf, 0x3a, 0xf7, 0xe8, 0x5f, 0xbd, 0xa3, 0x35, 0xc6, + 0x26, 0x27, 0x89, 0xd4, 0xba, 0x86, 0xde, 0x81, 0x22, 0x3e, 0xed, 0xe9, 0x76, 0x20, 0x89, 0x8f, + 0x06, 0xdc, 0x72, 0xc1, 0x47, 0x12, 0x1b, 0xe6, 0xf7, 0xe3, 0xbf, 0x8e, 0x42, 0x71, 0x28, 0x89, + 0x20, 0x55, 0x0b, 0x6d, 0x30, 0x85, 0xaa, 0x16, 0x02, 0x99, 0x52, 0x4b, 0x05, 0xdf, 0xcb, 0xc5, + 0xae, 0xfa, 0x5e, 0x2e, 0x7c, 0xef, 0x9c, 0xb8, 0xc0, 0xbd, 0xf3, 0x87, 0x70, 0x43, 0x77, 0x14, + 0xd3, 0x32, 0xc5, 0xf5, 0x80, 0xd7, 0x27, 0x08, 0xbe, 0x41, 0xbb, 0xa6, 0x3b, 0x0d, 0xcb, 0x64, + 0x17, 0x03, 0xde, 0xaa, 0xfd, 0xe7, 0x6a, 0xa9, 0xd1, 0xe7, 0x6a, 0x5e, 0x87, 0x3d, 0x2e, 0x25, + 0x16, 0xff, 0x25, 0x02, 0x99, 0xe0, 0x8b, 0xf0, 0x68, 0xb8, 0xef, 0x37, 0x52, 0xc9, 0x5d, 0xf2, + 0xf5, 0x4d, 0x78, 0x17, 0x62, 0x17, 0xd8, 0x85, 0x5b, 0x90, 0x38, 0x1a, 0x88, 0xb2, 0x31, 0xbd, + 0x91, 0xe3, 0xa3, 0xc5, 0x37, 0x48, 0x06, 0x15, 0x3f, 0x1a, 0x88, 0x9a, 0x75, 0xf1, 0x4f, 0x20, + 0x1b, 0x48, 0x20, 0x86, 0xdb, 0x37, 0x91, 0x4b, 0xb4, 0x6f, 0x5e, 0x87, 0x24, 0x37, 0x1f, 0xa6, + 0x7b, 0x79, 0xce, 0x9d, 0x60, 0xf6, 0x92, 0xf8, 0x82, 0x18, 0x08, 0x1f, 0xfd, 0x7f, 0x62, 0x90, + 0x0b, 0x26, 0x18, 0xc4, 0xc5, 0xea, 0x66, 0xcb, 0xa6, 0xd1, 0x9d, 0x8e, 0x1e, 0xf3, 0xde, 0x01, + 0x09, 0x30, 0x49, 0x3b, 0xba, 0xba, 0xa9, 0xd0, 0x37, 0x24, 0x21, 0xfd, 0x4e, 0x77, 0x75, 0xf3, + 0x09, 0x81, 0x52, 0x12, 0xf5, 0x94, 0x93, 0xc4, 0x42, 0x24, 0xea, 0x29, 0x23, 0x59, 0xa4, 0x39, + 0xbb, 0xed, 0xd2, 0x1d, 0x8a, 0x05, 0x72, 0x71, 0xdb, 0x0d, 0xbe, 0x93, 0x4b, 0x8c, 0x79, 0x27, + 0x87, 0x4c, 0x28, 0xf8, 0x29, 0xd5, 0x89, 0x89, 0x6d, 0x7e, 0x59, 0x50, 0xb9, 0x44, 0x4e, 0xe5, + 0x7f, 0x10, 0x41, 0x22, 0xf0, 0x38, 0x41, 0x20, 0x49, 0x72, 0x5b, 0x6a, 0xeb, 0x18, 0x2b, 0x8e, + 0xfe, 0x13, 0x56, 0x97, 0x7b, 0xdb, 0x42, 0xe1, 0xfb, 0xfa, 0x4f, 0xf0, 0xe2, 0xdf, 0x45, 0x20, + 0x1f, 0x92, 0x85, 0xea, 0x50, 0xa4, 0xb3, 0x1b, 0x69, 0x4e, 0xdf, 0xf2, 0xde, 0x88, 0x13, 0xf4, + 0xd8, 0xe2, 0x39, 0x6f, 0x05, 0x50, 0x1a, 0xfa, 0x14, 0x0a, 0x4c, 0x94, 0xf7, 0xec, 0x2c, 0xac, + 0xc6, 0x39, 0x2a, 0x29, 0xfc, 0xf6, 0x2c, 0x67, 0xf9, 0x30, 0x2d, 0xd8, 0x4a, 0x5f, 0x34, 0x21, + 0x1b, 0x48, 0xec, 0x66, 0xb0, 0x9f, 0x6f, 0x43, 0xdc, 0xf3, 0x66, 0xb3, 0xf6, 0x80, 0x5d, 0xdf, + 0xc5, 0xfd, 0x3c, 0x02, 0x0b, 0xe3, 0x12, 0xac, 0x90, 0x5d, 0x32, 0x6d, 0x9b, 0xc9, 0x2e, 0x6f, + 0x07, 0x13, 0x5f, 0xa6, 0x81, 0xe2, 0xb5, 0x86, 0x9f, 0xfa, 0xbe, 0xe1, 0xd9, 0x01, 0x53, 0xc0, + 0x62, 0xc8, 0x0e, 0x48, 0x29, 0x1b, 0xb4, 0x84, 0xdf, 0xc5, 0xa0, 0x30, 0x74, 0x77, 0xf2, 0x04, + 0x92, 0x1d, 0xc3, 0x3a, 0x52, 0x0d, 0xde, 0x73, 0xfe, 0xce, 0xa5, 0xa2, 0xf4, 0xda, 0x43, 0x2a, + 0x63, 0x7b, 0x4e, 0xe6, 0xd2, 0x90, 0x03, 0xf3, 0xc1, 0x4b, 0x12, 0xf6, 0x63, 0x16, 0xb6, 0xb3, + 0xb5, 0xcb, 0x0d, 0xe1, 0xdf, 0xa2, 0x50, 0xc2, 0xed, 0x39, 0xb9, 0x68, 0x87, 0x41, 0xa8, 0x0b, + 0xc5, 0xa1, 0x9b, 0x19, 0xde, 0xd0, 0xdf, 0xbc, 0xea, 0x90, 0xb2, 0x75, 0xb2, 0x4d, 0xcb, 0x82, + 0x00, 0x60, 0xf1, 0x8f, 0xa0, 0x38, 0x34, 0x29, 0x72, 0x1e, 0x8c, 0x86, 0x47, 0xb5, 0x02, 0xf1, + 0x61, 0x8c, 0x88, 0xd4, 0xb8, 0x32, 0xc7, 0xf2, 0xf3, 0xb8, 0x03, 0xf9, 0xd0, 0x10, 0xa8, 0x00, + 0x51, 0x95, 0xbd, 0xed, 0xcb, 0xc8, 0x51, 0x95, 0xbf, 0x0a, 0x5c, 0x2c, 0x40, 0x92, 0xed, 0x6f, + 0x50, 0xbf, 0x37, 0x00, 0xd2, 0x22, 0x35, 0x2a, 0xaf, 0x42, 0xc6, 0xab, 0x33, 0x50, 0x0e, 0xd2, + 0xd5, 0xfa, 0x7e, 0x65, 0x63, 0xa7, 0x56, 0x95, 0xe6, 0x50, 0x1e, 0x32, 0x72, 0xad, 0x52, 0xa5, + 0x1d, 0x53, 0x29, 0xf2, 0x51, 0xfa, 0xcf, 0x7e, 0xbe, 0x1c, 0xe1, 0x41, 0x26, 0x29, 0xa5, 0x1e, + 0xc5, 0xd3, 0x48, 0xba, 0x56, 0xfe, 0xaf, 0x0c, 0xa0, 0xaa, 0xea, 0xaa, 0x64, 0x53, 0x2e, 0xd0, + 0x57, 0x8c, 0x4e, 0xb1, 0xa6, 0x70, 0xaf, 0x28, 0x76, 0xa5, 0x5e, 0xd1, 0xd8, 0xce, 0x61, 0xfc, + 0x2a, 0x9d, 0xc3, 0x4b, 0x35, 0x30, 0x47, 0xbb, 0x1d, 0xc9, 0x2b, 0x74, 0x3b, 0x9e, 0x40, 0x8a, + 0xe5, 0x83, 0xec, 0xc9, 0xda, 0xe4, 0x66, 0xcc, 0xe8, 0xc1, 0xf0, 0xb6, 0x95, 0x53, 0x33, 0x5d, + 0x7b, 0xe0, 0xbd, 0x66, 0x61, 0x30, 0xbf, 0x4f, 0x94, 0xbe, 0x7c, 0x9f, 0x68, 0xb4, 0x62, 0xc9, + 0x4c, 0xae, 0x58, 0x7e, 0x00, 0xdc, 0x2e, 0x44, 0xbe, 0x0f, 0x53, 0x1f, 0x76, 0x8c, 0x59, 0x0e, + 0x33, 0x02, 0x9e, 0xf0, 0xe7, 0xec, 0xc0, 0xd7, 0xe2, 0x01, 0x00, 0x2f, 0x49, 0xcc, 0xb6, 0x35, + 0x83, 0x13, 0x5f, 0x82, 0x14, 0x71, 0x8e, 0x3d, 0xcc, 0xb4, 0xd3, 0x8b, 0xaa, 0x1c, 0xc8, 0x2d, + 0xaa, 0x07, 0xb9, 0xe0, 0x16, 0x22, 0x09, 0x62, 0xcf, 0xf0, 0x80, 0x1b, 0x1e, 0xf9, 0x13, 0x3d, + 0x82, 0x84, 0x1f, 0xfb, 0x27, 0xbf, 0xaf, 0x9e, 0x78, 0x36, 0x64, 0xba, 0x32, 0x13, 0xf1, 0x51, + 0xf4, 0x41, 0x64, 0xf1, 0x7f, 0xa3, 0x90, 0x0b, 0x2e, 0x13, 0xfd, 0x10, 0x52, 0x6c, 0xa1, 0xe2, + 0x09, 0xf7, 0x27, 0x97, 0xdb, 0x2f, 0xfe, 0x21, 0xd6, 0xc9, 0x65, 0xa2, 0x06, 0xe4, 0x9d, 0xbe, + 0xfd, 0x42, 0x7f, 0xa1, 0x1a, 0x4a, 0xc7, 0x52, 0x0d, 0xba, 0x8e, 0xc2, 0xfa, 0xed, 0x49, 0x6f, + 0xa4, 0x38, 0xed, 0x43, 0x4b, 0x35, 0x44, 0x83, 0xc7, 0x09, 0xc0, 0xd0, 0x87, 0xde, 0x05, 0x16, + 0xbf, 0xfc, 0xe6, 0xf7, 0xc2, 0x88, 0xdb, 0x4d, 0xd0, 0xc9, 0x89, 0x1e, 0x38, 0x03, 0x91, 0xb0, + 0xce, 0xf5, 0x03, 0xd3, 0xb7, 0xbf, 0xe2, 0x9a, 0xc1, 0x0b, 0xeb, 0x8c, 0xae, 0x66, 0xf6, 0xbb, + 0x7e, 0x58, 0xb7, 0x7d, 0x98, 0xb6, 0xf8, 0x01, 0x24, 0xb9, 0xac, 0x37, 0x42, 0x1e, 0x69, 0xdc, + 0xe0, 0x14, 0x1f, 0x74, 0x94, 0xbe, 0xcb, 0x2b, 0xff, 0x2e, 0x07, 0x85, 0x83, 0x41, 0x2f, 0xe8, + 0xe2, 0x2e, 0x75, 0xd7, 0x33, 0xee, 0x46, 0x27, 0x7a, 0xf1, 0x1b, 0x9d, 0x29, 0xbf, 0x0b, 0x62, + 0x8a, 0x1e, 0x9f, 0xa2, 0xe8, 0x55, 0x88, 0xd3, 0x5f, 0x6d, 0x24, 0xe8, 0xb9, 0x4e, 0xf2, 0xac, + 0xe1, 0xd5, 0xae, 0x05, 0x7e, 0xb8, 0x41, 0xb9, 0xd1, 0xf7, 0x20, 0x47, 0x0f, 0xa5, 0x8b, 0xbb, + 0x47, 0xd8, 0x16, 0x0e, 0xed, 0xfe, 0x6c, 0xd2, 0xc8, 0xe9, 0xec, 0x52, 0x46, 0xd1, 0x0c, 0xc2, + 0x1e, 0xc4, 0x41, 0xf7, 0x21, 0xa1, 0x1a, 0x3a, 0xf5, 0x6e, 0x2f, 0xfb, 0x35, 0x10, 0x23, 0x44, + 0x9f, 0x40, 0x5e, 0xb5, 0x6d, 0x75, 0xc0, 0x7f, 0xd7, 0xa2, 0x51, 0x0f, 0xc6, 0x5d, 0xf3, 0xf9, + 0xd9, 0x72, 0xb6, 0x42, 0x90, 0xf4, 0xa7, 0x2c, 0x62, 0x23, 0xb2, 0xaa, 0x07, 0x0a, 0x5d, 0x4a, + 0x65, 0xae, 0x76, 0x29, 0x05, 0x57, 0x09, 0x2d, 0xa3, 0x51, 0x22, 0x7b, 0x85, 0x28, 0xf1, 0x63, + 0x58, 0x14, 0x4f, 0x73, 0x89, 0x40, 0xff, 0xe2, 0x32, 0xf0, 0x8b, 0xa3, 0xf2, 0xf9, 0xd9, 0x72, + 0x49, 0xf6, 0xa9, 0xfc, 0xe5, 0xb2, 0xe2, 0x8d, 0xec, 0x54, 0xc9, 0x1e, 0x8b, 0xd7, 0x02, 0xf1, + 0x22, 0x7f, 0xf9, 0x78, 0x11, 0x0e, 0xf6, 0x85, 0x2b, 0x05, 0xfb, 0xd1, 0xd8, 0x53, 0x9c, 0x1c, + 0x7b, 0x9e, 0x0e, 0xc7, 0x1e, 0x69, 0x7a, 0xe7, 0x37, 0xac, 0xc0, 0x53, 0xe2, 0xce, 0xcf, 0x62, + 0x00, 0xbe, 0x7e, 0xa3, 0x6f, 0xc3, 0xcd, 0xde, 0xf1, 0xc0, 0xd1, 0x5b, 0xaa, 0xa1, 0xd8, 0xb8, + 0x67, 0x63, 0x07, 0x9b, 0x2c, 0xbd, 0xa7, 0x4e, 0x23, 0x27, 0xdf, 0x10, 0x68, 0x39, 0x84, 0x45, + 0x1f, 0xc3, 0x0d, 0xc3, 0xea, 0x8c, 0xe3, 0x0b, 0x36, 0x37, 0xae, 0x73, 0x9a, 0x21, 0x66, 0x95, + 0x94, 0x64, 0x3d, 0xf5, 0x48, 0x37, 0xfc, 0x7e, 0xc7, 0xc7, 0x17, 0xb5, 0xcd, 0xb5, 0x4d, 0x4f, + 0x84, 0x78, 0xf9, 0xe2, 0x0b, 0x45, 0x3f, 0x1a, 0x7d, 0xa3, 0xf1, 0xd1, 0x85, 0x47, 0x98, 0xfc, + 0x54, 0xa3, 0xfc, 0x3a, 0x80, 0x3f, 0x3e, 0xbd, 0x93, 0xdf, 0xd9, 0xf1, 0xb3, 0x52, 0x7e, 0xbb, + 0x5f, 0xbe, 0xfb, 0x92, 0x2b, 0x7c, 0x80, 0xa4, 0x5c, 0xdb, 0x6d, 0x3e, 0xa9, 0x89, 0x4b, 0xfc, + 0xc5, 0xe6, 0x50, 0x38, 0x1d, 0x8d, 0x4f, 0x91, 0x19, 0xe3, 0x13, 0xbf, 0x57, 0x7f, 0x17, 0xe2, + 0xf4, 0xe7, 0x6b, 0x69, 0x88, 0xd7, 0x1a, 0x87, 0xbb, 0xd2, 0x1c, 0xca, 0x40, 0xa2, 0xb2, 0x53, + 0xaf, 0xec, 0x4b, 0x11, 0xb4, 0x00, 0xd2, 0xee, 0xe1, 0xce, 0x41, 0x5d, 0xae, 0x3d, 0xac, 0x37, + 0x1b, 0x0a, 0x25, 0x88, 0x06, 0x02, 0xcb, 0xdf, 0xc6, 0x41, 0x62, 0x5e, 0xfd, 0xaa, 0xa1, 0x65, + 0x72, 0xeb, 0xeb, 0xe5, 0x57, 0xf9, 0x61, 0x2b, 0x8c, 0x7f, 0xfd, 0x29, 0x77, 0xe2, 0x6b, 0x4a, + 0xb9, 0x93, 0x57, 0x48, 0xb9, 0x53, 0x57, 0x70, 0xa6, 0x7f, 0xe8, 0xd4, 0x38, 0xa0, 0x21, 0xbf, + 0x88, 0x02, 0x04, 0x74, 0xe3, 0xbb, 0xc1, 0x7f, 0xdf, 0x61, 0xf2, 0x9d, 0xfe, 0x50, 0x7d, 0xba, + 0x3d, 0x27, 0xfe, 0xf5, 0x87, 0x87, 0x90, 0xd6, 0x78, 0x5e, 0xc8, 0x33, 0xd4, 0xb7, 0x66, 0x4e, + 0x1f, 0xb7, 0xe7, 0x64, 0x8f, 0x19, 0x7d, 0x1c, 0xfa, 0xc9, 0xee, 0x9d, 0x99, 0x4c, 0x7f, 0x5b, + 0xfc, 0x76, 0xa0, 0x02, 0x49, 0x96, 0x00, 0x71, 0x65, 0x9b, 0xf8, 0xdb, 0xd1, 0x21, 0xd3, 0xd8, + 0x9e, 0x93, 0x39, 0x23, 0xaf, 0x65, 0x53, 0x90, 0xe8, 0x9b, 0xba, 0x65, 0xde, 0x95, 0x83, 0xaf, + 0xd6, 0x45, 0xe3, 0x96, 0x78, 0x0b, 0xfa, 0xb7, 0xea, 0x62, 0x8d, 0x3d, 0x0e, 0x3a, 0x34, 0x5f, + 0x78, 0x80, 0x08, 0x2a, 0x00, 0x70, 0xbc, 0x6e, 0x76, 0xa4, 0x28, 0xad, 0x80, 0x49, 0xbe, 0x4f, + 0xbe, 0x62, 0x77, 0x3f, 0x01, 0x69, 0xf8, 0xc7, 0xab, 0x01, 0x1f, 0x33, 0x0f, 0xf9, 0xdd, 0x27, + 0x9b, 0x9b, 0x07, 0xf5, 0xdd, 0xda, 0xfe, 0x41, 0x65, 0x77, 0x8f, 0x3d, 0x87, 0x3e, 0x20, 0xe5, + 0x73, 0xb3, 0x5e, 0x95, 0xa2, 0x77, 0x3f, 0x81, 0xe2, 0x90, 0x42, 0x10, 0x77, 0xb4, 0x77, 0xb8, + 0xb1, 0x53, 0xdf, 0x1c, 0xfb, 0xcc, 0x08, 0x65, 0x21, 0xd5, 0xdc, 0xda, 0xda, 0xa9, 0x37, 0x6a, + 0x52, 0xec, 0xee, 0xfb, 0x90, 0x0b, 0x26, 0xd7, 0x48, 0x82, 0xdc, 0xf7, 0x9b, 0x8d, 0x9a, 0xb2, + 0x55, 0xa9, 0xef, 0x1c, 0xca, 0x64, 0x06, 0x08, 0x0a, 0xdc, 0xaf, 0x08, 0x58, 0x64, 0x63, 0xf5, + 0x37, 0xff, 0xb9, 0x34, 0xf7, 0x9b, 0xf3, 0xa5, 0xc8, 0x6f, 0xcf, 0x97, 0x22, 0xbf, 0x3f, 0x5f, + 0x8a, 0xfc, 0xc7, 0xf9, 0x52, 0xe4, 0x2f, 0xbf, 0x5c, 0x9a, 0xfb, 0xed, 0x97, 0x4b, 0x73, 0xbf, + 0xff, 0x72, 0x69, 0xee, 0xfb, 0x49, 0xf6, 0x2f, 0x93, 0xfc, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x9b, 0x15, 0xd5, 0xf2, 0x04, 0x45, 0x00, 0x00, } diff --git a/pkg/sql/catalog/descpb/structured.proto b/pkg/sql/catalog/descpb/structured.proto index 1d3d8a9b1b10..5ef89019aa83 100644 --- a/pkg/sql/catalog/descpb/structured.proto +++ b/pkg/sql/catalog/descpb/structured.proto @@ -1000,6 +1000,12 @@ message TableDescriptor { // with the mutations list. repeated MutationJob mutationJobs = 27 [(gogoproto.nullable) = false]; + // The job associated with a schema change job run in the new schema changer + // (in sql/schemachanger), if one exists. Only one such job can exist at a + // time. + optional int64 new_schema_change_job_id = 45 [(gogoproto.nullable) = false, + (gogoproto.customname) = "NewSchemaChangeJobID"]; + message SequenceOpts { option (gogoproto.equal) = true; // How much to increment the sequence by when nextval() is called. diff --git a/pkg/sql/catalog/tabledesc/structured.go b/pkg/sql/catalog/tabledesc/structured.go index f94c38234c33..9259aae4d5b5 100644 --- a/pkg/sql/catalog/tabledesc/structured.go +++ b/pkg/sql/catalog/tabledesc/structured.go @@ -2027,6 +2027,17 @@ func (desc *wrapper) ValidateSelf(ctx context.Context) error { } } + // Validate that the presence of MutationJobs (from the old schema changer) + // and the presence of a NewSchemaChangeJobID are mutually exclusive. (Note + // the jobs themselves can be running simultaneously, since a resumer can + // still be running after the schema change is complete from the point of view + // of the descriptor, in both the new and old schema change jobs.) + if len(desc.MutationJobs) > 0 && desc.NewSchemaChangeJobID != 0 { + return errors.AssertionFailedf( + "invalid concurrent new-style schema change job %d and old-style schema change jobs %v", + desc.NewSchemaChangeJobID, desc.MutationJobs) + } + if err := desc.validateTableIfTesting(ctx); err != nil { return err } diff --git a/pkg/sql/catalog/tabledesc/validate_test.go b/pkg/sql/catalog/tabledesc/validate_test.go index bae4d5ad6ee5..ada1d2129c47 100644 --- a/pkg/sql/catalog/tabledesc/validate_test.go +++ b/pkg/sql/catalog/tabledesc/validate_test.go @@ -112,6 +112,7 @@ var validationMap = []struct { "Temporary": {status: thisFieldReferencesNoObjects}, "LocalityConfig": {status: iSolemnlySwearThisFieldIsValidated}, "PartitionAllBy": {status: iSolemnlySwearThisFieldIsValidated}, + "NewSchemaChangeJobID": {status: iSolemnlySwearThisFieldIsValidated}, }, }, { diff --git a/pkg/sql/conn_executor.go b/pkg/sql/conn_executor.go index d830818a6cca..099a6c9423ca 100644 --- a/pkg/sql/conn_executor.go +++ b/pkg/sql/conn_executor.go @@ -2564,44 +2564,71 @@ func (ex *connExecutor) notifyStatsRefresherOfNewTables(ctx context.Context) { // runPreCommitStages is part of the new schema changer infrastructure to // mutate descriptors prior to committing a SQL transaction. func (ex *connExecutor) runPreCommitStages(ctx context.Context) error { - if len(ex.extraTxnState.schemaChangerState.nodes) == 0 { + scs := &ex.extraTxnState.schemaChangerState + if len(scs.nodes) == 0 { return nil } executor := scexec.NewExecutor( ex.planner.txn, &ex.extraTxnState.descCollection, ex.server.cfg.Codec, - nil /* backfiller */, nil, /* jobTracker */ + nil /* backfiller */, nil /* jobTracker */, ex.server.cfg.NewSchemaChangerTestingKnobs, ) after, err := runNewSchemaChanger( - ctx, scplan.PreCommitPhase, + ctx, + scplan.PreCommitPhase, ex.extraTxnState.schemaChangerState.nodes, executor, + scs.stmts, ) if err != nil { return err } - scs := &ex.extraTxnState.schemaChangerState scs.nodes = after targetSlice := make([]*scpb.Target, len(scs.nodes)) states := make([]scpb.State, len(scs.nodes)) + // TODO(ajwerner): It may be better in the future to have the builder be + // responsible for determining this set of descriptors. As of the time of + // writing, the descriptors to be "locked," descriptors that need schema + // change jobs, and descriptors with schema change mutations all coincide. But + // there are future schema changes to be implemented in the new schema changer + // (e.g., RENAME TABLE) for which this may no longer be true. + descIDSet := catalog.MakeDescriptorIDSet() for i := range scs.nodes { targetSlice[i] = scs.nodes[i].Target states[i] = scs.nodes[i].State + descIDSet.Add(scs.nodes[i].Element().DescriptorID()) } - _, err = ex.planner.extendedEvalCtx.QueueJob(ctx, jobs.Record{ + descIDs := descIDSet.Ordered() + job, err := ex.planner.extendedEvalCtx.QueueJob(ctx, jobs.Record{ Description: "Schema change job", // TODO(ajwerner): use const - Statement: "", // TODO(ajwerner): combine all of the DDL statements together + Statement: strings.Join(scs.stmts, "; "), Username: ex.planner.User(), - DescriptorIDs: nil, // TODO(ajwerner): populate - Details: jobspb.NewSchemaChangeDetails{Targets: targetSlice}, + DescriptorIDs: descIDs, + Details: jobspb.NewSchemaChangeDetails{ + Targets: targetSlice, + }, Progress: jobspb.NewSchemaChangeProgress{States: states}, RunningStatus: "", NonCancelable: false, }) - return err + if err != nil { + return err + } + // Write the job ID to the affected descriptors. + if err := scexec.UpdateDescriptorJobIDs( + ctx, ex.planner.Txn(), &ex.extraTxnState.descCollection, descIDs, jobspb.InvalidJobID, job.ID(), + ); err != nil { + return err + } + log.Infof(ctx, "queued new schema change job %d using the new schema changer", job.ID()) + return nil } func runNewSchemaChanger( - ctx context.Context, phase scplan.Phase, nodes []*scpb.Node, executor *scexec.Executor, + ctx context.Context, + phase scplan.Phase, + nodes []*scpb.Node, + executor *scexec.Executor, + stmts []string, ) (after []*scpb.Node, _ error) { sc, err := scplan.MakePlan(nodes, scplan.Params{ ExecutionPhase: phase, @@ -2612,7 +2639,11 @@ func runNewSchemaChanger( } after = nodes for _, s := range sc.Stages { - if err := executor.ExecuteOps(ctx, s.Ops); err != nil { + if err := executor.ExecuteOps(ctx, s.Ops, + scexec.TestingKnobMetadata{ + Statements: stmts, + Phase: phase, + }); err != nil { return nil, err } after = s.After diff --git a/pkg/sql/drop_table.go b/pkg/sql/drop_table.go index b43db7f76da2..eaf81480ee89 100644 --- a/pkg/sql/drop_table.go +++ b/pkg/sql/drop_table.go @@ -25,6 +25,8 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/tabledesc" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/privilege" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" @@ -422,6 +424,16 @@ func (p *planner) initiateDropTable( return errors.Errorf("table %q is already being dropped", tableDesc.Name) } + // Exit early with an error if the table is undergoing a new-style schema + // change, before we try to get job IDs and update job statuses later. See + // createOrUpdateSchemaChangeJob. + if tableDesc.NewSchemaChangeJobID != 0 { + return pgerror.Newf(pgcode.ObjectNotInPrerequisiteState, + "cannot perform a schema change on table %q while it is undergoing a new-style schema change", + tableDesc.GetName(), + ) + } + // If the table is not interleaved , use the delayed GC mechanism to // schedule usage of the more efficient ClearRange pathway. ClearRange will // only work if the entire hierarchy of interleaved tables are dropped at diff --git a/pkg/sql/exec_util.go b/pkg/sql/exec_util.go index c2677a030621..d2a156b0259c 100644 --- a/pkg/sql/exec_util.go +++ b/pkg/sql/exec_util.go @@ -65,6 +65,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgnotice" "github.com/cockroachdb/cockroach/pkg/sql/physicalplan" "github.com/cockroachdb/cockroach/pkg/sql/querycache" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scexec" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" "github.com/cockroachdb/cockroach/pkg/sql/sessiondatapb" @@ -337,7 +338,6 @@ var experimentalUniqueWithoutIndexConstraintsMode = settings.RegisterBoolSetting false, ) -// DistSQLClusterExecMode controls the cluster default for when DistSQL is used. var experimentalUseNewSchemaChanger = settings.RegisterEnumSetting( "sql.defaults.experimental_new_schema_changer.enabled", "default value for experimental_use_new_schema_changer session setting;"+ @@ -787,6 +787,7 @@ type ExecutorConfig struct { TestingKnobs ExecutorTestingKnobs PGWireTestingKnobs *PGWireTestingKnobs SchemaChangerTestingKnobs *SchemaChangerTestingKnobs + NewSchemaChangerTestingKnobs *scexec.NewSchemaChangerTestingKnobs TypeSchemaChangerTestingKnobs *TypeSchemaChangerTestingKnobs GCJobTestingKnobs *GCJobTestingKnobs DistSQLRunTestingKnobs *execinfra.TestingKnobs diff --git a/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic b/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic index 9a620c6cce5b..710f4fd69c03 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic +++ b/pkg/sql/opt/exec/execbuilder/testdata/show_trace_nonmetamorphic @@ -39,7 +39,7 @@ WHERE message NOT LIKE '%Z/%' AND operation != 'dist sender send' ---- flow CPut /NamespaceTable/30/1/53/29/"kv"/4/1 -> 54 -flow CPut /Table/3/1/54/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:2 privileges: users: owner_proto:"root" version:1 > next_mutation_id:1 format_version:3 state:PUBLIC offline_reason:"" view_query:"" is_materialized_view:false drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"" create_as_of_time:<> temporary:false partition_all_by:false > +flow CPut /Table/3/1/54/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:2 privileges: users: owner_proto:"root" version:1 > next_mutation_id:1 format_version:3 state:PUBLIC offline_reason:"" view_query:"" is_materialized_view:false new_schema_change_job_id:0 drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"" create_as_of_time:<> temporary:false partition_all_by:false > exec stmt rows affected: 0 # We avoid using the full trace output, because that would make the @@ -65,7 +65,7 @@ WHERE message NOT LIKE '%Z/%' AND message NOT LIKE 'querying next range at%' AND tag NOT LIKE '%IndexBackfiller%' AND operation != 'dist sender send' ---- -flow Put /Table/3/1/54/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:3 privileges: users: owner_proto:"root" version:1 > mutations: interleave:<> partitioning: type:FORWARD created_explicitly:true encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > state:DELETE_ONLY direction:ADD mutation_id:1 rollback:false > next_mutation_id:2 format_version:3 state:PUBLIC offline_reason:"" view_query:"" is_materialized_view:false mutationJobs:<...> drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"" create_as_of_time:<...> temporary:false partition_all_by:false > +flow Put /Table/3/1/54/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:3 privileges: users: owner_proto:"root" version:1 > mutations: interleave:<> partitioning: type:FORWARD created_explicitly:true encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > state:DELETE_ONLY direction:ADD mutation_id:1 rollback:false > next_mutation_id:2 format_version:3 state:PUBLIC offline_reason:"" view_query:"" is_materialized_view:false mutationJobs:<...> new_schema_change_job_id:0 drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"" create_as_of_time:<...> temporary:false partition_all_by:false > exec stmt rows affected: 0 statement ok @@ -120,7 +120,7 @@ WHERE message NOT LIKE '%Z/%' AND operation != 'dist sender send' ---- flow CPut /NamespaceTable/30/1/53/29/"kv2"/4/1 -> 55 -flow CPut /Table/3/1/55/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:false default_expr:"unique_rowid()" hidden:true virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:4 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:2 privileges: users: owner_proto:"root" version:1 > next_mutation_id:1 format_version:3 state:ADD offline_reason:"" view_query:"" is_materialized_view:false drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"TABLE t.public.kv" create_as_of_time:<> temporary:false partition_all_by:false > +flow CPut /Table/3/1/55/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:false default_expr:"unique_rowid()" hidden:true virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:4 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:2 privileges: users: owner_proto:"root" version:1 > next_mutation_id:1 format_version:3 state:ADD offline_reason:"" view_query:"" is_materialized_view:false new_schema_change_job_id:0 drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"TABLE t.public.kv" create_as_of_time:<> temporary:false partition_all_by:false > exec stmt rows affected: 0 statement ok @@ -168,7 +168,7 @@ WHERE message NOT LIKE '%Z/%' AND message NOT LIKE 'querying next range at%' AND tag NOT LIKE '%IndexBackfiller%' AND operation != 'dist sender send' ---- -flow Put /Table/3/1/55/2/1 -> table: draining_names: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:false default_expr:"unique_rowid()" hidden:true virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:4 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:2 privileges: users: owner_proto:"root" version:1 > next_mutation_id:1 format_version:3 state:DROP offline_reason:"" view_query:"" is_materialized_view:false drop_time:... replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"TABLE t.public.kv" create_as_of_time:<...> temporary:false partition_all_by:false > +flow Put /Table/3/1/55/2/1 -> table: draining_names: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:false default_expr:"unique_rowid()" hidden:true virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:4 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:2 privileges: users: owner_proto:"root" version:1 > next_mutation_id:1 format_version:3 state:DROP offline_reason:"" view_query:"" is_materialized_view:false new_schema_change_job_id:0 drop_time:... replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"TABLE t.public.kv" create_as_of_time:<...> temporary:false partition_all_by:false > exec stmt rows affected: 0 statement ok @@ -202,7 +202,7 @@ WHERE message NOT LIKE '%Z/%' AND message NOT LIKE 'querying next range at%' AND tag NOT LIKE '%IndexBackfiller%' AND operation != 'dist sender send' ---- -flow Put /Table/3/1/54/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:3 privileges: users: owner_proto:"root" version:1 > mutations: interleave:<> partitioning: type:FORWARD created_explicitly:true encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > state:DELETE_AND_WRITE_ONLY direction:DROP mutation_id:2 rollback:false > next_mutation_id:3 format_version:3 state:PUBLIC offline_reason:"" view_query:"" is_materialized_view:false mutationJobs:<...> drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"" create_as_of_time:<...> temporary:false partition_all_by:false > +flow Put /Table/3/1/54/2/1 -> table: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:3 privileges: users: owner_proto:"root" version:1 > mutations: interleave:<> partitioning: type:FORWARD created_explicitly:true encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > state:DELETE_AND_WRITE_ONLY direction:DROP mutation_id:2 rollback:false > next_mutation_id:3 format_version:3 state:PUBLIC offline_reason:"" view_query:"" is_materialized_view:false mutationJobs:<...> new_schema_change_job_id:0 drop_time:0 replacement_of: > audit_mode:DISABLED drop_job_id:0 create_query:"" create_as_of_time:<...> temporary:false partition_all_by:false > exec stmt rows affected: 0 statement ok @@ -219,7 +219,7 @@ WHERE message NOT LIKE '%Z/%' AND message NOT LIKE 'querying next range at%' AND tag NOT LIKE '%IndexBackfiller%' AND operation != 'dist sender send' ---- -flow Put /Table/3/1/54/2/1 -> table: draining_names: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:3 privileges: users: owner_proto:"root" version:1 > next_mutation_id:3 format_version:3 state:DROP offline_reason:"" view_query:"" is_materialized_view:false drop_time:... replacement_of: > audit_mode:DISABLED drop_job_id:0 gc_mutations: create_query:"" create_as_of_time:<...> temporary:false partition_all_by:false > +flow Put /Table/3/1/54/2/1 -> table: draining_names: parent_id:53 unexposed_parent_schema_id:29 columns: TypeMeta: > nullable:false hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > columns: TypeMeta: > nullable:true hidden:false virtual:false pg_attribute_num:0 alter_column_type_in_progress:false system_column_kind:NONE > next_column_id:3 families: next_family_id:1 primary_index: interleave:<> partitioning: type:FORWARD created_explicitly:false encoding_type:0 sharded: disabled:false geo_config:<> predicate:"" > next_index_id:3 privileges: users: owner_proto:"root" version:1 > next_mutation_id:3 format_version:3 state:DROP offline_reason:"" view_query:"" is_materialized_view:false new_schema_change_job_id:0 drop_time:... replacement_of: > audit_mode:DISABLED drop_job_id:0 gc_mutations: create_query:"" create_as_of_time:<...> temporary:false partition_all_by:false > exec stmt rows affected: 0 # Check that session tracing does not inhibit the fast path for inserts & diff --git a/pkg/sql/schema_change_plan_node.go b/pkg/sql/schema_change_plan_node.go index 27a516e49c9c..3e87e92e7d07 100644 --- a/pkg/sql/schema_change_plan_node.go +++ b/pkg/sql/schema_change_plan_node.go @@ -13,12 +13,19 @@ package sql import ( "context" + "github.com/cockroachdb/cockroach/pkg/base" + "github.com/cockroachdb/cockroach/pkg/kv" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/descs" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scbuild" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scexec" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scpb" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" + "github.com/cockroachdb/cockroach/pkg/util/log" + "github.com/cockroachdb/cockroach/pkg/util/retry" + "github.com/cockroachdb/errors" ) // SchemaChange provides the planNode for the new schema changer. @@ -29,11 +36,39 @@ func (p *planner) SchemaChange(ctx context.Context, stmt tree.Statement) (planNo (mode == sessiondata.UseNewSchemaChangerOn && !p.extendedEvalCtx.TxnImplicit) { return nil, false, nil } + scs := p.extendedEvalCtx.SchemaChangerState + scs.stmts = append(scs.stmts, p.stmt.SQL) b := scbuild.NewBuilder(p, p.SemaCtx(), p.EvalContext()) - updated, err := b.Build(ctx, p.extendedEvalCtx.SchemaChangerState.nodes, stmt) + updated, err := b.Build(ctx, scs.nodes, stmt) if scbuild.HasNotImplemented(err) && mode == sessiondata.UseNewSchemaChangerOn { return nil, false, nil } + // If the schema change needs to lock descriptors that are currently + // undergoing other schema changes, wait for them to finish, and then restart + // the transaction. + if concurrentErr := (*scbuild.ConcurrentSchemaChangeError)(nil); errors.As(err, &concurrentErr) { + log.Infof(ctx, + "schema change waiting for concurrent schema changes on descriptor %d", + concurrentErr.DescriptorID()) + + p.Descriptors().ReleaseLeases(ctx) + + if knobs := p.ExecCfg().NewSchemaChangerTestingKnobs; knobs != nil && + knobs.BeforeWaitingForConcurrentSchemaChanges != nil { + knobs.BeforeWaitingForConcurrentSchemaChanges(scs.stmts) + } + + if err := p.waitForDescriptorSchemaChanges(ctx, concurrentErr.DescriptorID()); err != nil { + return nil, false, err + } + log.Infof(ctx, + "done waiting for concurrent schema changes on descriptor %d, restarting transaction", + concurrentErr.DescriptorID()) + + p.txn.ManualRestart(ctx, p.ExecCfg().Clock.Now()) + retryErr := p.txn.PrepareRetryableError(ctx, concurrentErr.Error()) + return nil, false, retryErr + } if err != nil { return nil, false, err } @@ -42,6 +77,36 @@ func (p *planner) SchemaChange(ctx context.Context, stmt tree.Statement) (planNo }, true, nil } +func (p *planner) waitForDescriptorSchemaChanges(ctx context.Context, id descpb.ID) error { + for r := retry.StartWithCtx(ctx, base.DefaultRetryOptions()); r.Next(); { + now := p.ExecCfg().Clock.Now() + blocked := false + if err := descs.Txn( + ctx, p.ExecCfg().Settings, p.LeaseMgr(), p.ExecCfg().InternalExecutor, p.ExecCfg().DB, + func(ctx context.Context, txn *kv.Txn, descriptors *descs.Collection) error { + txn.SetFixedTimestamp(ctx, now) + table, err := descriptors.GetImmutableTableByID(ctx, txn, id, + tree.ObjectLookupFlags{ + CommonLookupFlags: tree.CommonLookupFlags{ + Required: true, + AvoidCached: true, + }, + }) + if err != nil { + return err + } + blocked = scbuild.HasConcurrentSchemaChanges(table) + return nil + }); err != nil { + return err + } + if !blocked { + break + } + } + return nil +} + // schemaChangePlanNode is the planNode utilized by the new schema changer to // perform all schema changes, unified in the new schema changer. type schemaChangePlanNode struct { @@ -54,15 +119,16 @@ type schemaChangePlanNode struct { } func (s *schemaChangePlanNode) startExec(params runParams) error { - executor := scexec.NewExecutor(params.p.txn, params.p.Descriptors(), params.p.EvalContext().Codec, - nil /* backfiller */, nil /* jobTracker */) + p := params.p + scs := p.extendedEvalCtx.SchemaChangerState + executor := scexec.NewExecutor(p.txn, p.Descriptors(), p.EvalContext().Codec, + nil /* backfiller */, nil /* jobTracker */, p.ExecCfg().NewSchemaChangerTestingKnobs) after, err := runNewSchemaChanger( - params.ctx, scplan.StatementPhase, s.plannedState, executor, + params.ctx, scplan.StatementPhase, s.plannedState, executor, scs.stmts, ) if err != nil { return err } - scs := params.p.extendedEvalCtx.SchemaChangerState scs.nodes = after return nil } diff --git a/pkg/sql/schema_changer_state.go b/pkg/sql/schema_changer_state.go index 462c921080d3..6a93da2345d2 100644 --- a/pkg/sql/schema_changer_state.go +++ b/pkg/sql/schema_changer_state.go @@ -19,4 +19,8 @@ import ( type SchemaChangerState struct { mode sessiondata.NewSchemaChangerMode nodes []*scpb.Node + // stmts contains the SQL statements involved in the schema change. This is + // the bare minimum of statement information we need for testing, but in the + // future we may want sql.Statement or something. + stmts []string } diff --git a/pkg/sql/schemachanger/BUILD.bazel b/pkg/sql/schemachanger/BUILD.bazel new file mode 100644 index 000000000000..7150b2c0db7d --- /dev/null +++ b/pkg/sql/schemachanger/BUILD.bazel @@ -0,0 +1,37 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "schemachanger_test", + srcs = [ + "main_test.go", + "schemachanger_test.go", + ], + deps = [ + "//pkg/base", + "//pkg/jobs", + "//pkg/jobs/jobspb", + "//pkg/keys", + "//pkg/kv", + "//pkg/security", + "//pkg/security/securitytest", + "//pkg/server", + "//pkg/sql", + "//pkg/sql/catalog/catalogkv", + "//pkg/sql/catalog/descpb", + "//pkg/sql/schemachanger/scexec", + "//pkg/sql/schemachanger/scop", + "//pkg/sql/schemachanger/scplan", + "//pkg/sql/sqltestutils", + "//pkg/sql/tests", + "//pkg/testutils", + "//pkg/testutils/serverutils", + "//pkg/testutils/sqlutils", + "//pkg/testutils/testcluster", + "//pkg/util/ctxgroup", + "//pkg/util/leaktest", + "//pkg/util/randutil", + "@com_github_cockroachdb_errors//:errors", + "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", + ], +) diff --git a/pkg/sql/schemachanger/main_test.go b/pkg/sql/schemachanger/main_test.go new file mode 100644 index 000000000000..d8d73e6d012c --- /dev/null +++ b/pkg/sql/schemachanger/main_test.go @@ -0,0 +1,33 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package schemachanger_test + +import ( + "os" + "testing" + + "github.com/cockroachdb/cockroach/pkg/security" + "github.com/cockroachdb/cockroach/pkg/security/securitytest" + "github.com/cockroachdb/cockroach/pkg/server" + "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" + "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" + "github.com/cockroachdb/cockroach/pkg/util/randutil" +) + +func TestMain(m *testing.M) { + security.SetAssetLoader(securitytest.EmbeddedAssets) + randutil.SeedForTests() + serverutils.InitTestServerFactory(server.TestServerFactory) + serverutils.InitTestClusterFactory(testcluster.TestClusterFactory) + os.Exit(m.Run()) +} + +//go:generate ../../util/leaktest/add-leaktest.sh *_test.go diff --git a/pkg/sql/schemachanger/scbuild/builder.go b/pkg/sql/schemachanger/scbuild/builder.go index bb8688a39a7d..4abd80df41f1 100644 --- a/pkg/sql/schemachanger/scbuild/builder.go +++ b/pkg/sql/schemachanger/scbuild/builder.go @@ -81,6 +81,23 @@ func (e *notImplementedError) Error() string { return buf.String() } +// ConcurrentSchemaChangeError indicates that building the schema change plan +// is not currently possible because there are other concurrent schema changes +// on one of the descriptors. +type ConcurrentSchemaChangeError struct { + descID descpb.ID +} + +func (e *ConcurrentSchemaChangeError) Error() string { + return fmt.Sprintf("descriptor %d is undergoing another schema change", e.descID) +} + +// DescriptorID is the ID of the descriptor undergoing concurrent schema +// changes. +func (e *ConcurrentSchemaChangeError) DescriptorID() descpb.ID { + return e.descID +} + // NewBuilder creates a new Builder. func NewBuilder( res resolver.SchemaResolver, semaCtx *tree.SemaContext, evalCtx *tree.EvalContext, @@ -130,8 +147,7 @@ func (b *Builder) AlterTable( // Resolve the table. tn := n.Table.ToTableName() - table, err := resolver.ResolveExistingTableObject(ctx, b.res, &tn, - tree.ObjectLookupFlagsWithRequired()) + table, err := b.getLockedTableDescriptor(ctx, &tn) if err != nil { if errors.Is(err, catalog.ErrDescriptorNotFound) && n.IfExists { return nodes, nil @@ -437,9 +453,7 @@ func (b *Builder) maybeAddSequenceReferenceDependencies( } tn = parsedSeqName.ToTableName() } - - seqDesc, err := resolver.ResolveExistingTableObject(ctx, b.res, &tn, - tree.ObjectLookupFlagsWithRequired()) + seqDesc, err := b.getTableDescriptor(ctx, &tn) if err != nil { return err } @@ -671,6 +685,49 @@ func (b *Builder) addNode(dir scpb.Target_Direction, elem scpb.Element) { }) } +// getLockedTableDescriptor returns a table descriptor guaranteed to be "locked" +// (i.e., with no other concurrent schema changes), or else a +// ConcurrentSchemaChangeError if the table descriptor is not in the required +// state. +func (b *Builder) getLockedTableDescriptor( + ctx context.Context, tn *tree.TableName, +) (catalog.TableDescriptor, error) { + table, err := b.getTableDescriptor(ctx, tn) + if err != nil { + return nil, err + } + if HasConcurrentSchemaChanges(table) { + return nil, &ConcurrentSchemaChangeError{descID: table.GetID()} + } + return table, nil +} + +func (b *Builder) getTableDescriptor( + ctx context.Context, tn *tree.TableName, +) (catalog.TableDescriptor, error) { + // This will return an error for dropped and offline tables, but it's possible + // that later iterations of the builder will want to handle those cases + // in a different way. + return resolver.ResolveExistingTableObject(ctx, b.res, tn, + tree.ObjectLookupFlags{ + CommonLookupFlags: tree.CommonLookupFlags{ + Required: true, + AvoidCached: true, + }, + }, + ) +} + +// HasConcurrentSchemaChanges returns whether the table descriptor is undergoing +// concurrent schema changes. +func HasConcurrentSchemaChanges(table catalog.TableDescriptor) bool { + // TODO(ajwerner): For now we simply check for the absence of mutations. Once + // we start implementing schema changes with ops to be executed during + // statement execution, we'll have to take into account mutations that were + // written in this transaction. + return len(table.GetMutations()) > 0 +} + // minimumTypeUsageVersions defines the minimum version needed for a new // data type. var minimumTypeUsageVersions = map[types.Family]clusterversion.Key{ diff --git a/pkg/sql/schemachanger/scexec/BUILD.bazel b/pkg/sql/schemachanger/scexec/BUILD.bazel index bf91b87febf9..89d0a7f69271 100644 --- a/pkg/sql/schemachanger/scexec/BUILD.bazel +++ b/pkg/sql/schemachanger/scexec/BUILD.bazel @@ -19,6 +19,7 @@ go_library( "//pkg/sql/schemachanger/scexec/descriptorutils", "//pkg/sql/schemachanger/scexec/scmutationexec", "//pkg/sql/schemachanger/scop", + "//pkg/sql/schemachanger/scplan", "//pkg/sql/sem/tree", "//pkg/util/log", "@com_github_cockroachdb_errors//:errors", diff --git a/pkg/sql/schemachanger/scexec/executor.go b/pkg/sql/schemachanger/scexec/executor.go index 845492702d7f..21c1ecd7b5e3 100644 --- a/pkg/sql/schemachanger/scexec/executor.go +++ b/pkg/sql/schemachanger/scexec/executor.go @@ -14,6 +14,7 @@ import ( "context" "time" + "github.com/cockroachdb/cockroach/pkg/jobs/jobspb" "github.com/cockroachdb/cockroach/pkg/keys" "github.com/cockroachdb/cockroach/pkg/kv" "github.com/cockroachdb/cockroach/pkg/roachpb" @@ -23,6 +24,7 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scexec/descriptorutils" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scexec/scmutationexec" "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scop" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan" "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" "github.com/cockroachdb/cockroach/pkg/util/log" "github.com/cockroachdb/errors" @@ -36,6 +38,7 @@ type Executor struct { codec keys.SQLCodec indexBackfiller IndexBackfiller jobTracker JobProgressTracker + testingKnobs *NewSchemaChangerTestingKnobs } // NewExecutor creates a new Executor. @@ -45,6 +48,7 @@ func NewExecutor( codec keys.SQLCodec, backfiller IndexBackfiller, tracker JobProgressTracker, + testingKnobs *NewSchemaChangerTestingKnobs, ) *Executor { return &Executor{ txn: txn, @@ -52,21 +56,64 @@ func NewExecutor( codec: codec, indexBackfiller: backfiller, jobTracker: tracker, + testingKnobs: testingKnobs, } } +// NewSchemaChangerTestingKnobs are testing knobs for the executor. +type NewSchemaChangerTestingKnobs struct { + // BeforeStage is called before ops passed to the executor are executed. + // Errors returned are injected into the executor. + BeforeStage func(ops scop.Ops, m TestingKnobMetadata) error + // AfterStage is called after ops passed to the executor are successfully + // executed. Errors returned are injected into the executor. + AfterStage func(ops scop.Ops, m TestingKnobMetadata) error + // BeforeWaitingForConcurrentSchemaChanges is called at the start of waiting + // for concurrent schema changes to finish. + BeforeWaitingForConcurrentSchemaChanges func(stmts []string) +} + +// ModuleTestingKnobs is part of the base.ModuleTestingKnobs interface. +func (*NewSchemaChangerTestingKnobs) ModuleTestingKnobs() {} + +// TestingKnobMetadata holds additional information about the execution of the +// schema change that is used by the testing knobs. +type TestingKnobMetadata struct { + Statements []string + Phase scplan.Phase +} + // ExecuteOps executes the provided ops. The ops must all be of the same type. -func (ex *Executor) ExecuteOps(ctx context.Context, toExecute scop.Ops) error { +func (ex *Executor) ExecuteOps( + ctx context.Context, toExecute scop.Ops, m TestingKnobMetadata, +) error { + log.Infof(ctx, "executing %d ops of type %s", len(toExecute.Slice()), toExecute.Type().String()) + + if ex.testingKnobs != nil && ex.testingKnobs.BeforeStage != nil { + if err := ex.testingKnobs.BeforeStage(toExecute, m); err != nil { + return err + } + } + var err error switch typ := toExecute.Type(); typ { case scop.MutationType: - return ex.executeDescriptorMutationOps(ctx, toExecute.Slice()) + err = ex.executeDescriptorMutationOps(ctx, toExecute.Slice()) case scop.BackfillType: - return ex.executeBackfillOps(ctx, toExecute.Slice()) + err = ex.executeBackfillOps(ctx, toExecute.Slice()) case scop.ValidationType: - return ex.executeValidationOps(ctx, toExecute.Slice()) + err = ex.executeValidationOps(ctx, toExecute.Slice()) default: - return errors.AssertionFailedf("unknown ops type %d", typ) + err = errors.AssertionFailedf("unknown ops type %d", typ) + } + if err != nil { + return err + } + if ex.testingKnobs != nil && ex.testingKnobs.AfterStage != nil { + if err := ex.testingKnobs.AfterStage(toExecute, m); err != nil { + return err + } } + return nil } func (ex *Executor) executeValidationOps(ctx context.Context, execute []scop.Op) error { @@ -199,3 +246,31 @@ func (ex *Executor) executeDescriptorMutationOps(ctx context.Context, ops []scop } return nil } + +func UpdateDescriptorJobIDs( + ctx context.Context, + txn *kv.Txn, + descriptors *descs.Collection, + descIDs []descpb.ID, + expectedID jobspb.JobID, + newID jobspb.JobID, +) error { + b := txn.NewBatch() + for _, id := range descIDs { + // Currently all "locking" schema changes are on tables. This will probably + // need to be expanded at least to types. + table, err := descriptors.GetMutableTableByID(ctx, txn, id, tree.ObjectLookupFlagsWithRequired()) + if err != nil { + return err + } + if oldID := jobspb.JobID(table.NewSchemaChangeJobID); oldID != expectedID { + return errors.AssertionFailedf( + "unexpected schema change job ID %d on table %d, expected %d", oldID, table.GetID(), expectedID) + } + table.NewSchemaChangeJobID = int64(newID) + if err := descriptors.WriteDescToBatch(ctx, true /* kvTrace */, table, b); err != nil { + return err + } + } + return txn.Run(ctx, b) +} diff --git a/pkg/sql/schemachanger/scexec/executor_external_test.go b/pkg/sql/schemachanger/scexec/executor_external_test.go index 67aba6af8414..27e0635d3f18 100644 --- a/pkg/sql/schemachanger/scexec/executor_external_test.go +++ b/pkg/sql/schemachanger/scexec/executor_external_test.go @@ -128,11 +128,11 @@ CREATE TABLE db.t ( require.NoError(t, ti.txn(ctx, func( ctx context.Context, txn *kv.Txn, descriptors *descs.Collection, ) error { - ex := scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), nil, nil) + ex := scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), nil, nil, nil) _, orig, err := descriptors.GetImmutableTableByName(ctx, txn, &tn, immFlags) require.NoError(t, err) require.Equal(t, c.orig(), orig) - require.NoError(t, ex.ExecuteOps(ctx, c.ops())) + require.NoError(t, ex.ExecuteOps(ctx, c.ops(), scexec.TestingKnobMetadata{})) _, after, err := descriptors.GetImmutableTableByName(ctx, txn, &tn, immFlags) require.NoError(t, err) require.Equal(t, c.exp(), after) @@ -312,8 +312,9 @@ func TestSchemaChanger(t *testing.T) { ti.lm.Codec(), noopBackfiller{}, nil, + nil, ) - require.NoError(t, exec.ExecuteOps(ctx, s.Ops)) + require.NoError(t, exec.ExecuteOps(ctx, s.Ops, scexec.TestingKnobMetadata{})) ts = s.After } } @@ -328,8 +329,8 @@ func TestSchemaChanger(t *testing.T) { }) require.NoError(t, err) for _, s := range sc.Stages { - exec := scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), noopBackfiller{}, nil) - require.NoError(t, exec.ExecuteOps(ctx, s.Ops)) + exec := scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), noopBackfiller{}, nil, nil) + require.NoError(t, exec.ExecuteOps(ctx, s.Ops, scexec.TestingKnobMetadata{})) after = s.After } return nil @@ -399,7 +400,8 @@ func TestSchemaChanger(t *testing.T) { }) require.NoError(t, err) for _, s := range sc.Stages { - require.NoError(t, scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), noopBackfiller{}, nil).ExecuteOps(ctx, s.Ops)) + require.NoError(t, scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), noopBackfiller{}, nil, nil). + ExecuteOps(ctx, s.Ops, scexec.TestingKnobMetadata{})) ts = s.After } } @@ -413,8 +415,8 @@ func TestSchemaChanger(t *testing.T) { }) require.NoError(t, err) for _, s := range sc.Stages { - exec := scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), noopBackfiller{}, nil) - require.NoError(t, exec.ExecuteOps(ctx, s.Ops)) + exec := scexec.NewExecutor(txn, descriptors, ti.lm.Codec(), noopBackfiller{}, nil, nil) + require.NoError(t, exec.ExecuteOps(ctx, s.Ops, scexec.TestingKnobMetadata{})) } return nil })) diff --git a/pkg/sql/schemachanger/schemachanger_test.go b/pkg/sql/schemachanger/schemachanger_test.go new file mode 100644 index 000000000000..38ad20575022 --- /dev/null +++ b/pkg/sql/schemachanger/schemachanger_test.go @@ -0,0 +1,417 @@ +// Copyright 2021 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package schemachanger_test + +import ( + "context" + gosql "database/sql" + "fmt" + "sync" + "testing" + + "github.com/cockroachdb/cockroach/pkg/base" + "github.com/cockroachdb/cockroach/pkg/jobs" + "github.com/cockroachdb/cockroach/pkg/jobs/jobspb" + "github.com/cockroachdb/cockroach/pkg/keys" + "github.com/cockroachdb/cockroach/pkg/kv" + "github.com/cockroachdb/cockroach/pkg/sql" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/catalogkv" + "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scexec" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scop" + "github.com/cockroachdb/cockroach/pkg/sql/schemachanger/scplan" + "github.com/cockroachdb/cockroach/pkg/sql/sqltestutils" + "github.com/cockroachdb/cockroach/pkg/sql/tests" + "github.com/cockroachdb/cockroach/pkg/testutils" + "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" + "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" + "github.com/cockroachdb/cockroach/pkg/util/ctxgroup" + "github.com/cockroachdb/cockroach/pkg/util/leaktest" + "github.com/cockroachdb/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSchemaChangeWaitsForOtherSchemaChanges(t *testing.T) { + defer leaktest.AfterTest(t)() + defer sqltestutils.SetTestJobsAdoptInterval()() + + t.Run("wait for old-style schema changes", func(t *testing.T) { + // This test starts an old-style schema change job (job 1), and then starts + // another old-style schema change job (job 2) and a new-style schema change + // job (job 3) while job 1 is backfilling. Job 1 is resumed after job 2 + // has started running. + ctx := context.Background() + + var job1Backfill sync.Once + var job2Resume sync.Once + var job3Wait sync.Once + // Closed when we enter the RunBeforeBackfill knob of job 1. + job1BackfillNotification := make(chan struct{}) + // Closed when we're ready to continue with job 1. + job1ContinueNotification := make(chan struct{}) + // Closed when job 2 starts. + job2ResumeNotification := make(chan struct{}) + // Closed when job 3 starts waiting for concurrent schema changes to finish. + job3WaitNotification := make(chan struct{}) + var job1ID jobspb.JobID + + var s serverutils.TestServerInterface + var kvDB *kv.DB + params, _ := tests.CreateTestServerParams() + params.Knobs = base.TestingKnobs{ + SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ + RunBeforeResume: func(jobID jobspb.JobID) error { + // Only block in job 2. + if job1ID == 0 || jobID == job1ID { + job1ID = jobID + return nil + } + job2Resume.Do(func() { + close(job2ResumeNotification) + }) + return nil + }, + RunBeforeBackfill: func() error { + job1Backfill.Do(func() { + close(job1BackfillNotification) + <-job1ContinueNotification + }) + return nil + }, + }, + SQLNewSchemaChanger: &scexec.NewSchemaChangerTestingKnobs{ + BeforeStage: func(_ scop.Ops, m scexec.TestingKnobMetadata) error { + // Assert that when job 3 is running, there are no mutations other + // than the ones associated with this schema change. + if m.Phase != scplan.PostCommitPhase { + return nil + } + table := catalogkv.TestingGetTableDescriptorFromSchema( + kvDB, keys.SystemSQLCodec, "db", "public", "t") + mutations := table.GetMutations() + // There are 2 schema changes that should precede job 3. Note that the + // new-style schema change itself uses multiple mutation IDs. + for i := range mutations { + assert.Greater(t, int(mutations[i].MutationID), 2) + } + return nil + }, + BeforeWaitingForConcurrentSchemaChanges: func(_ []string) { + job3Wait.Do(func() { + close(job3WaitNotification) + }) + }, + }, + } + var sqlDB *gosql.DB + s, sqlDB, kvDB = serverutils.StartServer(t, params) + defer s.Stopper().Stop(ctx) + + tdb := sqlutils.MakeSQLRunner(sqlDB) + tdb.Exec(t, `CREATE DATABASE db`) + tdb.Exec(t, `CREATE TABLE db.t (a INT PRIMARY KEY)`) + + g := ctxgroup.WithContext(ctx) + + // Start job 1: An index schema change, which does not use the new schema + // changer. + g.GoCtx(func(ctx context.Context) error { + _, err := sqlDB.ExecContext(ctx, `CREATE INDEX idx ON db.t(a)`) + assert.NoError(t, err) + return nil + }) + + <-job1BackfillNotification + + // Start job 3: A column schema change which uses the new schema changer. + // The transaction will not actually commit until job 1 has finished. + g.GoCtx(func(ctx context.Context) error { + conn, err := sqlDB.Conn(ctx) + if err != nil { + return err + } + _, err = conn.ExecContext(ctx, `SET experimental_use_new_schema_changer = 'on'`) + assert.NoError(t, err) + _, err = conn.ExecContext(ctx, `ALTER TABLE db.t ADD COLUMN b INT DEFAULT 1`) + assert.NoError(t, err) + return nil + }) + + <-job3WaitNotification + + // Start job 2: Another index schema change which does not use the new + // schema changer. + g.GoCtx(func(ctx context.Context) error { + _, err := sqlDB.ExecContext(ctx, `CREATE INDEX idx2 ON db.t(a)`) + assert.NoError(t, err) + return nil + }) + + // Wait for job 2 to start. + <-job2ResumeNotification + + // Finally, let job 1 finish, which will unblock the + // others. + close(job1ContinueNotification) + require.NoError(t, g.Wait()) + + // Check that job 3 was created last. + tdb.CheckQueryResults(t, + fmt.Sprintf(`SELECT job_type, status, description FROM crdb_internal.jobs WHERE job_type = '%s' OR job_type = '%s' ORDER BY created`, + jobspb.TypeSchemaChange.String(), jobspb.TypeNewSchemaChange.String(), + ), + [][]string{ + {jobspb.TypeSchemaChange.String(), string(jobs.StatusSucceeded), `CREATE INDEX idx ON db.public.t (a)`}, + {jobspb.TypeSchemaChange.String(), string(jobs.StatusSucceeded), `CREATE INDEX idx2 ON db.public.t (a)`}, + {jobspb.TypeNewSchemaChange.String(), string(jobs.StatusSucceeded), `Schema change job`}, + }, + ) + }) + + t.Run("wait for new-style schema changes", func(t *testing.T) { + // This test starts a new-style schema change job (job 1), and then starts + // another new-style schema change job (job 2) while job 1 is backfilling. + ctx := context.Background() + + var job1Backfill sync.Once + var job2Wait sync.Once + // Closed when we enter the RunBeforeBackfill knob of job 1. + job1BackfillNotification := make(chan struct{}) + // Closed when we're ready to continue with job 1. + job1ContinueNotification := make(chan struct{}) + // Closed when job 2 starts waiting for concurrent schema changes to finish. + job2WaitNotification := make(chan struct{}) + + stmt1 := `ALTER TABLE db.t ADD COLUMN b INT DEFAULT 1` + stmt2 := `ALTER TABLE db.t ADD COLUMN c INT DEFAULT 2` + + var kvDB *kv.DB + params, _ := tests.CreateTestServerParams() + params.Knobs = base.TestingKnobs{ + SQLNewSchemaChanger: &scexec.NewSchemaChangerTestingKnobs{ + BeforeStage: func(ops scop.Ops, m scexec.TestingKnobMetadata) error { + // Verify that we never queue mutations for job 2 before finishing job + // 1. + if m.Phase != scplan.PostCommitPhase { + return nil + } + table := catalogkv.TestingGetTableDescriptorFromSchema( + kvDB, keys.SystemSQLCodec, "db", "public", "t") + mutations := table.GetMutations() + if len(mutations) == 0 { + t.Errorf("unexpected empty mutations") + return errors.Errorf("test failure") + } + var idsSeen []descpb.MutationID + for i := range mutations { + m := &mutations[i] + if len(idsSeen) == 0 || m.MutationID > idsSeen[len(idsSeen)-1] { + idsSeen = append(idsSeen, m.MutationID) + } + } + // Each schema change involving an index backfill has 2 consecutive + // mutation IDs, so the first schema change is expected to have + // mutation IDs 1 and 2, and the second one 3 and 4. + lowestID, highestID := idsSeen[0], idsSeen[len(idsSeen)-1] + if m.Statements[0] == stmt1 { + assert.Truef(t, highestID <= 2, "unexpected mutation IDs %v", idsSeen) + } else if m.Statements[0] == stmt2 { + assert.Truef(t, lowestID >= 3 && highestID <= 4, "unexpected mutation IDs %v", idsSeen) + } else { + t.Errorf("unexpected statements %v", m.Statements) + return errors.Errorf("test failure") + } + + // Block job 1 during the backfill. + if m.Statements[0] != stmt1 || ops.Type() != scop.BackfillType { + return nil + } + for _, op := range ops.Slice() { + if backfillOp, ok := op.(scop.BackfillIndex); ok && backfillOp.IndexID == descpb.IndexID(2) { + job1Backfill.Do(func() { + close(job1BackfillNotification) + <-job1ContinueNotification + }) + } + } + + return nil + }, + BeforeWaitingForConcurrentSchemaChanges: func(stmts []string) { + if stmts[0] != stmt2 { + return + } + job2Wait.Do(func() { + close(job2WaitNotification) + }) + }, + }, + } + + var s serverutils.TestServerInterface + var sqlDB *gosql.DB + s, sqlDB, kvDB = serverutils.StartServer(t, params) + defer s.Stopper().Stop(ctx) + + tdb := sqlutils.MakeSQLRunner(sqlDB) + tdb.Exec(t, `CREATE DATABASE db`) + tdb.Exec(t, `CREATE TABLE db.t (a INT PRIMARY KEY)`) + + g := ctxgroup.WithContext(ctx) + + g.GoCtx(func(ctx context.Context) error { + conn, err := sqlDB.Conn(ctx) + if err != nil { + return err + } + _, err = conn.ExecContext(ctx, `SET experimental_use_new_schema_changer = 'on'`) + assert.NoError(t, err) + _, err = conn.ExecContext(ctx, stmt1) + assert.NoError(t, err) + return nil + }) + + <-job1BackfillNotification + + g.GoCtx(func(ctx context.Context) error { + conn, err := sqlDB.Conn(ctx) + if err != nil { + return err + } + _, err = conn.ExecContext(ctx, `SET experimental_use_new_schema_changer = 'on'`) + assert.NoError(t, err) + _, err = conn.ExecContext(ctx, stmt2) + assert.NoError(t, err) + return nil + }) + + <-job2WaitNotification + close(job1ContinueNotification) + require.NoError(t, g.Wait()) + + tdb.CheckQueryResults(t, + fmt.Sprintf(`SELECT job_type, status FROM crdb_internal.jobs WHERE job_type = '%s' OR job_type = '%s' ORDER BY created`, + jobspb.TypeSchemaChange.String(), jobspb.TypeNewSchemaChange.String(), + ), + [][]string{ + {jobspb.TypeNewSchemaChange.String(), string(jobs.StatusSucceeded)}, + {jobspb.TypeNewSchemaChange.String(), string(jobs.StatusSucceeded)}, + }, + ) + }) +} + +func TestConcurrentOldSchemaChangesCannotStart(t *testing.T) { + defer leaktest.AfterTest(t)() + defer sqltestutils.SetTestJobsAdoptInterval()() + + ctx := context.Background() + + var doOnce sync.Once + // Closed when we enter the RunBeforeBackfill knob. + beforeBackfillNotification := make(chan struct{}) + // Closed when we're ready to continue with the schema change. + continueNotification := make(chan struct{}) + + var kvDB *kv.DB + params, _ := tests.CreateTestServerParams() + params.Knobs = base.TestingKnobs{ + SQLSchemaChanger: &sql.SchemaChangerTestingKnobs{ + RunBeforeResume: func(jobID jobspb.JobID) error { + // Assert that old schema change jobs never run in this test. + t.Errorf("unexpected old schema change job %d", jobID) + return nil + }, + }, + SQLNewSchemaChanger: &scexec.NewSchemaChangerTestingKnobs{ + BeforeStage: func(ops scop.Ops, m scexec.TestingKnobMetadata) error { + // Verify that we never get a mutation ID not associated with the schema + // change that is running. + if m.Phase != scplan.PostCommitPhase { + return nil + } + table := catalogkv.TestingGetTableDescriptorFromSchema( + kvDB, keys.SystemSQLCodec, "db", "public", "t") + mutations := table.GetMutations() + for i := range mutations { + assert.LessOrEqual(t, int(mutations[i].MutationID), 2) + } + + if ops.Type() != scop.BackfillType { + return nil + } + for _, op := range ops.Slice() { + if _, ok := op.(scop.BackfillIndex); ok { + doOnce.Do(func() { + close(beforeBackfillNotification) + <-continueNotification + }) + } + } + return nil + }, + }, + } + + var s serverutils.TestServerInterface + var sqlDB *gosql.DB + s, sqlDB, kvDB = serverutils.StartServer(t, params) + defer s.Stopper().Stop(ctx) + + tdb := sqlutils.MakeSQLRunner(sqlDB) + tdb.Exec(t, `CREATE DATABASE db`) + tdb.Exec(t, `CREATE TABLE db.t (a INT PRIMARY KEY)`) + + g := ctxgroup.WithContext(ctx) + + g.GoCtx(func(ctx context.Context) error { + conn, err := sqlDB.Conn(ctx) + if err != nil { + return err + } + _, err = conn.ExecContext(ctx, `SET experimental_use_new_schema_changer = 'on'`) + assert.NoError(t, err) + _, err = conn.ExecContext(ctx, `ALTER TABLE db.t ADD COLUMN b INT DEFAULT 1`) + assert.NoError(t, err) + return nil + }) + + <-beforeBackfillNotification + + { + conn, err := sqlDB.Conn(ctx) + require.NoError(t, err) + + _, err = conn.ExecContext(ctx, `SET experimental_use_new_schema_changer = 'off'`) + require.NoError(t, err) + for _, stmt := range []string{ + `ALTER TABLE db.t ADD COLUMN c INT DEFAULT 2`, + `CREATE INDEX ON db.t(a)`, + `ALTER TABLE db.t RENAME COLUMN a TO c`, + `CREATE TABLE db.t2 (i INT PRIMARY KEY, a INT REFERENCES db.t)`, + `CREATE VIEW db.v AS SELECT a FROM db.t`, + `ALTER TABLE db.t RENAME TO db.new`, + `GRANT ALL ON db.t TO root`, + `TRUNCATE TABLE db.t`, + `DROP TABLE db.t`, + } { + _, err = conn.ExecContext(ctx, stmt) + assert.Truef(t, + testutils.IsError(err, `cannot perform a schema change on table "t"`), + "statement: %s, error: %s", stmt, err, + ) + } + } + + close(continueNotification) + require.NoError(t, g.Wait()) +} diff --git a/pkg/sql/schemachanger/scjob/BUILD.bazel b/pkg/sql/schemachanger/scjob/BUILD.bazel index 2a0f140e1bda..f758f6302f45 100644 --- a/pkg/sql/schemachanger/scjob/BUILD.bazel +++ b/pkg/sql/schemachanger/scjob/BUILD.bazel @@ -22,5 +22,6 @@ go_library( "//pkg/sql/sem/tree", "//pkg/sql/sqlutil", "//pkg/util/log/logcrash", + "@com_github_cockroachdb_errors//:errors", ], ) diff --git a/pkg/sql/schemachanger/scjob/job.go b/pkg/sql/schemachanger/scjob/job.go index 3cf4532b6259..2e84e80417a2 100644 --- a/pkg/sql/schemachanger/scjob/job.go +++ b/pkg/sql/schemachanger/scjob/job.go @@ -12,6 +12,7 @@ package scjob import ( "context" + "strings" "github.com/cockroachdb/cockroach/pkg/jobs" "github.com/cockroachdb/cockroach/pkg/jobs/jobspb" @@ -103,7 +104,9 @@ func (n *newSchemaChangeResumer) Resume(ctx context.Context, execCtxI interface{ return err } - for _, s := range sc.Stages { + stmts := getStmtsForTestingMetadata(n.job) + + for i, s := range sc.Stages { var descriptorsWithUpdatedVersions []lease.IDVersion if err := descs.Txn(ctx, settings, lm, ie, db, func(ctx context.Context, txn *kv.Txn, descriptors *descs.Collection) error { jt := badJobTracker{ @@ -111,9 +114,24 @@ func (n *newSchemaChangeResumer) Resume(ctx context.Context, execCtxI interface{ descriptors: descriptors, codec: execCtx.ExecCfg().Codec, } - if err := scexec.NewExecutor(txn, descriptors, execCtx.ExecCfg().Codec, execCtx.ExecCfg().IndexBackfiller, jt).ExecuteOps(ctx, s.Ops); err != nil { + if err := scexec.NewExecutor( + txn, descriptors, execCtx.ExecCfg().Codec, execCtx.ExecCfg().IndexBackfiller, + jt, execCtx.ExecCfg().NewSchemaChangerTestingKnobs, + ).ExecuteOps(ctx, s.Ops, scexec.TestingKnobMetadata{ + Statements: stmts, + Phase: scplan.PostCommitPhase, + }); err != nil { return err } + // If this is the last stage, also update all the table descriptors to + // remove the job ID. + if i == len(sc.Stages)-1 { + if err := scexec.UpdateDescriptorJobIDs( + ctx, txn, descriptors, n.job.Payload().DescriptorIDs, n.job.ID(), jobspb.InvalidJobID, + ); err != nil { + return err + } + } descriptorsWithUpdatedVersions = descriptors.GetDescriptorsWithNewVersion() return n.job.Update(ctx, txn, func(txn *kv.Txn, md jobs.JobMetadata, ju *jobs.JobUpdater) error { pg := md.Progress.GetNewSchemaChange() @@ -162,6 +180,12 @@ func makeTargetStates( return ts } +func getStmtsForTestingMetadata(j *jobs.Job) []string { + // This is a hack to get individual statements back out of the concatenated + // statements. + return strings.Split(j.Payload().Statement, "; ") +} + func (n *newSchemaChangeResumer) OnFailOrCancel(ctx context.Context, execCtx interface{}) error { panic("unimplemented") } diff --git a/pkg/sql/table.go b/pkg/sql/table.go index 319e91ffa195..5568858bd6cb 100644 --- a/pkg/sql/table.go +++ b/pkg/sql/table.go @@ -22,6 +22,8 @@ import ( "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" "github.com/cockroachdb/cockroach/pkg/sql/catalog/tabledesc" "github.com/cockroachdb/cockroach/pkg/sql/catalog/typedesc" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" "github.com/cockroachdb/cockroach/pkg/sql/sqltelemetry" "github.com/cockroachdb/cockroach/pkg/util/log" "github.com/cockroachdb/errors" @@ -101,6 +103,14 @@ func (p *planner) createNonDropDatabaseChangeJob( func (p *planner) createOrUpdateSchemaChangeJob( ctx context.Context, tableDesc *tabledesc.Mutable, jobDesc string, mutationID descpb.MutationID, ) error { + if tableDesc.NewSchemaChangeJobID != 0 { + return pgerror.Newf(pgcode.ObjectNotInPrerequisiteState, + "cannot perform a schema change on table %q while it is undergoing a new-style schema change", + // We use the cluster version because the table may have been renamed. + // This is a bit of a hack. + tableDesc.ClusterVersion.GetName(), + ) + } var job *jobs.Job if cachedJob, ok := p.extendedEvalCtx.SchemaChangeJobCache[tableDesc.ID]; ok { job = cachedJob