Skip to content

Commit 752ff50

Browse files
authored
Exclude deleted namespaces from ListNamespace response (#2646)
1 parent 4152b17 commit 752ff50

File tree

12 files changed

+222
-62
lines changed

12 files changed

+222
-62
lines changed

common/namespace/handler.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,9 @@ func (d *HandlerImpl) ListNamespaces(
301301
}
302302

303303
resp, err := d.metadataMgr.ListNamespaces(ctx, &persistence.ListNamespacesRequest{
304-
PageSize: pageSize,
305-
NextPageToken: listRequest.NextPageToken,
304+
PageSize: pageSize,
305+
NextPageToken: listRequest.NextPageToken,
306+
IncludeDeleted: listRequest.GetNamespaceFilter().GetIncludeDeleted(),
306307
})
307308

308309
if err != nil {

common/persistence/cassandra/metadata_store.go

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -307,46 +307,65 @@ func (m *MetadataStore) GetNamespace(request *p.GetNamespaceRequest) (*p.Interna
307307
}, nil
308308
}
309309

310-
func (m *MetadataStore) ListNamespaces(request *p.ListNamespacesRequest) (*p.InternalListNamespacesResponse, error) {
310+
func (m *MetadataStore) ListNamespaces(request *p.InternalListNamespacesRequest) (*p.InternalListNamespacesResponse, error) {
311311
query := m.session.Query(templateListNamespaceQueryV2, constNamespacePartition)
312-
iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter()
313-
312+
pageSize := request.PageSize
313+
nextPageToken := request.NextPageToken
314314
response := &p.InternalListNamespacesResponse{}
315+
315316
for {
316-
var name string
317-
var detail []byte
318-
var detailEncoding string
319-
var notificationVersion int64
320-
var isGlobal bool
321-
if !iter.Scan(
322-
nil,
323-
&name,
324-
&detail,
325-
&detailEncoding,
326-
&notificationVersion,
327-
&isGlobal,
328-
) {
329-
// done iterating over all namespaces in this page
330-
break
331-
}
317+
iter := query.PageSize(pageSize).PageState(nextPageToken).Iter()
318+
skippedRows := 0
319+
320+
for {
321+
var name string
322+
var detail []byte
323+
var detailEncoding string
324+
var notificationVersion int64
325+
var isGlobal bool
326+
if !iter.Scan(
327+
nil,
328+
&name,
329+
&detail,
330+
&detailEncoding,
331+
&notificationVersion,
332+
&isGlobal,
333+
) {
334+
// done iterating over all namespaces in this page
335+
break
336+
}
332337

333-
// do not include the metadata record
334-
if name != namespaceMetadataRecordName {
338+
// do not include the metadata record
339+
if name == namespaceMetadataRecordName {
340+
skippedRows++
341+
continue
342+
}
335343
response.Namespaces = append(response.Namespaces, &p.InternalGetNamespaceResponse{
336344
Namespace: p.NewDataBlob(detail, detailEncoding),
337345
IsGlobal: isGlobal,
338346
NotificationVersion: notificationVersion,
339347
})
340348
}
341-
}
349+
if len(iter.PageState()) > 0 {
350+
nextPageToken = iter.PageState()
351+
} else {
352+
nextPageToken = nil
353+
}
354+
if err := iter.Close(); err != nil {
355+
return nil, serviceerror.NewUnavailable(fmt.Sprintf("ListNamespaces operation failed. Error: %v", err))
356+
}
342357

343-
if len(iter.PageState()) > 0 {
344-
response.NextPageToken = iter.PageState()
345-
}
346-
if err := iter.Close(); err != nil {
347-
return nil, serviceerror.NewUnavailable(fmt.Sprintf("ListNamespaces operation failed. Error: %v", err))
358+
if len(nextPageToken) == 0 {
359+
// No more records in DB.
360+
break
361+
}
362+
if skippedRows == 0 {
363+
break
364+
}
365+
pageSize = skippedRows
348366
}
349367

368+
response.NextPageToken = nextPageToken
350369
return response, nil
351370
}
352371

common/persistence/client/fault_injection.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ func (m *FaultInjectionMetadataStore) DeleteNamespaceByName(request *persistence
741741
return m.baseMetadataStore.DeleteNamespaceByName(request)
742742
}
743743

744-
func (m *FaultInjectionMetadataStore) ListNamespaces(request *persistence.ListNamespacesRequest) (
744+
func (m *FaultInjectionMetadataStore) ListNamespaces(request *persistence.InternalListNamespacesRequest) (
745745
*persistence.InternalListNamespacesResponse,
746746
error,
747747
) {

common/persistence/dataInterfaces.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,9 @@ type (
641641

642642
// ListNamespacesRequest is used to list namespaces
643643
ListNamespacesRequest struct {
644-
PageSize int
645-
NextPageToken []byte
644+
PageSize int
645+
NextPageToken []byte
646+
IncludeDeleted bool
646647
}
647648

648649
// ListNamespacesResponse is the response for GetNamespace

common/persistence/metadata_manager.go

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -195,21 +195,45 @@ func (m *metadataManagerImpl) ListNamespaces(
195195
_ context.Context,
196196
request *ListNamespacesRequest,
197197
) (*ListNamespacesResponse, error) {
198-
resp, err := m.persistence.ListNamespaces(request)
199-
if err != nil {
200-
return nil, err
201-
}
202-
namespaces := make([]*GetNamespaceResponse, 0, len(resp.Namespaces))
203-
for _, d := range resp.Namespaces {
204-
ret, err := m.ConvertInternalGetResponse(d)
198+
var namespaces []*GetNamespaceResponse
199+
nextPageToken := request.NextPageToken
200+
pageSize := request.PageSize
201+
202+
for {
203+
resp, err := m.persistence.ListNamespaces(&InternalListNamespacesRequest{
204+
PageSize: pageSize,
205+
NextPageToken: nextPageToken,
206+
})
205207
if err != nil {
206208
return nil, err
207209
}
208-
namespaces = append(namespaces, ret)
210+
deletedNamespacesCount := 0
211+
for _, d := range resp.Namespaces {
212+
ret, err := m.ConvertInternalGetResponse(d)
213+
if err != nil {
214+
return nil, err
215+
}
216+
if ret.Namespace.Info.State == enumspb.NAMESPACE_STATE_DELETED && !request.IncludeDeleted {
217+
deletedNamespacesCount++
218+
continue
219+
}
220+
namespaces = append(namespaces, ret)
221+
}
222+
nextPageToken = resp.NextPageToken
223+
if len(nextPageToken) == 0 {
224+
// Page wasn't full, no more namespaces in DB.
225+
break
226+
}
227+
if deletedNamespacesCount == 0 {
228+
break
229+
}
230+
// Page was full but few namespaces weren't added. Read number of deleted namespaces for DB again.
231+
pageSize = deletedNamespacesCount
209232
}
233+
210234
return &ListNamespacesResponse{
211235
Namespaces: namespaces,
212-
NextPageToken: resp.NextPageToken,
236+
NextPageToken: nextPageToken,
213237
}, nil
214238
}
215239

common/persistence/mock/store_mock.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/persistence/persistence-tests/metadataPersistenceV2Test.go

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,27 +1084,135 @@ func (m *MetadataPersistenceSuiteV2) TestListNamespaces() {
10841084
}
10851085

10861086
var token []byte
1087-
pageSize := 1
1087+
const pageSize = 1
1088+
pageCount := 0
10881089
outputNamespaces := make(map[string]*p.GetNamespaceResponse)
1089-
ListLoop:
10901090
for {
10911091
resp, err := m.ListNamespaces(pageSize, token)
10921092
m.NoError(err)
10931093
token = resp.NextPageToken
10941094
for _, namespace := range resp.Namespaces {
1095-
outputNamespaces[string(namespace.Namespace.Info.Id)] = namespace
1095+
outputNamespaces[namespace.Namespace.Info.Id] = namespace
10961096
// global notification version is already tested, so here we make it 0
10971097
// so we can test == easily
10981098
namespace.NotificationVersion = 0
10991099
}
1100+
pageCount++
11001101
if len(token) == 0 {
1101-
break ListLoop
1102+
break
11021103
}
11031104
}
11041105

1106+
// 2 pages with data and 1 empty page which is unavoidable.
1107+
m.Equal(pageCount, 3)
11051108
m.Equal(len(inputNamespaces), len(outputNamespaces))
11061109
for _, namespace := range inputNamespaces {
1107-
m.Equal(namespace, outputNamespaces[string(namespace.Namespace.Info.Id)])
1110+
m.Equal(namespace, outputNamespaces[namespace.Namespace.Info.Id])
1111+
}
1112+
}
1113+
1114+
func (m *MetadataPersistenceSuiteV2) TestListNamespaces_DeletedNamespace() {
1115+
inputNamespaces := []*p.GetNamespaceResponse{
1116+
{
1117+
Namespace: &persistencespb.NamespaceDetail{
1118+
Info: &persistencespb.NamespaceInfo{
1119+
Id: uuid.New(),
1120+
Name: "list-namespace-test-name-1",
1121+
State: enumspb.NAMESPACE_STATE_REGISTERED,
1122+
},
1123+
Config: &persistencespb.NamespaceConfig{},
1124+
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
1125+
},
1126+
},
1127+
{
1128+
Namespace: &persistencespb.NamespaceDetail{
1129+
Info: &persistencespb.NamespaceInfo{
1130+
Id: uuid.New(),
1131+
Name: "list-namespace-test-name-2",
1132+
State: enumspb.NAMESPACE_STATE_DELETED,
1133+
},
1134+
Config: &persistencespb.NamespaceConfig{},
1135+
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
1136+
},
1137+
},
1138+
{
1139+
Namespace: &persistencespb.NamespaceDetail{
1140+
Info: &persistencespb.NamespaceInfo{
1141+
Id: uuid.New(),
1142+
Name: "list-namespace-test-name-3",
1143+
State: enumspb.NAMESPACE_STATE_REGISTERED,
1144+
},
1145+
Config: &persistencespb.NamespaceConfig{},
1146+
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
1147+
},
1148+
},
1149+
{
1150+
Namespace: &persistencespb.NamespaceDetail{
1151+
Info: &persistencespb.NamespaceInfo{
1152+
Id: uuid.New(),
1153+
Name: "list-namespace-test-name-4",
1154+
State: enumspb.NAMESPACE_STATE_DELETED,
1155+
},
1156+
Config: &persistencespb.NamespaceConfig{},
1157+
ReplicationConfig: &persistencespb.NamespaceReplicationConfig{},
1158+
},
1159+
},
1160+
}
1161+
for _, namespace := range inputNamespaces {
1162+
_, err := m.CreateNamespace(
1163+
namespace.Namespace.Info,
1164+
namespace.Namespace.Config,
1165+
namespace.Namespace.ReplicationConfig,
1166+
namespace.IsGlobalNamespace,
1167+
namespace.Namespace.ConfigVersion,
1168+
namespace.Namespace.FailoverVersion,
1169+
)
1170+
m.NoError(err)
1171+
}
1172+
1173+
var token []byte
1174+
var listNamespacesPageSize2 []*p.GetNamespaceResponse
1175+
pageCount := 0
1176+
for {
1177+
resp, err := m.ListNamespaces(2, token)
1178+
m.NoError(err)
1179+
token = resp.NextPageToken
1180+
for _, namespace := range resp.Namespaces {
1181+
listNamespacesPageSize2 = append(listNamespacesPageSize2, namespace)
1182+
}
1183+
pageCount++
1184+
if len(token) == 0 {
1185+
break
1186+
}
1187+
}
1188+
1189+
// 1 page with data and 1 empty page which is unavoidable.
1190+
m.Equal(2, pageCount)
1191+
m.Len(listNamespacesPageSize2, 2)
1192+
for _, namespace := range listNamespacesPageSize2 {
1193+
m.NotEqual(namespace.Namespace.Info.State, enumspb.NAMESPACE_STATE_DELETED)
1194+
}
1195+
1196+
pageCount = 0
1197+
var listNamespacesPageSize1 []*p.GetNamespaceResponse
1198+
for {
1199+
resp, err := m.ListNamespaces(1, token)
1200+
m.NoError(err)
1201+
token = resp.NextPageToken
1202+
for _, namespace := range resp.Namespaces {
1203+
listNamespacesPageSize1 = append(listNamespacesPageSize1, namespace)
1204+
}
1205+
pageCount++
1206+
if len(token) == 0 {
1207+
break
1208+
}
1209+
}
1210+
1211+
// 2 pages with data and 1 empty page which is unavoidable.
1212+
m.Equal(3, pageCount)
1213+
m.Len(listNamespacesPageSize1, 2)
1214+
for _, namespace := range listNamespacesPageSize1 {
1215+
m.NotEqual(namespace.Namespace.Info.State, enumspb.NAMESPACE_STATE_DELETED)
11081216
}
11091217
}
11101218

common/persistence/persistenceInterface.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ type (
8484
RenameNamespace(request *InternalRenameNamespaceRequest) error
8585
DeleteNamespace(request *DeleteNamespaceRequest) error
8686
DeleteNamespaceByName(request *DeleteNamespaceByNameRequest) error
87-
ListNamespaces(request *ListNamespacesRequest) (*InternalListNamespacesResponse, error)
87+
ListNamespaces(request *InternalListNamespacesRequest) (*InternalListNamespacesResponse, error)
8888
GetMetadata() (*GetMetadataResponse, error)
8989
}
9090

@@ -631,6 +631,11 @@ type (
631631
PreviousName string
632632
}
633633

634+
InternalListNamespacesRequest struct {
635+
PageSize int
636+
NextPageToken []byte
637+
}
638+
634639
// InternalListNamespacesResponse is the response for GetNamespace
635640
InternalListNamespacesResponse struct {
636641
Namespaces []*InternalGetNamespaceResponse

common/persistence/sql/metadata.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func (m *sqlMetadataManagerV2) GetMetadata() (*persistence.GetMetadataResponse,
235235
return &persistence.GetMetadataResponse{NotificationVersion: row.NotificationVersion}, nil
236236
}
237237

238-
func (m *sqlMetadataManagerV2) ListNamespaces(request *persistence.ListNamespacesRequest) (*persistence.InternalListNamespacesResponse, error) {
238+
func (m *sqlMetadataManagerV2) ListNamespaces(request *persistence.InternalListNamespacesRequest) (*persistence.InternalListNamespacesResponse, error) {
239239
ctx, cancel := newExecutionContext()
240240
defer cancel()
241241
var pageToken *primitives.UUID

go.mod

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ require (
3939
go.opentelemetry.io/otel/sdk v1.4.0
4040
go.opentelemetry.io/otel/sdk/export/metric v0.27.0
4141
go.opentelemetry.io/otel/sdk/metric v0.27.0
42-
go.temporal.io/api v1.7.1-0.20220324004000-817724af565a
42+
go.temporal.io/api v1.7.1-0.20220325233305-d1f0ee499b92
4343
go.temporal.io/sdk v1.14.0
4444
go.temporal.io/version v0.3.0
4545
go.uber.org/atomic v1.9.0
@@ -56,6 +56,8 @@ require (
5656
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
5757
)
5858

59+
replace go.temporal.io/api v1.7.1-0.20220324004000-817724af565a => ../temporal-api-go
60+
5961
require (
6062
cloud.google.com/go v0.100.2 // indirect
6163
cloud.google.com/go/compute v1.2.0 // indirect
@@ -100,12 +102,12 @@ require (
100102
go.opentelemetry.io/otel/trace v1.4.0 // indirect
101103
go.uber.org/dig v1.13.0 // indirect
102104
golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2 // indirect
103-
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
104-
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect
105+
golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect
106+
golang.org/x/sys v0.0.0-20220325203850-36772127a21f // indirect
105107
golang.org/x/text v0.3.7 // indirect
106108
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
107109
google.golang.org/appengine v1.6.7 // indirect
108-
google.golang.org/genproto v0.0.0-20220323144105-ec3c684e5b14 // indirect
110+
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb // indirect
109111
google.golang.org/protobuf v1.28.0 // indirect
110112
gopkg.in/inf.v0 v0.9.1 // indirect
111113
)

0 commit comments

Comments
 (0)