Skip to content

Commit 68dc1ed

Browse files
Add more comments about how to implement the interfaces in NoSQL
1 parent cade91a commit 68dc1ed

File tree

1 file changed

+44
-23
lines changed

1 file changed

+44
-23
lines changed

common/persistence/nosql/nosqlplugin/interfaces.go

+44-23
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ type (
3838
tableCRUD
3939
}
4040
// tableCRUD defines the API for interacting with the database tables
41-
// NOTE: All SELECT interfaces require strong consistency. Using eventual consistency will not work.
41+
// NOTE 1: All SELECT interfaces require strong consistency (eventual consistency will not work) unless specify in the method.
42+
//
43+
// NOTE 2: About schema: only the columns that need to be partition key, range key or index key are considered 'significant',
44+
// which required to be in the schema. All other non 'significant' columns are opaque for implementation.
45+
// Therefore, it's recommended to use a data blob to store all the other columns, so that adding new
46+
// column will not require schema changes. This approach has been proved very successful in MySQL/Postgres implementation of SQL interfaces.
47+
// Cassandra implementation cannot do it due to backward-compatibility. Any other NoSQL implementation should use datablob for non-significant columns.
48+
// Follow the comment for each tableCRUD for what are 'significant' columns.
4249
tableCRUD interface {
4350
historyEventsCRUD
4451
messageQueueCRUD
@@ -58,16 +65,15 @@ type (
5865
IsThrottlingError(error) bool
5966
}
6067

61-
// historyEventsCRUD is for History events storage system
68+
/**
69+
* historyEventsCRUD is for History events storage system
70+
* Recommendation: use two tables: history_tree for branch records and history_node for node records
71+
* if a single update query can operate on two tables.
72+
* Significant columns:
73+
* history_tree partition key: (shardID, treeID), range key: (branchID)
74+
* history_node partition key: (shardID, treeID), range key: (branchID, nodeID ASC, txnID DESC)
75+
*/
6276
historyEventsCRUD interface {
63-
/**
64-
* It can be implemented with two tables(history_tree for branch records and history_node for node records)
65-
* ShardID is passed from application layer as the same shardID of the workflow. But it is not required for History events
66-
* to be in the same shard as workflows. The pro of being the same shard is that when one DB partition goes down, the impact is lower.
67-
* However, being in the same shard can cause some hot partition issue. Because sometimes history can grow very large, this could be worse.
68-
* Therefore, Cadence built-in Cassandra plugin doesn't take use of ShardID at all.
69-
**/
70-
7177
// InsertIntoHistoryTreeAndNode inserts one or two rows: tree row and node row(at least one of them)
7278
InsertIntoHistoryTreeAndNode(ctx context.Context, treeRow *HistoryTreeRow, nodeRow *HistoryNodeRow) error
7379

@@ -86,8 +92,14 @@ type (
8692
SelectFromHistoryTree(ctx context.Context, filter *HistoryTreeFilter) ([]*HistoryTreeRow, error)
8793
}
8894

89-
// messageQueueCRUD is for the message queue storage system
90-
// Typically two tables(queue_message,and queue_metadata) are needed to implement this interface
95+
/***
96+
* messageQueueCRUD is for the message queue storage system
97+
*
98+
* Recommendation: use two tables(queue_message,and queue_metadata) to implement this interface
99+
* Significant columns:
100+
* queue_message partition key: (queueType), range key: (messageID)
101+
* queue_metadata partition key: (queueType), range key: N/A
102+
*/
91103
messageQueueCRUD interface {
92104
//Insert message into queue, return error if failed or already exists
93105
// Must return conditionFailed error if row already exists
@@ -117,17 +129,26 @@ type (
117129
GetQueueSize(ctx context.Context, queueType persistence.QueueType) (int64, error)
118130
}
119131

120-
// domainCRUD is for domain + domain metadata storage system
121-
// Ideally a domain operation should be implemented in transaction to be atomic if using multiple tables.
122-
// For example, Cassandra uses two table, domains and domains_by_name_v2.
123-
// But it is okay if not, as the nosqlMetadataManager will handle the edge cases.
124-
//
125-
// However, there is a special record as "domain metadata". Right now it is an integer number as notification version.
126-
// The main purpose of it is to notify clusters that there is some changes in domains, so domain cache needs to refresh.
127-
// It always increase by one, whenever a domain is updated or inserted.
128-
// Updating this failover metadata with domain insert/update needs to be atomic.
129-
// Because Batch LWTs is only allowed within one table and same partition.
130-
// The Cassandra implementation stores it in the same table as domain in domains_by_name_v2.
132+
/***
133+
* domainCRUD is for domain + domain metadata storage system
134+
*
135+
* Recommendation: Use one table to implement
136+
* Significant columns:
137+
* domain: partition key( a constant value), range key(domainName), local secondary index(domainID)
138+
*
139+
* Note 1: About Cassandra's implementation: Because of historical reasons, Cassandra uses two table,
140+
* domains and domains_by_name_v2. Therefore, Cassandra implementation lost the atomicity causing some edge cases,
141+
* and the implementation is more complicated than it should be.
142+
*
143+
* Note 2: About the special record as "domain metadata". Right now it is an integer number as notification version.
144+
* The main purpose of it is to notify clusters that there is some changes in domains, so domain cache needs to refresh.
145+
* It always increase by one, whenever a domain is updated or inserted.
146+
* Updating this failover metadata with domain insert/update needs to be atomic.
147+
* Because Batch LWTs is only allowed within one table and same partition.
148+
* The Cassandra implementation stores it in the same table as domain in domains_by_name_v2.
149+
*
150+
* Note 3: It's okay to use a constant value for partition key because domain table is serving very small volume of traffic.
151+
*/
131152
domainCRUD interface {
132153
// Insert a new record to domain, return error if failed or already exists
133154
// Must return conditionFailed error if domainName already exists

0 commit comments

Comments
 (0)