use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.
the class CouchDbPacketSaver method handle.
@Override
public void handle(PacketCollection packetCollection) throws PacketHandleException {
// Normally we would try and create the database, but that doesn't work with non-admin cookie authenticated users
String id = packetCollection.getDbId();
String revision = idMap == null ? null : idMap.get(id);
final JsonData jsonData;
try {
jsonData = new StringJsonData(MAPPER.writeValueAsString(packetCollection));
} catch (JsonProcessingException e) {
throw new RuntimeException("Cannot serialize packet collection! This is bad!", e);
}
try {
final DocumentResponse response;
if (revision == null) {
response = database.putDocument(id, jsonData);
} else {
response = database.updateDocument(id, revision, jsonData);
}
LOGGER.debug("Now revision is: " + response.getRev() + ". It was: " + revision);
if (idMap != null) {
// Currently, if we have a new document ID, we never, ever, need to worry about using an older document ID, so we can clear the map to avoid keeping unnecessary memory
idMap.clear();
idMap.put(id, response.getRev());
}
} catch (CouchDbNotFoundException ex) {
throw new PacketHandleException("Got 'not found'. Does the database exist? Make sure to run the couchdb-setup!", ex);
} catch (CouchDbUpdateConflictException ex) {
if (idMap == null) {
// we are ignoring conflicts
LOGGER.debug("Got update conflict exception. Ignoring...");
return;
}
try {
String actualRev = database.getCurrentRevision(id);
idMap.put(id, actualRev);
LOGGER.debug("We were able to get the actual Revision ID for id=" + id + " actual rev=" + actualRev);
} catch (CouchDbException revEx) {
LOGGER.debug("Unable to get the actual Revision ID for id=" + id, revEx);
}
throw new PacketHandleException("Conflict while saving something to couchdb. id=" + id + " rev=" + revision + ". This usually means we put a packet in the database, but we weren't able to cache its rev id.", ex);
} catch (CouchDbException ex) {
if (ex.getCause() instanceof IOException) {
throw new PacketHandleException("We got a DbAccessException probably meaning we couldn't reach the database.", ex);
} else {
throw new PacketHandleException("Got a DbAccessException without IOException as a cause. Something must be wrong.", ex);
}
}
}
use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.
the class CacheHandler method queryOrCalculateCaches.
private <T extends CacheDataPacket> List<T> queryOrCalculateCaches(TypeReference<T> typeReference, String cacheName, String sourceId, long startPeriodNumber, long endPeriodNumber) {
// the document IDs needed to return data
List<String> documentIds = new ArrayList<>();
// a map from a document ID to a period number
Map<String, Long> documentIdPeriodNumberMap = new HashMap<>();
for (long periodNumber = startPeriodNumber; periodNumber <= endPeriodNumber; periodNumber++) {
Instant periodStart = getPeriodStartFromNumber(periodNumber);
String documentId = CacheUtil.getDocumentId(periodStart, duration, sourceId, cacheName);
documentIds.add(documentId);
documentIdPeriodNumberMap.put(documentId, periodNumber);
}
BulkGetRequest request = BulkGetRequest.from(documentIds);
final BulkGetResponse response;
try {
response = cacheDatabase.getDocumentsBulk(request);
} catch (CouchDbException e) {
throw new DatabaseException("CouchDB exception | message: " + e.getMessage(), e);
}
// map for documents that need to be updated. The value represents the revision that needs to be used to update it
Map<String, String> documentIdRevisionMapForUpdate = new HashMap<>();
// Map for period number -> cached data. This helps us make sure we only return a single piece of data for each period
Map<Long, T> periodNumberPacketMap = new TreeMap<>();
// Set for document IDs that we already have and do not need to be updated
Set<String> doNotUpdateDocumentIdsSet = new HashSet<>();
Long queryStartPeriodNumber = null;
Long queryEndPeriodNumber = null;
for (BulkGetResponse.Result result : response.getResults()) {
if (result.hasConflicts()) {
// replication going on with their databases.
throw new UnexpectedResponseException("cache document with conflict! doc id: " + result.getDocumentId());
}
Long periodNumber = documentIdPeriodNumberMap.get(result.getDocumentId());
if (periodNumber == null) {
throw new IllegalStateException("Could not get period number for doc id: " + result.getDocumentId() + ". This should never happen.");
}
T value = null;
if (!result.isError()) {
JsonData jsonData = result.getJsonDataAssertNotConflicted();
try {
value = CouchDbJacksonUtil.readValue(mapper, jsonData, typeReference);
if (value.getSourceId().equals(sourceId) && value.getCacheName().equals(cacheName)) {
periodNumberPacketMap.put(periodNumber, value);
}
doNotUpdateDocumentIdsSet.add(value.getDbId());
} catch (JsonProcessingException ex) {
// If we are in this catch block, one of two things has happened:
// The JSON is invalid (unlikely), we updated how a given cache is serialized/deserialized, or we're dumb and never tested to see if the deserialization works.
// If the JSON is actually invalid, getRevisionFromJsonData will throw an exception. Otherwise, we need to calculate the given cache again
String revision = getRevisionFromJsonData(jsonData);
documentIdRevisionMapForUpdate.put(result.getDocumentId(), revision);
}
}
if (value == null) {
if (queryStartPeriodNumber == null) {
queryStartPeriodNumber = periodNumber;
queryEndPeriodNumber = periodNumber;
} else {
queryStartPeriodNumber = Math.min(queryStartPeriodNumber, periodNumber);
queryEndPeriodNumber = Math.max(queryEndPeriodNumber, periodNumber);
}
}
}
if (queryStartPeriodNumber != null) {
List<CacheDataPacket> calculatedPackets = calculatePeriod(queryStartPeriodNumber, queryEndPeriodNumber);
List<JsonData> calculatedPacketsJsonDataList = new ArrayList<>();
int updateAttemptCount = 0;
for (CacheDataPacket packet : calculatedPackets) {
if (doNotUpdateDocumentIdsSet.contains(packet.getDbId())) {
continue;
}
if (!sourceId.equals(packet.getSourceId()) || !cacheName.equals(packet.getCacheName())) {
// This is the same with different cache names, we don't know which ones we need to update and which ones we cannot
continue;
}
JsonData json;
try {
String revision = documentIdRevisionMapForUpdate.get(packet.getDbId());
if (revision == null) {
json = new StringJsonData(mapper.writeValueAsString(packet));
} else {
json = new StringJsonData(mapper.writeValueAsString(new DocumentRevisionWrapper(revision, packet)));
updateAttemptCount++;
}
} catch (JsonProcessingException e) {
throw new RuntimeException("Should be able to serialize!", e);
}
calculatedPacketsJsonDataList.add(json);
}
final List<BulkDocumentResponse> postResponse;
try {
postResponse = cacheDatabase.postDocumentsBulk(new BulkPostRequest(calculatedPacketsJsonDataList));
} catch (CouchDbException e) {
throw new DatabaseException("Could not update cache", e);
}
int successCount = 0;
int failCount = 0;
for (BulkDocumentResponse documentResponse : postResponse) {
if (documentResponse.isOk()) {
successCount++;
} else {
failCount++;
LOGGER.info("Error: " + documentResponse.getError() + " reason: " + documentResponse.getReason() + " on id: " + documentResponse.getId());
}
}
LOGGER.debug("(Cache updating) Success: " + successCount + " fail: " + failCount + ". Tried to update: " + updateAttemptCount);
int numberOfWantedType = 0;
for (CacheDataPacket cacheDataPacket : calculatedPackets) {
if (cacheDataPacket.getSourceId().equals(sourceId) && cacheDataPacket.getCacheName().equals(cacheName)) {
@SuppressWarnings("unchecked") T packet = (T) cacheDataPacket;
Long periodNumber = documentIdPeriodNumberMap.get(cacheDataPacket.getDbId());
if (periodNumber == null) {
throw new NullPointerException("No period number for id: " + cacheDataPacket.getDbId());
}
periodNumberPacketMap.put(periodNumber, packet);
numberOfWantedType++;
}
}
LOGGER.debug("Calculated " + calculatedPackets.size() + " and " + numberOfWantedType + " were of type " + cacheName);
} else {
LOGGER.trace("Didn't have to get any data");
}
return new ArrayList<>(periodNumberPacketMap.values());
}
use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.
the class SolarMain method doMain.
private static int doMain(String[] args) {
String logMessage = "Beginning main. Jar: " + getJarInfo();
LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "[LOG] " + logMessage);
System.out.println("[stdout] " + logMessage);
System.err.println("[stderr] " + logMessage);
Cli<CommandOptions> cli = CliFactory.createCli(CommandOptions.class);
final CommandOptions commandOptions;
try {
commandOptions = cli.parseArguments(args);
} catch (ArgumentValidationException ex) {
System.out.println(cli.getHelpMessage());
if (ex instanceof HelpRequestedException) {
return 0;
}
LOGGER.error(SolarThingConstants.SUMMARY_MARKER, ex.getMessage());
LOGGER.error(SolarThingConstants.SUMMARY_MARKER, "(Fatal)Incorrect args");
return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS;
}
if (commandOptions.getBaseConfigFile() != null) {
return doMainCommand(commandOptions, commandOptions.getBaseConfigFile());
}
if (commandOptions.getCouchDbSetupFile() != null) {
final DatabaseConfig config;
try {
config = ConfigUtil.MAPPER.readValue(commandOptions.getCouchDbSetupFile(), DatabaseConfig.class);
} catch (IOException e) {
e.printStackTrace();
System.err.println("Problem reading CouchDB database settings file.");
return SolarThingConstants.EXIT_CODE_INVALID_CONFIG;
}
DatabaseSettings settings = config.getSettings();
if (!(settings instanceof CouchDbDatabaseSettings)) {
System.err.println("Must be CouchDB database settings!");
return SolarThingConstants.EXIT_CODE_INVALID_CONFIG;
}
try {
return CouchDbSetupMain.createFrom((CouchDbDatabaseSettings) settings).doCouchDbSetupMain();
} catch (CouchDbException e) {
if (e instanceof CouchDbCodeException) {
ErrorResponse error = ((CouchDbCodeException) e).getErrorResponse();
if (error != null) {
System.err.println(error.getError());
System.err.println(error.getReason());
}
}
throw new RuntimeException(e);
}
}
List<String> legacyArguments = commandOptions.getLegacyOptionsRaw();
if (legacyArguments == null || legacyArguments.isEmpty()) {
System.err.println(cli.getHelpMessage());
return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS;
}
System.err.println("Invalid sub command: " + legacyArguments.get(0));
return SolarThingConstants.EXIT_CODE_INVALID_OPTIONS;
}
use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.
the class CouchDbMillisDatabase method query.
@Override
public List<StoredPacketGroup> query(MillisQuery query) throws SolarThingDatabaseException {
final ViewResponse response;
try {
response = database.queryView(SolarThingCouchDb.createMillisNullView(CouchDbQueryUtil.createMillisNullParams(query)));
} catch (CouchDbException e) {
throw ExceptionUtil.createFromCouchDbException(e);
}
List<ViewResponse.DocumentEntry> rows = response.getRows();
List<StoredPacketGroup> r = new ArrayList<>(rows.size());
for (ViewResponse.DocumentEntry row : rows) {
// When using includeDocs=true, we want to use the doc, not its value (which is null with millisNull)
JsonData jsonData = row.getDoc();
StoredPacketGroup storedPacketGroup = jsonDataToStoredPacketGroup(jsonData).getPacket();
r.add(storedPacketGroup);
}
return r;
}
use of me.retrodaredevil.couchdbjava.exception.CouchDbException in project solarthing by wildmountainfarms.
the class CouchDbMillisDatabase method uploadPacketCollection.
@Override
public UpdateToken uploadPacketCollection(PacketCollection packetCollection, UpdateToken updateToken) throws SolarThingDatabaseException {
final JsonData jsonData;
try {
jsonData = new StringJsonData(mapper.writeValueAsString(packetCollection));
} catch (JsonProcessingException e) {
throw new RuntimeException("Couldn't serialize the packet collection", e);
}
try {
final DocumentResponse response;
if (updateToken == null) {
response = database.putDocument(packetCollection.getDbId(), jsonData);
} else {
RevisionUpdateToken revisionUpdateToken = CouchDbSolarThingDatabase.checkUpdateToken(updateToken);
response = database.updateDocument(packetCollection.getDbId(), revisionUpdateToken.getRevision(), jsonData);
}
return new RevisionUpdateToken(response.getRev());
} catch (CouchDbException e) {
throw ExceptionUtil.createFromCouchDbException(e);
}
}
Aggregations