@@ -174,7 +174,7 @@ private bool NetworkEXPIRE<TGarnetApi>(RespCommand command, ref TGarnetApi stora
174
174
where TGarnetApi : IGarnetApi
175
175
{
176
176
var count = parseState . Count ;
177
- if ( count < 2 || count > 3 )
177
+ if ( count < 2 || count > 4 )
178
178
{
179
179
return AbortWithWrongNumberOfArguments ( nameof ( RespCommand . EXPIRE ) ) ;
180
180
}
@@ -205,6 +205,36 @@ private bool NetworkEXPIRE<TGarnetApi>(RespCommand command, ref TGarnetApi stora
205
205
}
206
206
}
207
207
208
+ if ( parseState . Count > 3 )
209
+ {
210
+ if ( ! TryGetExpireOption ( parseState . GetArgSliceByRef ( 3 ) . ReadOnlySpan , out var additionExpireOption ) )
211
+ {
212
+ var optionStr = parseState . GetString ( 3 ) ;
213
+
214
+ while ( ! RespWriteUtils . WriteError ( $ "ERR Unsupported option { optionStr } ", ref dcurr , dend ) )
215
+ SendAndReset ( ) ;
216
+ return true ;
217
+ }
218
+
219
+ if ( expireOption == ExpireOption . XX && ( additionExpireOption == ExpireOption . GT || additionExpireOption == ExpireOption . LT ) )
220
+ {
221
+ expireOption = ExpireOption . XX | additionExpireOption ;
222
+ }
223
+ else if ( expireOption == ExpireOption . GT && additionExpireOption == ExpireOption . XX )
224
+ {
225
+ expireOption = ExpireOption . XXGT ;
226
+ }
227
+ else if ( expireOption == ExpireOption . LT && additionExpireOption == ExpireOption . XX )
228
+ {
229
+ expireOption = ExpireOption . XXLT ;
230
+ }
231
+ else
232
+ {
233
+ while ( ! RespWriteUtils . WriteError ( "ERR NX and XX, GT or LT options at the same time are not compatible" , ref dcurr , dend ) )
234
+ SendAndReset ( ) ;
235
+ }
236
+ }
237
+
208
238
var status = command == RespCommand . EXPIRE ?
209
239
storageApi . EXPIRE ( key , expiryMs , out var timeoutSet , StoreType . All , expireOption ) :
210
240
storageApi . PEXPIRE ( key , expiryMs , out timeoutSet , StoreType . All , expireOption ) ;
@@ -223,6 +253,92 @@ private bool NetworkEXPIRE<TGarnetApi>(RespCommand command, ref TGarnetApi stora
223
253
return true ;
224
254
}
225
255
256
+ /// <summary>
257
+ /// Set a timeout on a key based on unix timestamp
258
+ /// </summary>
259
+ /// <typeparam name="TGarnetApi"></typeparam>
260
+ /// <param name="command">Indicates which command to use, expire or pexpire.</param>
261
+ /// <param name="storageApi"></param>
262
+ /// <returns></returns>
263
+ private bool NetworkEXPIREAT < TGarnetApi > ( RespCommand command , ref TGarnetApi storageApi )
264
+ where TGarnetApi : IGarnetApi
265
+ {
266
+ var count = parseState . Count ;
267
+ if ( count < 2 || count > 4 )
268
+ {
269
+ return AbortWithWrongNumberOfArguments ( nameof ( RespCommand . EXPIREAT ) ) ;
270
+ }
271
+
272
+ var key = parseState . GetArgSliceByRef ( 0 ) ;
273
+ if ( ! parseState . TryGetLong ( 1 , out var expiryTimestamp ) )
274
+ {
275
+ while ( ! RespWriteUtils . WriteError ( CmdStrings . RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER , ref dcurr , dend ) )
276
+ SendAndReset ( ) ;
277
+ return true ;
278
+ }
279
+
280
+ var expireOption = ExpireOption . None ;
281
+
282
+ if ( parseState . Count > 2 )
283
+ {
284
+ if ( ! TryGetExpireOption ( parseState . GetArgSliceByRef ( 2 ) . ReadOnlySpan , out expireOption ) )
285
+ {
286
+ var optionStr = parseState . GetString ( 2 ) ;
287
+
288
+ while ( ! RespWriteUtils . WriteError ( $ "ERR Unsupported option { optionStr } ", ref dcurr , dend ) )
289
+ SendAndReset ( ) ;
290
+ return true ;
291
+ }
292
+ }
293
+
294
+ if ( parseState . Count > 3 )
295
+ {
296
+ if ( ! TryGetExpireOption ( parseState . GetArgSliceByRef ( 3 ) . ReadOnlySpan , out var additionExpireOption ) )
297
+ {
298
+ var optionStr = parseState . GetString ( 3 ) ;
299
+
300
+ while ( ! RespWriteUtils . WriteError ( $ "ERR Unsupported option { optionStr } ", ref dcurr , dend ) )
301
+ SendAndReset ( ) ;
302
+ return true ;
303
+ }
304
+
305
+ if ( expireOption == ExpireOption . XX && ( additionExpireOption == ExpireOption . GT || additionExpireOption == ExpireOption . LT ) )
306
+ {
307
+ expireOption = ExpireOption . XX | additionExpireOption ;
308
+ }
309
+ else if ( expireOption == ExpireOption . GT && additionExpireOption == ExpireOption . XX )
310
+ {
311
+ expireOption = ExpireOption . XXGT ;
312
+ }
313
+ else if ( expireOption == ExpireOption . LT && additionExpireOption == ExpireOption . XX )
314
+ {
315
+ expireOption = ExpireOption . XXLT ;
316
+ }
317
+ else
318
+ {
319
+ while ( ! RespWriteUtils . WriteError ( "ERR NX and XX, GT or LT options at the same time are not compatible" , ref dcurr , dend ) )
320
+ SendAndReset ( ) ;
321
+ }
322
+ }
323
+
324
+ var status = command == RespCommand . EXPIREAT ?
325
+ storageApi . EXPIREAT ( key , expiryTimestamp , out var timeoutSet , StoreType . All , expireOption ) :
326
+ storageApi . PEXPIREAT ( key , expiryTimestamp , out timeoutSet , StoreType . All , expireOption ) ;
327
+
328
+ if ( status == GarnetStatus . OK && timeoutSet )
329
+ {
330
+ while ( ! RespWriteUtils . WriteDirect ( CmdStrings . RESP_RETURN_VAL_1 , ref dcurr , dend ) )
331
+ SendAndReset ( ) ;
332
+ }
333
+ else
334
+ {
335
+ while ( ! RespWriteUtils . WriteDirect ( CmdStrings . RESP_RETURN_VAL_0 , ref dcurr , dend ) )
336
+ SendAndReset ( ) ;
337
+ }
338
+
339
+ return true ;
340
+ }
341
+
226
342
/// <summary>
227
343
/// PERSIST command
228
344
/// </summary>
0 commit comments