Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Br dev #18

Merged
merged 3 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group 'com.scaleoutsoftware.digitaltwin'
version '3.0.6'
version '3.0.7'

sourceCompatibility = JavaVersion.VERSION_12

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package com.scaleoutsoftware.digitaltwin.core;

import java.time.Duration;
import java.util.Date;

/**
* The SimulationController interface is used to interact with the running DigitalTwin simulation.
Expand Down Expand Up @@ -64,6 +65,20 @@ public interface SimulationController {
*/
SendingResult delay(Duration duration);

/**
* <p>
* Delay simulation processing for this DigitalTwin instance, indefinitely.
* </p>
*
* <p>
* Simulation processing will be delayed until this instance is run with {@link SimulationController#runThisTwin()}.
* </p>
*
* @return {@link SendingResult#Handled} if the delay was processed or {@link SendingResult#NotHandled}
* if the delay was not processed.
*/
SendingResult delayIndefinitely();

/**
* <p>
* Asynchronously send a JSON serialized message to a DigitalTwin instance that will be processed by the DigitalTwin
Expand Down Expand Up @@ -144,9 +159,20 @@ public interface SimulationController {
*/
SendingResult deleteThisInstance();

/**
* Run this instance during this simulation step. The instance will be run using the models {@link SimulationProcessor#processModel(ProcessingContext, DigitalTwinBase, Date)}
* implementation.
*
* This will cause the simulation sub-system to run this instance regardless of the instances current
* {@link DigitalTwinBase#NextSimulationTime}.
*/
void runThisInstance();

/**
* Stop the simulation.
* @return a {@link SimulationStatus#InstanceRequestedStop}.
*/
SimulationStatus stopSimulation();


}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,83 @@

class Constants {
public static final int MAX_TIMER_COUNT = 5;
/**
*
* Returns a hash that is suitable for inserting an object into a hash-based collection.
* <p>
* -----------------------------------------------------------------------------
* MurmurHash3 was written by Austin Appleby, and is placed in the public
* domain. The author hereby disclaims copyright to this source code.
*
* Note - The x86 and x64 versions do _not_ produce the same results, as the
* algorithms are optimized for their respective platforms. You can still
* compile and run any of them on any platform, but your performance with the
* non-native version will be less than optimal.
* Original code from:
* https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
* -----------------------------------------------------------------------------
*
* This implementation is tweaked to initialize with a hard-coded seed and to return a long instead of a
* 32-bit unsigned integer (since Java doesn't easily support unsigned integers).
* @param data The byte array to be hashed.
* @return Hash code for the array, with values ranging from 0 to 4,294,967,295.
*/
static long getHash(byte[] data) {
if(data == null) {
throw new IllegalArgumentException("Hash data was null.");
}

final int seed = 947203; // Scaleout's implementation-specific seed.
final int c1 = 0xcc9e2d51;
final int c2 = 0x1b873593;

int len = data.length;
int h1 = seed;
int roundedEnd = len & 0xfffffffc; // round down to 4 byte block

for (int i = 0; i < roundedEnd; i += 4) {
// little endian load order
int k1 = (data[i] & 0xff) | ((data[i + 1] & 0xff) << 8) | ((data[i + 2] & 0xff) << 16) | (data[i + 3] << 24);
k1 *= c1;
k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15);
k1 *= c2;

h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19); // ROTL32(h1,13);
h1 = h1 * 5 + 0xe6546b64;
}

// tail (leftover bytes that didn't fit into a 4-byte block)
int k1 = 0;

switch (len & 0x03) {
case 3:
k1 = (data[roundedEnd + 2] & 0xff) << 16;
// fallthrough
case 2:
k1 |= (data[roundedEnd + 1] & 0xff) << 8;
// fallthrough
case 1:
k1 |= (data[roundedEnd] & 0xff);
k1 *= c1;
k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15);
k1 *= c2;
h1 ^= k1;
}

// finalization
h1 ^= len;

// fmix(h1);
h1 ^= h1 >>> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >>> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >>> 16;

// Other languages want to represent the hash as an unsigned int, but java doesn't easily have
// unsigned types. So we move the signed integer's bits into an "unsigned" long, which
// is big enough to hold all the positive values of an unsigned int.
return h1 & 0x00000000ffffffffL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ String getId() {
return _id;
}

String getModel() {return _model;}

