Skip to content

Commit b176a7c

Browse files
authored
Merge pull request #116 from MobilityFirst/sanity_check_config
Configurable sanity check before request update
2 parents ca9b891 + a568501 commit b176a7c

9 files changed

Lines changed: 191 additions & 12 deletions

File tree

build.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#Sat, 18 Feb 2017 17:11:23 -0500
1+
#Sun, 28 May 2017 23:06:01 +0530
22
build.major.number=1
33
build.minor.number=19
4-
build.revision.number=13
4+
build.revision.number=15

src/edu/umass/cs/gnscommon/GNSProtocol.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,12 @@ public enum GNSProtocol {
541541
/**
542542
* Whether an internal request was previously coordinated (at most once).
543543
*/
544-
COORD1("COORD1"),;
544+
COORD1("COORD1"),
545+
/**
546+
* Indicates that sanity check failed
547+
* See {@link edu.umass.cs.gnscommon.ResponseCode#SANITY_CHECK_ERROR}.
548+
*/
549+
SANITY_CHECK_ERROR("+SANITY_CHECK_ERROR+"),;
545550

546551
final String label;
547552

src/edu/umass/cs/gnscommon/ResponseCode.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,11 @@ public enum ResponseCode implements Serializable {
231231
* IO exception incurred either by the client or by an induced remote query.
232232
*/
233233
IO_EXCEPTION(412, IOException.class.getSimpleName(),
234-
ResponseCodeType.EXCEPTION)
234+
ResponseCodeType.EXCEPTION),
235+
/*
236+
* Sanity check on a record failed.
237+
*/
238+
SANITY_CHECK_ERROR(413, GNSProtocol.SANITY_CHECK_ERROR.toString(), ResponseCodeType.ERROR)
235239

236240
;
237241

src/edu/umass/cs/gnsserver/database/DiskMapRecords.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.logging.Level;
1717
import java.util.logging.Logger;
1818

19+
import com.mongodb.BulkWriteException;
1920
import org.json.JSONArray;
2021
import org.json.JSONException;
2122
import org.json.JSONObject;
@@ -361,45 +362,54 @@ record = lookupEntireRecord(collection, name);
361362

362363
@Override
363364
public AbstractRecordCursor getAllRowsIterator(String collection) throws FailedDBOperationException {
364-
getMap(collection).commit();
365+
commit(collection);
365366
return getMongoRecords(collection).getAllRowsIterator(MongoRecords.DBNAMERECORD);
366367
}
367368

368369
@Override
369370
public AbstractRecordCursor selectRecords(String collection, ColumnField valuesMapField, String key, Object value) throws FailedDBOperationException {
370-
getMap(collection).commit();
371+
commit(collection);
371372
return getMongoRecords(collection).selectRecords(MongoRecords.DBNAMERECORD, valuesMapField, key, value);
372373
}
373374

374375
@Override
375376
public AbstractRecordCursor selectRecordsWithin(String collection, ColumnField valuesMapField, String key, String value) throws FailedDBOperationException {
376-
getMap(collection).commit();
377+
commit(collection);
377378
return getMongoRecords(collection).selectRecordsWithin(MongoRecords.DBNAMERECORD, valuesMapField, key, value);
378379
}
379380

380381
@Override
381382
public AbstractRecordCursor selectRecordsNear(String collection, ColumnField valuesMapField, String key, String value, Double maxDistance) throws FailedDBOperationException {
382-
getMap(collection).commit();
383+
commit(collection);
383384
return getMongoRecords(collection).selectRecordsNear(MongoRecords.DBNAMERECORD, valuesMapField, key, value, maxDistance);
384385
}
385386

386387
@Override
387388
public AbstractRecordCursor selectRecordsQuery(String collection, ColumnField valuesMapField,
388389
String query, List<String> projection) throws FailedDBOperationException {
389-
getMap(collection).commit();
390+
commit(collection);
390391
return getMongoRecords(collection).selectRecordsQuery(MongoRecords.DBNAMERECORD, valuesMapField,
391392
query, projection);
392393
}
393394

394395
@Override
395396
public void createIndex(String collection, String field, String index) {
396-
getMap(collection).commit();
397+
commit(collection);
397398
getMongoRecords(collection).createIndex(MongoRecords.DBNAMERECORD, field, index);
398399
}
399400

400401
@Override
401402
public void printAllEntries(String collection) throws FailedDBOperationException {
402-
getMap(collection).commit();
403+
commit(collection);
403404
getMongoRecords(collection).printAllEntries(MongoRecords.DBNAMERECORD);
404405
}
406+
407+
private void commit(String collection) {
408+
try{
409+
getMap(collection).commit();
410+
} catch (BulkWriteException e) {
411+
LOGGER.log(Level.WARNING, "Caught {e}, ignoring and proceeding: {1}", new Object[]{e.getClass().getSimpleName(), e.getMessage()});
412+
}
413+
414+
}
405415
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
*
3+
* Copyright (c) 2015 University of Massachusetts
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you
6+
* may not use this file except in compliance with the License. You
7+
* may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14+
* implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*
17+
* Initial developer(s): Karthik A.
18+
*
19+
*/
20+
21+
package edu.umass.cs.gnsserver.extensions.sanitycheck;
22+
23+
import edu.umass.cs.gigapaxos.interfaces.Request;
24+
import edu.umass.cs.reconfiguration.reconfigurationutils.RequestParseException;
25+
26+
public abstract class AbstractSanityCheck {
27+
28+
public abstract void check(Request request) throws RequestParseException;
29+
30+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
*
3+
* Copyright (c) 2015 University of Massachusetts
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you
6+
* may not use this file except in compliance with the License. You
7+
* may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14+
* implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*
17+
* Initial developer(s): Karthik A.
18+
*
19+
*/
20+
21+
package edu.umass.cs.gnsserver.extensions.sanitycheck;
22+
23+
import edu.umass.cs.gigapaxos.interfaces.Request;
24+
import edu.umass.cs.gnscommon.CommandType;
25+
import edu.umass.cs.gnscommon.GNSProtocol;
26+
import edu.umass.cs.reconfiguration.reconfigurationutils.RequestParseException;
27+
import org.json.JSONArray;
28+
import org.json.JSONException;
29+
import org.json.JSONObject;
30+
31+
/* This is an implementation of sanity checker */
32+
public class GeoSanityCheck extends AbstractSanityCheck {
33+
34+
@Override
35+
public void check(Request request) throws RequestParseException {
36+
37+
try {
38+
JSONObject requestJSON = new JSONObject(request.toString());
39+
JSONObject commandQuery = requestJSON.getJSONObject(GNSProtocol.COMMAND_QUERY.toString());
40+
41+
if (commandQuery.has(GNSProtocol.COMMAND_INT.toString()) &&
42+
commandQuery.getInt(GNSProtocol.COMMAND_INT.toString()) == CommandType.ReplaceUserJSON.getInt()) {
43+
JSONObject userJSON = new JSONObject(commandQuery.getString(GNSProtocol.USER_JSON.toString()));
44+
if (userJSON.has(GNSProtocol.LOCATION_FIELD_NAME_2D_SPHERE.toString())) {
45+
JSONObject geoLocCurrent = userJSON.getJSONObject(GNSProtocol.LOCATION_FIELD_NAME_2D_SPHERE.toString());
46+
if (geoLocCurrent.has("coordinates")) {
47+
JSONArray coordinates = geoLocCurrent.getJSONArray("coordinates");
48+
if(coordinates.get(0).getClass().equals(String.class) || coordinates.get(1).getClass().equals(String.class)) {
49+
throw new RequestParseException(new Exception("Numeric value expected for location coordinates, string provided"));
50+
}
51+
}
52+
}
53+
}
54+
55+
} catch (JSONException e) {
56+
//Pass
57+
}
58+
}
59+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
*
3+
* Copyright (c) 2015 University of Massachusetts
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you
6+
* may not use this file except in compliance with the License. You
7+
* may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14+
* implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*
17+
* Initial developer(s): Karthik A.
18+
*
19+
*/
20+
21+
package edu.umass.cs.gnsserver.extensions.sanitycheck;
22+
23+
import edu.umass.cs.gigapaxos.interfaces.Request;
24+
import edu.umass.cs.reconfiguration.reconfigurationutils.RequestParseException;
25+
26+
public class NullSanityCheck extends AbstractSanityCheck {
27+
28+
public void check(Request request) throws RequestParseException {
29+
30+
}
31+
32+
}

src/edu/umass/cs/gnsserver/gnsapp/GNSApp.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import edu.umass.cs.gigapaxos.interfaces.Replicable;
2424
import edu.umass.cs.gigapaxos.interfaces.Request;
2525
import edu.umass.cs.gigapaxos.interfaces.RequestIdentifier;
26+
import edu.umass.cs.gnscommon.GNSProtocol;
27+
import edu.umass.cs.gnscommon.ResponseCode;
2628
import edu.umass.cs.gnscommon.exceptions.client.ClientException;
2729
import edu.umass.cs.gnsserver.activecode.ActiveCodeHandler;
2830
import edu.umass.cs.gnsserver.database.ColumnField;
@@ -36,6 +38,7 @@
3638
import edu.umass.cs.gnscommon.packets.CommandPacket;
3739
import edu.umass.cs.gnscommon.packets.ResponsePacket;
3840
import edu.umass.cs.gnsserver.database.NoSQLRecords;
41+
import edu.umass.cs.gnsserver.extensions.sanitycheck.AbstractSanityCheck;
3942
import edu.umass.cs.gnsserver.main.GNSConfig;
4043
import edu.umass.cs.gnsserver.gnsapp.clientCommandProcessor.ClientRequestHandlerInterface;
4144

@@ -170,6 +173,17 @@ private static boolean enqueueCommand() {
170173
*/
171174
private AppAdminServer appAdminServer = null;
172175

176+
private static AbstractSanityCheck sanityCheck;
177+
178+
static {
179+
try {
180+
sanityCheck = (AbstractSanityCheck) Class.forName(Config.getGlobalString(GNSConfig.GNSC.SANITY_CHECKER)).newInstance();
181+
} catch (ClassNotFoundException|InstantiationException|IllegalAccessException e) {
182+
GNSConfig.getLogger().log(Level.SEVERE, "Error instantiating sanity checker class: {0}", e.getMessage());
183+
}
184+
185+
}
186+
173187
/**
174188
* Constructor invoked via reflection by gigapaxos.
175189
*
@@ -283,6 +297,24 @@ public boolean execute(Request request, boolean doNotReplyToClient) {
283297
+ RequestIdentifier.class;
284298
}
285299

300+
try {
301+
if (sanityCheck != null) {
302+
sanityCheck.check(request);
303+
} else {
304+
GNSConfig.getLogger().log(Level.FINE, "Sanity checker has not been instantiated, skipping check");
305+
}
306+
} catch (RequestParseException e) {
307+
//Malformed request, log and skip execution returning an error
308+
GNSConfig.getLogger().log(Level.WARNING, "Sanity check caught malformed request: {0}", e.getMessage());
309+
((BasicPacketWithClientAddress) request)
310+
.setResponse(new ResponsePacket(request.getServiceName(),
311+
((RequestIdentifier) request).getRequestID(),
312+
ResponseCode.SANITY_CHECK_ERROR,
313+
GNSProtocol.BAD_RESPONSE.toString() + " " + GNSProtocol.SANITY_CHECK_ERROR + " " + e.getMessage()));
314+
return true;
315+
}
316+
317+
286318
switch (packetType) {
287319
case SELECT_REQUEST:
288320
Select.handleSelectRequest((SelectRequestPacket) request, this);

src/edu/umass/cs/gnsserver/main/GNSConfig.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.logging.Logger;
3333

3434
import edu.umass.cs.gnsclient.client.GNSClientConfig;
35+
import edu.umass.cs.gnsserver.extensions.sanitycheck.NullSanityCheck;
3536
import edu.umass.cs.utils.Config;
3637

3738
/**
@@ -248,7 +249,13 @@ public static enum GNSC implements Config.ConfigurableEnum,
248249
* Turn off active code handling. Default is true.
249250
* Temporary - The use of this will go away at some point.
250251
*/
251-
DISABLE_ACTIVE_CODE(true);
252+
DISABLE_ACTIVE_CODE(true),
253+
/**
254+
* The class name to use for doing sanity checks while updating GNS
255+
* record. Must extend {@link edu.umass.cs.gnsserver.extensions.sanitycheck.AbstractSanityCheck}
256+
*/
257+
SANITY_CHECKER(NullSanityCheck.class.getName())
258+
;
252259

253260
final Object defaultValue;
254261
final boolean unsafeTestingOnly;

0 commit comments

Comments
 (0)