@@ -94,6 +94,7 @@ type server struct {
9494 gcc chan int // set when gcloop starts, closed when server shuts down
9595 db * sql.DB
9696 tableBackend * SqlTables
97+ mvBackend * SqlMaterializedViews
9798 cmvs * cmvRegistry
9899
99100 materializedViews map [string ]* btapb.MaterializedView // keyed by full resource name
@@ -123,6 +124,7 @@ func NewServer(laddr string, db *sql.DB, opt ...grpc.ServerOption) (*Server, err
123124 materializedViews : make (map [string ]* btapb.MaterializedView ),
124125 db : db ,
125126 tableBackend : NewSqlTables (db ),
127+ mvBackend : NewSqlMaterializedViews (db ),
126128 cmvs : newCMVRegistry (),
127129 },
128130 }
@@ -131,6 +133,7 @@ func NewServer(laddr string, db *sql.DB, opt ...grpc.ServerOption) (*Server, err
131133 }
132134 longrunningpb .RegisterOperationsServer (s .srv , opsServer )
133135 s .s .LoadTables ()
136+ s .s .LoadMaterializedViews ()
134137 btapb .RegisterBigtableInstanceAdminServer (s .srv , s .s )
135138 btapb .RegisterBigtableTableAdminServer (s .srv , s .s )
136139 btpb .RegisterBigtableServer (s .srv , s .s )
@@ -159,6 +162,36 @@ func (s *server) LoadTables() {
159162 }
160163}
161164
165+ // LoadMaterializedViews restores persisted CMV metadata from SQLite on startup.
166+ // For each stored view, it re-parses the SQL to reconstruct the CMVConfig and
167+ // re-registers it so that write-time propagation resumes immediately.
168+ func (s * server ) LoadMaterializedViews () {
169+ for _ , v := range s .mvBackend .GetAll () {
170+ cfg , err := ParseCMVConfigFromSQL (viewIDFromName (v .name ), v .query )
171+ if err != nil {
172+ // Log and skip rather than crashing — the parser may have evolved.
173+ log .Printf ("WARNING: skipping persisted materialized view %q: could not parse query: %v" , v .name , err )
174+ continue
175+ }
176+ s .cmvs .register (* cfg )
177+ s .materializedViews [v .name ] = & btapb.MaterializedView {
178+ Name : v .name ,
179+ Query : v .query ,
180+ DeletionProtection : v .deletionProtection ,
181+ }
182+ }
183+ }
184+
185+ // viewIDFromName extracts the view ID from a full resource name of the form
186+ // projects/.../instances/.../materializedViews/<id>.
187+ func viewIDFromName (name string ) string {
188+ const sep = "/materializedViews/"
189+ if idx := strings .LastIndex (name , sep ); idx >= 0 {
190+ return name [idx + len (sep ):]
191+ }
192+ return name
193+ }
194+
162195// ensureCMVTable creates the shadow table for a CMV if it doesn't already exist.
163196// Copies column families from the source table, filtered by IncludeFamilies.
164197// Must be called with s.mu held.
@@ -383,6 +416,7 @@ func (s *server) DeleteTable(ctx context.Context, req *btapb.DeleteTableRequest)
383416 }
384417 for mvName := range s .materializedViews {
385418 if strings .HasSuffix (mvName , "/materializedViews/" + viewID ) {
419+ s .mvBackend .Delete (mvName )
386420 delete (s .materializedViews , mvName )
387421 break
388422 }
0 commit comments