void setNextSimulationTime(long nextSimulationTime) {
_nextSimulationTime = nextSimulationTime;
handleResetNextSimulationTime();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import com.scaleoutsoftware.digitaltwin.core.ProcessingContext;
import com.scaleoutsoftware.digitaltwin.core.SimulationProcessor;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Objects;

class SimulationEventTwinImpl extends SimulationEvent {
SimulationProcessor _processor;
Expand Down Expand Up @@ -63,4 +65,17 @@ void handleResetNextSimulationTime() {
base.NextSimulationTime = _nextSimulationTime;
_proxy.setInstance(base);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimulationEventTwinImpl that = (SimulationEventTwinImpl) o;
return this._proxy.getInstance().getId().compareTo(that._id) == 0 && this._proxy.getInstance().getModel().compareTo(that._model) == 0;
}

@Override
public int hashCode() {
return (int)Constants.getHash(_id.getBytes(StandardCharsets.UTF_8));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public SimulationScheduler(String modelName,
_modelName = modelName;
_simulationProcessor = modelProcessor;
for(int i = 0; i < NUM_SIMULATION_WORKERS; i++) {
_workers.add(new SimulationWorker(i, _modelName, _simulationProcessor, digitalTwinClass, executor));
_workers.add(new SimulationWorker(i, _modelName, _simulationProcessor, digitalTwinClass, executor, this));
}
}

Expand Down Expand Up @@ -146,87 +146,14 @@ void stopTimer(String modelName, String id, String timerName) {
worker.stopTimer(modelName, id, timerName);
}

private int findSlotId(String id) {
return (int)((getHash(id.getBytes(StandardCharsets.UTF_8))) % (long)NUM_SIMULATION_WORKERS);
void runThisInstance(String model, String id) throws WorkbenchException {
SimulationWorker worker = _workers.get(findSlotId(id));
worker.runThisInstance(model, id);
}

/**
*
* Returns a hash that is suitable for inserting an object into a hash-based collection.
* <p>
* -----------------------------------------------------------------------------
* MurmurHash3 was written by Austin Appleby, and is placed in the public
* domain. The author hereby disclaims copyright to this source code.
*
* Note - The x86 and x64 versions do _not_ produce the same results, as the
* algorithms are optimized for their respective platforms. You can still
* compile and run any of them on any platform, but your performance with the
* non-native version will be less than optimal.
* Original code from:
* https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
* -----------------------------------------------------------------------------
*
* This implementation is tweaked to initialize with a hard-coded seed and to return a long instead of a
* 32-bit unsigned integer (since Java doesn't easily support unsigned integers).
* @param data The byte array to be hashed.
* @return Hash code for the array, with values ranging from 0 to 4,294,967,295.
*/
static long getHash(byte[] data) {
if(data == null) {
throw new IllegalArgumentException("Hash data was null.");
}

final int seed = 947203; // Scaleout's implementation-specific seed.
final int c1 = 0xcc9e2d51;
final int c2 = 0x1b873593;

int len = data.length;
int h1 = seed;
int roundedEnd = len & 0xfffffffc; // round down to 4 byte block

for (int i = 0; i < roundedEnd; i += 4) {
// little endian load order
int k1 = (data[i] & 0xff) | ((data[i + 1] & 0xff) << 8) | ((data[i + 2] & 0xff) << 16) | (data[i + 3] << 24);
k1 *= c1;
k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15);
k1 *= c2;

h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19); // ROTL32(h1,13);
h1 = h1 * 5 + 0xe6546b64;
}

// tail (leftover bytes that didn't fit into a 4-byte block)
int k1 = 0;

switch (len & 0x03) {
case 3:
k1 = (data[roundedEnd + 2] & 0xff) << 16;
// fallthrough
case 2:
k1 |= (data[roundedEnd + 1] & 0xff) << 8;
// fallthrough
case 1:
k1 |= (data[roundedEnd] & 0xff);
k1 *= c1;
k1 = (k1 << 15) | (k1 >>> 17); // ROTL32(k1,15);
k1 *= c2;
h1 ^= k1;
}

// finalization
h1 ^= len;
private int findSlotId(String id) {
return (int)((Constants.getHash(id.getBytes(StandardCharsets.UTF_8))) % (long)NUM_SIMULATION_WORKERS);
}

// fmix(h1);
h1 ^= h1 >>> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >>> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >>> 16;

// Other languages want to represent the hash as an unsigned int, but java doesn't easily have
// unsigned types. So we move the signed integer's bits into an "unsigned" long, which
// is big enough to hold all the positive values of an unsigned int.
return h1 & 0x00000000ffffffffL;
}
}
Loading