@@ -14,14 +14,16 @@ import java.time.Instant
1414
1515interface StateManager {
1616 fun init ()
17- fun lockStatement (runId : String , statementId : String ): Boolean
18- fun pingLockStatement (runId : String , statementId : String ): Boolean
19- fun unlockStatemnt (runId : String , statementId : String )
20- fun writeStateForStatement (runId : String , statementId : String , lastRunStart : Instant , status : String , lastRowCount : Long , errMsg : String? = null)
21- fun readStateForStatement (runId : String , statementId : String ): Instant ?
22- fun logStatement (runId : String , statementId : String , lastRunStart : Instant , status : String , rowCount : Long , errMsg : String? = null)
17+ fun lockStatement (runId : String , statement : EsImportStatement ): Boolean
18+ fun pingLockStatement (runId : String , statement : EsImportStatement ): Boolean
19+ fun unlockStatemnt (runId : String , statement : EsImportStatement )
20+ fun writeStateForStatement (runId : String , statement : EsImportStatement , lastRunStart : Instant , status : String , lastRowCount : Long , errMsg : String? = null)
21+ fun readStateForStatement (runId : String , statement : EsImportStatement ): Instant ?
22+ fun logStatement (runId : String , statement : EsImportStatement , lastRunStart : Instant , status : String , rowCount : Long , errMsg : String? = null)
2323}
2424
25+ private fun EsImportStatement.stateKey (): String = this .indexName + " -" + this .id
26+
2527// TODO: better state management
2628// This is NOT using the ES client because we do not want conflicts with Spark dependencies
2729class ElasticSearchStateManager (val nodes : List <String >, val auth : AuthInfo ? ) : StateManager {
@@ -32,7 +34,7 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
3234 configure(SerializationFeature .WRITE_DATES_AS_TIMESTAMPS , true )
3335 configure(DeserializationFeature .READ_DATE_TIMESTAMPS_AS_NANOSECONDS , false )
3436 }
35- val STATE_INDEX = " .kohesive-dih-state"
37+ val STATE_INDEX = " .kohesive-dih-state-v2 "
3638
3739 private fun OkHttpClient.get (url : String ): Pair <Int , String > {
3840 val request = Request .Builder ().url(url).build()
@@ -98,6 +100,7 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
98100 "mappings": {
99101 "state": {
100102 "properties": {
103+ "targetIndex": { "type": "keyword" },
101104 "statementId": { "type": "keyword" },
102105 "lastRunDate": { "type": "date" },
103106 "status": { "type": "keyword" },
@@ -108,6 +111,7 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
108111 },
109112 "log": {
110113 "properties": {
114+ "targetIndex": { "type": "keyword" },
111115 "statementId": { "type": "keyword" },
112116 "runId": { "type": "keyword" },
113117 "runDate": { "type": "date" },
@@ -118,6 +122,7 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
118122 },
119123 "lock": {
120124 "properties": {
125+ "targetIndex": { "type": "keyword" },
121126 "statementId": { "type": "keyword" },
122127 "runId": { "type": "keyword" },
123128 "lockDate": { "type": "date" }
@@ -137,7 +142,7 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
137142 ttlKillOldLocks()
138143 }
139144
140- data class Lock (val runId : String , val statementId : String , val lockDate : Instant )
145+ data class Lock (val runId : String , val targetIndex : String , val statementId : String , val lockDate : Instant )
141146
142147 fun makeUrl (index : String , type : String ) = " $url /$index /$type "
143148 fun makeUrl (type : String ) = makeUrl(STATE_INDEX , type)
@@ -151,19 +156,19 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
151156 if (! delCode.isSuccess()) throw DataImportException (" State manager failed, TTL delete query for locks failed\n $response " )
152157 }
153158
154- override fun lockStatement (runId : String , statementId : String ): Boolean {
155- val lockUrl = " ${makeUrl(" lock" )} /${statementId } "
156- val (code, response) = http.post(" $lockUrl ?op_type=create" , JSON .writeValueAsString(Lock (runId, statementId , Instant .now())))
159+ override fun lockStatement (runId : String , statement : EsImportStatement ): Boolean {
160+ val lockUrl = " ${makeUrl(" lock" )} /${statement.stateKey() } "
161+ val (code, response) = http.post(" $lockUrl ?op_type=create" , JSON .writeValueAsString(Lock (runId, statement.indexName, statement.id , Instant .now())))
157162
158163 if (! code.isSuccess()) {
159164 ttlKillOldLocks()
160- return pingLockStatement(runId, statementId )
165+ return pingLockStatement(runId, statement )
161166 }
162167 return true
163168 }
164169
165- override fun pingLockStatement (runId : String , statementId : String ): Boolean {
166- val lockUrl = " ${makeUrl(" lock" )} /${statementId } "
170+ override fun pingLockStatement (runId : String , statement : EsImportStatement ): Boolean {
171+ val lockUrl = " ${makeUrl(" lock" )} /${statement.stateKey() } "
167172 val (getCode, response) = http.get(lockUrl)
168173 if (getCode.isSuccess()) {
169174 val lock = mapFromSource<Lock >(response)
@@ -179,45 +184,47 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
179184 "bool": {
180185 "must": [
181186 { "term": { "runId": "$runId " } },
182- { "term": { "statementId": "$statementId " } }
187+ { "term": { "targetIndex": "${statement.indexName} " } },
188+ { "term": { "statementId": "${statement.id} " } }
183189 ]
184190 }
185191 }
186192 }
187193 """ )
188194 if (! updCode.isSuccess()) {
189- throw DataImportException (" State manager failed, cannot acquire lock for $statementId - had conflict on pinging of lock\n $updResponse " )
195+ throw DataImportException (" State manager failed, cannot acquire lock for ${statement.stateKey()} - had conflict on pinging of lock\n $updResponse " )
190196 }
191197 } else {
192- throw DataImportException (" State manager failed, cannot acquire lock for $statementId -- it is held by ${lock.runId} since ${lock.lockDate.toIsoString()} \n $response " )
198+ throw DataImportException (" State manager failed, cannot acquire lock for ${statement.stateKey()} -- it is held by ${lock.runId} since ${lock.lockDate.toIsoString()} \n $response " )
193199 }
194200 }
195201 return true
196202 }
197203
198- override fun unlockStatemnt (runId : String , statementId : String ) {
199- if (pingLockStatement(runId, statementId )) {
200- val lockUrl = " ${makeUrl(" lock" )} /${statementId } ?refresh"
204+ override fun unlockStatemnt (runId : String , statement : EsImportStatement ) {
205+ if (pingLockStatement(runId, statement )) {
206+ val lockUrl = " ${makeUrl(" lock" )} /${statement.stateKey() } ?refresh"
201207 val (code, response) = http.delete(lockUrl)
202208 if (! code.isSuccess()) {
203- throw DataImportException (" State manager failed, cannot delete lock for $statementId \n $response " )
209+ throw DataImportException (" State manager failed, cannot delete lock for ${statement.stateKey()} \n $response " )
204210 }
205211 }
206212 }
207213
208- data class State (val statementId : String , val lastRunDate : Instant , val status : String , val lastRunId : String , val lastErrorMesasge : String? , val lastRowCount : Long )
214+ data class State (val targetIndex : String , val statementId : String , val lastRunDate : Instant , val status : String , val lastRunId : String , val lastErrorMesasge : String? , val lastRowCount : Long )
209215
210- data class StateLog (val statementId : String , val runId : String , val runDate : Instant , val status : String , val errorMsg : String? , val rowCount : Long )
216+ data class StateLog (val targetIndex : String , val statementId : String , val runId : String , val runDate : Instant , val status : String , val errorMsg : String? , val rowCount : Long )
211217
212- override fun writeStateForStatement (runId : String , statementId : String , lastRunStart : Instant , status : String , lastRowCount : Long , errMsg : String? ) {
213- val (code, response) = http.post(" ${makeUrl(" state" )} /${statementId} ?refresh" , JSON .writeValueAsString(State (statementId, lastRunStart, status, runId, errMsg, lastRowCount)))
218+ override fun writeStateForStatement (runId : String , statement : EsImportStatement , lastRunStart : Instant , status : String , lastRowCount : Long , errMsg : String? ) {
219+ val (code, response) = http.post(" ${makeUrl(" state" )} /${statement.stateKey()} ?refresh" ,
220+ JSON .writeValueAsString(State (statement.indexName, statement.id, lastRunStart, status, runId, errMsg, lastRowCount)))
214221 if (! code.isSuccess()) {
215- throw DataImportException (" State manager failed, cannot update state for $statementId \n $response " )
222+ throw DataImportException (" State manager failed, cannot update state for ${statement.stateKey()} \n $response " )
216223 }
217224 }
218225
219- override fun readStateForStatement (runId : String , statementId : String ): Instant ? {
220- val (code, response) = http.get(" ${makeUrl(" state" )} /${statementId } " )
226+ override fun readStateForStatement (runId : String , statement : EsImportStatement ): Instant ? {
227+ val (code, response) = http.get(" ${makeUrl(" state" )} /${statement.stateKey() } " )
221228 if (code.isSuccess()) {
222229 val state = mapFromSource<State >(response)
223230 return state.lastRunDate
@@ -226,10 +233,11 @@ class ElasticSearchStateManager(val nodes: List<String>, val auth: AuthInfo?) :
226233 }
227234 }
228235
229- override fun logStatement (runId : String , statementId : String , lastRunStart : Instant , status : String , rowCount : Long , errMsg : String? ) {
230- val (code, response) = http.post(" ${makeUrl(" log" )} /${statementId} _run_${runId} ?refresh" , JSON .writeValueAsString(StateLog (statementId, runId, lastRunStart, status, errMsg, rowCount)))
236+ override fun logStatement (runId : String , statement : EsImportStatement , lastRunStart : Instant , status : String , rowCount : Long , errMsg : String? ) {
237+ val (code, response) = http.post(" ${makeUrl(" log" )} /${statement.stateKey()} _run_${runId} ?refresh" ,
238+ JSON .writeValueAsString(StateLog (statement.indexName, statement.id, runId, lastRunStart, status, errMsg, rowCount)))
231239 if (! code.isSuccess()) {
232- throw DataImportException (" State manager failed, cannot log state for $statementId \n $response " )
240+ throw DataImportException (" State manager failed, cannot log state for ${statement.stateKey()} \n $response " )
233241 }
234242 }
235243}
0 commit comments