@@ -2,8 +2,9 @@ package rest
22
33import (
44 "context"
5+ "errors"
6+ "time"
57
6- apierrors "k8s.io/apimachinery/pkg/api/errors"
78 metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
89 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910 "k8s.io/apimachinery/pkg/runtime"
@@ -21,114 +22,151 @@ type DualWriterMode3 struct {
2122// newDualWriterMode3 returns a new DualWriter in mode 3.
2223// Mode 3 represents writing to LegacyStorage and Storage and reading from Storage.
2324func newDualWriterMode3 (legacy LegacyStorage , storage Storage , dwm * dualWriterMetrics ) * DualWriterMode3 {
24- return & DualWriterMode3 {Legacy : legacy , Storage : storage , Log : klog .NewKlogr ().WithName ("DualWriterMode3" ), dualWriterMetrics : dwm }
25+ return & DualWriterMode3 {Legacy : legacy , Storage : storage , Log : klog .NewKlogr ().WithName ("DualWriterMode3" ). WithValues ( "mode" , mode3Str ) , dualWriterMetrics : dwm }
2526}
2627
2728// Mode returns the mode of the dual writer.
2829func (d * DualWriterMode3 ) Mode () DualWriterMode {
2930 return Mode3
3031}
3132
33+ const mode3Str = "3"
34+
3235// Create overrides the behavior of the generic DualWriter and writes to LegacyStorage and Storage.
3336func (d * DualWriterMode3 ) Create (ctx context.Context , obj runtime.Object , createValidation rest.ValidateObjectFunc , options * metav1.CreateOptions ) (runtime.Object , error ) {
34- log := klog .FromContext (ctx )
37+ var method = "create"
38+ log := d .Log .WithValues ("kind" , options .Kind , "method" , method )
39+ ctx = klog .NewContext (ctx , log )
3540
41+ startStorage := time .Now ()
3642 created , err := d .Storage .Create (ctx , obj , createValidation , options )
3743 if err != nil {
3844 log .Error (err , "unable to create object in storage" )
45+ d .recordLegacyDuration (true , mode3Str , options .Kind , method , startStorage )
3946 return created , err
4047 }
48+ d .recordStorageDuration (false , mode3Str , options .Kind , method , startStorage )
4149
42- if _ , err := d .Legacy .Create (ctx , obj , createValidation , options ); err != nil {
43- log .WithValues ("object" , created ).Error (err , "unable to create object in legacy storage" )
44- }
45- return created , nil
50+ go func () {
51+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("legacy create timeout" ))
52+ defer cancel ()
53+
54+ startLegacy := time .Now ()
55+ _ , errObjectSt := d .Legacy .Create (ctx , obj , createValidation , options )
56+ d .recordLegacyDuration (errObjectSt != nil , mode3Str , options .Kind , method , startLegacy )
57+ }()
58+
59+ return created , err
4660}
4761
4862// Get overrides the behavior of the generic DualWriter and retrieves an object from Storage.
4963func (d * DualWriterMode3 ) Get (ctx context.Context , name string , options * metav1.GetOptions ) (runtime.Object , error ) {
50- return d .Storage .Get (ctx , name , & metav1.GetOptions {})
64+ var method = "get"
65+ log := d .Log .WithValues ("kind" , options .Kind , "name" , name , "method" , method )
66+ ctx = klog .NewContext (ctx , log )
67+
68+ startStorage := time .Now ()
69+ res , err := d .Storage .Get (ctx , name , options )
70+ if err != nil {
71+ log .Error (err , "unable to get object in storage" )
72+ }
73+ d .recordStorageDuration (err != nil , mode3Str , options .Kind , method , startStorage )
74+
75+ return res , err
5176}
5277
53- func (d * DualWriterMode3 ) Delete (ctx context.Context , name string , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions ) (runtime.Object , bool , error ) {
54- log := d .Log .WithValues ("name" , name )
78+ // List overrides the behavior of the generic DualWriter and reads only from Unified Store.
79+ func (d * DualWriterMode3 ) List (ctx context.Context , options * metainternalversion.ListOptions ) (runtime.Object , error ) {
80+ var method = "list"
81+ log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , options .ResourceVersion , "method" , method )
5582 ctx = klog .NewContext (ctx , log )
5683
57- deleted , async , err := d .Storage .Delete (ctx , name , deleteValidation , options )
84+ startStorage := time .Now ()
85+ res , err := d .Storage .List (ctx , options )
5886 if err != nil {
59- if ! apierrors .IsNotFound (err ) {
60- log .Error (err , "could not delete from unified store" )
61- return deleted , async , err
62- }
87+ log .Error (err , "unable to list object in storage" )
6388 }
89+ d .recordStorageDuration (err != nil , mode3Str , options .Kind , method , startStorage )
6490
65- _ , _ , errLS := d .Legacy .Delete (ctx , name , deleteValidation , options )
66- if errLS != nil {
67- if ! apierrors .IsNotFound (errLS ) {
68- log .WithValues ("deleted" , deleted ).Error (errLS , "could not delete from legacy store" )
69- }
91+ return res , err
92+ }
93+
94+ func (d * DualWriterMode3 ) Delete (ctx context.Context , name string , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions ) (runtime.Object , bool , error ) {
95+ var method = "delete"
96+ log := d .Log .WithValues ("name" , name , "kind" , options .Kind , "method" , method )
97+ ctx = klog .NewContext (ctx , d .Log )
98+
99+ startStorage := time .Now ()
100+ res , async , err := d .Storage .Delete (ctx , name , deleteValidation , options )
101+ if err != nil {
102+ log .Error (err , "unable to delete object in storage" )
103+ d .recordStorageDuration (true , mode3Str , options .Kind , method , startStorage )
104+ return res , async , err
70105 }
106+ d .recordStorageDuration (false , mode3Str , name , method , startStorage )
71107
72- return deleted , async , err
108+ go func () {
109+ startLegacy := time .Now ()
110+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("legacy delete timeout" ))
111+ defer cancel ()
112+ _ , _ , err := d .Legacy .Delete (ctx , name , deleteValidation , options )
113+ d .recordLegacyDuration (err != nil , mode3Str , options .Kind , method , startLegacy )
114+ }()
115+
116+ return res , async , err
73117}
74118
75119// Update overrides the behavior of the generic DualWriter and writes first to Storage and then to LegacyStorage.
76120func (d * DualWriterMode3 ) Update (ctx context.Context , name string , objInfo rest.UpdatedObjectInfo , createValidation rest.ValidateObjectFunc , updateValidation rest.ValidateObjectUpdateFunc , forceAllowCreate bool , options * metav1.UpdateOptions ) (runtime.Object , bool , error ) {
77- log := d .Log .WithValues ("name" , name )
121+ var method = "update"
122+ log := d .Log .WithValues ("name" , name , "kind" , options .Kind , "method" , method )
78123 ctx = klog .NewContext (ctx , log )
79- old , err := d .Storage .Get (ctx , name , & metav1.GetOptions {})
80- if err != nil {
81- log .WithValues ("object" , old ).Error (err , "could not get object to update" )
82- return nil , false , err
83- }
84124
85- updated , err := objInfo .UpdatedObject (ctx , old )
125+ startStorage := time .Now ()
126+ res , async , err := d .Storage .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
86127 if err != nil {
87- log .WithValues ("object" , updated ).Error (err , "could not update or create object" )
88- return nil , false , err
89- }
90- objInfo = & updateWrapper {
91- upstream : objInfo ,
92- updated : updated ,
128+ log .Error (err , "unable to update in storage" )
129+ d .recordLegacyDuration (true , mode3Str , options .Kind , method , startStorage )
130+ return res , async , err
93131 }
132+ d .recordStorageDuration (false , mode3Str , options .Kind , method , startStorage )
94133
95- obj , created , err := d .Storage .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
96- if err != nil {
97- log .WithValues ("object" , obj ).Error (err , "could not write to US" )
98- return obj , created , err
99- }
134+ go func () {
135+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("legacy update timeout" ))
100136
101- _ , _ , errLeg := d .Legacy .Update (ctx , name , & updateWrapper {
102- upstream : objInfo ,
103- updated : obj ,
104- }, createValidation , updateValidation , forceAllowCreate , options )
105- if errLeg != nil {
106- log .Error (errLeg , "could not update object in legacy store" )
107- }
108- return obj , created , err
137+ startLegacy := time .Now ()
138+ defer cancel ()
139+ _ , _ , errObjectSt := d .Legacy .Update (ctx , name , objInfo , createValidation , updateValidation , forceAllowCreate , options )
140+ d .recordLegacyDuration (errObjectSt != nil , mode3Str , options .Kind , method , startLegacy )
141+ }()
142+
143+ return res , async , err
109144}
110145
111146// DeleteCollection overrides the behavior of the generic DualWriter and deletes from both LegacyStorage and Storage.
112147func (d * DualWriterMode3 ) DeleteCollection (ctx context.Context , deleteValidation rest.ValidateObjectFunc , options * metav1.DeleteOptions , listOptions * metainternalversion.ListOptions ) (runtime.Object , error ) {
113- log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , listOptions .ResourceVersion )
148+ var method = "delete-collection"
149+ log := d .Log .WithValues ("kind" , options .Kind , "resourceVersion" , listOptions .ResourceVersion , "method" , method )
114150 ctx = klog .NewContext (ctx , log )
115151
116- deleted , err := d .Storage .DeleteCollection (ctx , deleteValidation , options , listOptions )
152+ startStorage := time .Now ()
153+ res , err := d .Storage .DeleteCollection (ctx , deleteValidation , options , listOptions )
117154 if err != nil {
118- log .Error (err , "failed to delete collection successfully from Storage" )
155+ log .Error (err , "unable to delete collection in storage" )
156+ d .recordStorageDuration (true , mode3Str , options .Kind , method , startStorage )
157+ return res , err
119158 }
159+ d .recordStorageDuration (false , mode3Str , options .Kind , method , startStorage )
120160
121- if deleted , err := d .Legacy .DeleteCollection (ctx , deleteValidation , options , listOptions ); err != nil {
122- log .WithValues ("deleted" , deleted ).Error (err , "failed to delete collection successfully from LegacyStorage" )
123- }
161+ go func () {
162+ startLegacy := time .Now ()
163+ ctx , cancel := context .WithTimeoutCause (ctx , time .Second * 10 , errors .New ("legacy deletecollection timeout" ))
164+ defer cancel ()
165+ _ , err := d .Legacy .DeleteCollection (ctx , deleteValidation , options , listOptions )
166+ d .recordStorageDuration (err != nil , mode3Str , options .Kind , method , startLegacy )
167+ }()
124168
125- return deleted , err
126- }
127-
128- func (d * DualWriterMode3 ) List (ctx context.Context , options * metainternalversion.ListOptions ) (runtime.Object , error ) {
129- //TODO: implement List
130- klog .Error ("List not implemented" )
131- return nil , nil
169+ return res , err
132170}
133171
134172func (d * DualWriterMode3 ) Destroy () {
0 commit comments