5
5
6
6
package org .opensearch .geospatial .ip2geo .action ;
7
7
8
- import java .io .IOException ;
8
+ import static org .opensearch .geospatial .ip2geo .common .Ip2GeoLockService .LOCK_DURATION_IN_SECONDS ;
9
+
9
10
import java .time .Instant ;
11
+ import java .util .concurrent .atomic .AtomicReference ;
10
12
11
13
import lombok .extern .log4j .Log4j2 ;
12
14
15
+ import org .opensearch .OpenSearchException ;
13
16
import org .opensearch .ResourceAlreadyExistsException ;
14
17
import org .opensearch .action .ActionListener ;
15
18
import org .opensearch .action .StepListener ;
21
24
import org .opensearch .geospatial .annotation .VisibleForTesting ;
22
25
import org .opensearch .geospatial .ip2geo .common .DatasourceFacade ;
23
26
import org .opensearch .geospatial .ip2geo .common .DatasourceState ;
27
+ import org .opensearch .geospatial .ip2geo .common .Ip2GeoLockService ;
24
28
import org .opensearch .geospatial .ip2geo .jobscheduler .Datasource ;
25
29
import org .opensearch .geospatial .ip2geo .jobscheduler .DatasourceUpdateService ;
26
30
import org .opensearch .index .engine .VersionConflictEngineException ;
31
+ import org .opensearch .jobscheduler .spi .LockModel ;
27
32
import org .opensearch .tasks .Task ;
28
33
import org .opensearch .threadpool .ThreadPool ;
29
34
import org .opensearch .transport .TransportService ;
@@ -36,6 +41,7 @@ public class PutDatasourceTransportAction extends HandledTransportAction<PutData
36
41
private final ThreadPool threadPool ;
37
42
private final DatasourceFacade datasourceFacade ;
38
43
private final DatasourceUpdateService datasourceUpdateService ;
44
+ private final Ip2GeoLockService lockService ;
39
45
40
46
/**
41
47
* Default constructor
@@ -44,50 +50,73 @@ public class PutDatasourceTransportAction extends HandledTransportAction<PutData
44
50
* @param threadPool the thread pool
45
51
* @param datasourceFacade the datasource facade
46
52
* @param datasourceUpdateService the datasource update service
53
+ * @param lockService the lock service
47
54
*/
48
55
@ Inject
49
56
public PutDatasourceTransportAction (
50
57
final TransportService transportService ,
51
58
final ActionFilters actionFilters ,
52
59
final ThreadPool threadPool ,
53
60
final DatasourceFacade datasourceFacade ,
54
- final DatasourceUpdateService datasourceUpdateService
61
+ final DatasourceUpdateService datasourceUpdateService ,
62
+ final Ip2GeoLockService lockService
55
63
) {
56
64
super (PutDatasourceAction .NAME , transportService , actionFilters , PutDatasourceRequest ::new );
57
65
this .threadPool = threadPool ;
58
66
this .datasourceFacade = datasourceFacade ;
59
67
this .datasourceUpdateService = datasourceUpdateService ;
68
+ this .lockService = lockService ;
60
69
}
61
70
62
71
@ Override
63
72
protected void doExecute (final Task task , final PutDatasourceRequest request , final ActionListener <AcknowledgedResponse > listener ) {
64
- try {
65
- StepListener <Void > createIndexStep = new StepListener <>();
66
- datasourceFacade .createIndexIfNotExists (createIndexStep );
67
- createIndexStep .whenComplete (v -> putDatasource (request , listener ), exception -> listener .onFailure (exception ));
68
- } catch (Exception e ) {
69
- listener .onFailure (e );
70
- }
73
+ lockService .acquireLock (request .getName (), LOCK_DURATION_IN_SECONDS , ActionListener .wrap (lock -> {
74
+ if (lock == null ) {
75
+ listener .onFailure (new OpenSearchException ("another processor is holding a lock on the resource. Try again later" ));
76
+ return ;
77
+ }
78
+ try {
79
+ internalDoExecute (request , lock , listener );
80
+ } catch (Exception e ) {
81
+ listener .onFailure (e );
82
+ } finally {
83
+ lockService .releaseLock (
84
+ lock ,
85
+ ActionListener .wrap (released -> {}, exception -> log .error ("Failed to release the lock" , exception ))
86
+ );
87
+ }
88
+ }, exception -> { listener .onFailure (exception ); }));
71
89
}
72
90
73
91
@ VisibleForTesting
74
- protected void putDatasource (final PutDatasourceRequest request , final ActionListener <AcknowledgedResponse > listener )
75
- throws IOException {
76
- Datasource datasource = Datasource .Builder .build (request );
77
- datasourceFacade .putDatasource (datasource , getIndexResponseListener (datasource , listener ));
92
+ protected void internalDoExecute (
93
+ final PutDatasourceRequest request ,
94
+ final LockModel lock ,
95
+ final ActionListener <AcknowledgedResponse > listener
96
+ ) {
97
+ StepListener <Void > createIndexStep = new StepListener <>();
98
+ datasourceFacade .createIndexIfNotExists (createIndexStep );
99
+ createIndexStep .whenComplete (v -> {
100
+ Datasource datasource = Datasource .Builder .build (request );
101
+ datasourceFacade .putDatasource (
102
+ datasource ,
103
+ getIndexResponseListener (datasource , lockService .getRenewLockRunnable (new AtomicReference <>(lock )), listener )
104
+ );
105
+ }, exception -> listener .onFailure (exception ));
78
106
}
79
107
80
108
@ VisibleForTesting
81
109
protected ActionListener <IndexResponse > getIndexResponseListener (
82
110
final Datasource datasource ,
111
+ final Runnable renewLock ,
83
112
final ActionListener <AcknowledgedResponse > listener
84
113
) {
85
114
return new ActionListener <>() {
86
115
@ Override
87
116
public void onResponse (final IndexResponse indexResponse ) {
88
117
// This is user initiated request. Therefore, we want to handle the first datasource update task in a generic thread
89
118
// pool.
90
- threadPool .generic ().submit (() -> { createDatasource (datasource ); });
119
+ threadPool .generic ().submit (() -> { createDatasource (datasource , renewLock ); });
91
120
listener .onResponse (new AcknowledgedResponse (true ));
92
121
}
93
122
@@ -103,15 +132,15 @@ public void onFailure(final Exception e) {
103
132
}
104
133
105
134
@ VisibleForTesting
106
- protected void createDatasource (final Datasource datasource ) {
135
+ protected void createDatasource (final Datasource datasource , final Runnable renewLock ) {
107
136
if (DatasourceState .CREATING .equals (datasource .getState ()) == false ) {
108
137
log .error ("Invalid datasource state. Expecting {} but received {}" , DatasourceState .CREATING , datasource .getState ());
109
138
markDatasourceAsCreateFailed (datasource );
110
139
return ;
111
140
}
112
141
113
142
try {
114
- datasourceUpdateService .updateOrCreateGeoIpData (datasource );
143
+ datasourceUpdateService .updateOrCreateGeoIpData (datasource , renewLock );
115
144
} catch (Exception e ) {
116
145
log .error ("Failed to create datasource for {}" , datasource .getName (), e );
117
146
markDatasourceAsCreateFailed (datasource );
0 commit comments