Heap Corruption In C When Using DLL With JNA - java

I am using C language Native API callbacks with DLL files. When we are calling callback first time everything is working fine but on second call I am getting heap corruption error and JVM is getting crashed.
In the native code the memory allocated in first call is being released and then is being used in second call again and during memory allocation in second call JVM is being crashed. But on the same place when in second call new memory pointer is used rather than the one which was used in previous call I am not getting this heap corruption error.
As this callback is called many times I can not keep on allocating new space every time. In below logs I am getting error as INVALID_POINTER_READ.
I am not able to understand what is the reason behind it and how this can be fixed. When same DLL is used with JNA it's working fine.
Java/JNA Code:
Setting Hook:
final PropertyCallBack callback = new PropertyCallBack();
final int setHookStatus = callback.setHook();
private static CALLBACK callback;
public int setHook() {
if (callback != null) {
return 0;
}
synchronized (this) {
if (callback == null) {
callback = new CALLBACK();
return callback.setHook();
}
}
return 0;
}
Callback Method Called From Native:
#Override
public int PropertyHook(final DESTINATION dest, final BACSTAC_READ_INFO.ByReference info) {
final PROPERTY_CONTENTS.ByReference content = new PROPERTY_CONTENTS.ByReference();
final BUFFER.ByReference buffer = new BUFFER.ByReference();
// Memory assign
final int bufferSize = 1048;
buffer.pBuffer = new Memory(bufferSize);
buffer.nBufferSize = bufferSize;
content.tag = "INVALID";
content.buffer = buffer;
content.nElements = 0;
Pointer dev = NativeLibrary.INSTANCE.Call_1();
Pointer obj = null;
if (dev != null) {
obj = NativeLibrary.INSTANCE.call_2(dev, info.objectID);
}
final int readDbStatus = NativeLibrary.INSTANCE.call_3(obj, info.prop, info.index, content, null);
final int responseStatus = NativeLibrary.INSTANCE.call_4(dest, info, content);
return 0;
}
When I analyzed heap dump with windbg I am getting below details:
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(6201c.5ef10): Access violation - code c0000005 (first/second chance not available)
For analysis of this file, run !analyze -v
ntdll!NtWaitForMultipleObjects+0x14:
00007ffa`46deb4f4 c3 ret
0:026> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** WARNING: Unable to verify checksum for srv.dll
DEBUG_FLR_EXCEPTION_CODE(c0000374) and the ".exr -1" ExceptionCode(c0000005) don't match
KEY_VALUES_STRING: 1
Key : AV.Fault
Value: Read
Key : Timeline.Process.Start.DeltaSec
Value: 46
PROCESSES_ANALYSIS: 1
SERVICE_ANALYSIS: 1
STACKHASH_ANALYSIS: 1
TIMELINE_ANALYSIS: 1
Timeline: !analyze.Start
Name: <blank>
Time: 2019-12-02T11:13:41.439Z
Diff: 3429439 mSec
Timeline: Dump.Current
Name: <blank>
Time: 2019-12-02T10:16:32.0Z
Diff: 0 mSec
Timeline: Process.Start
Name: <blank>
Time: 2019-12-02T10:15:46.0Z
Diff: 46000 mSec
DUMP_CLASS: 2
DUMP_QUALIFIER: 400
CONTEXT: (.ecxr)
rax=0000000000030000 rbx=000000002b200000 rcx=0000000000000303
rdx=0000000000000003 rsi=01fda8c00000ed00 rdi=000000002b223ef0
rip=00007ffa46d6cb7a rsp=000000002b8ff500 rbp=0000000000000008
r8=0000000000000028 r9=0000000000000030 r10=00000000014da2d0
r11=00000000014e2ef0 r12=0000000000000001 r13=0000000000000003
r14=000000002b223ee0 r15=000000000600c1ba
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246
ntdll!RtlpAllocateHeap+0xdaa:
00007ffa`46d6cb7a 498b07 mov rax,qword ptr [r15] ds:00000000`0600c1ba=????????????????
Resetting default scope
FAULTING_IP:
ntdll!RtlpAllocateHeap+daa
00007ffa`46d6cb7a 498b07 mov rax,qword ptr [r15]
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ffa46d6cb7a (ntdll!RtlpAllocateHeap+0x0000000000000daa)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: 000000000600c1ba
Attempt to read from address 000000000600c1ba
DEFAULT_BUCKET_ID: HEAP_CORRUPTION
PROCESS_NAME: javaw.exe
FOLLOWUP_IP:
ntdll!RtlpAllocateHeap+daa
00007ffa`46d6cb7a 498b07 mov rax,qword ptr [r15]
READ_ADDRESS: 000000000600c1ba
ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.
EXCEPTION_CODE: (NTSTATUS) 0xc0000374 - A heap has been corrupted.
EXCEPTION_CODE_STR: c0000005
EXCEPTION_PARAMETER1: 0000000000000000
EXCEPTION_PARAMETER2: 000000000600c1ba
WATSON_BKT_PROCSTAMP: 5d1dea24
WATSON_BKT_PROCVER: 8.0.2210.11
PROCESS_VER_PRODUCT: Java(TM) Platform SE 8
WATSON_BKT_MODULE: ntdll.dll
WATSON_BKT_MODSTAMP: 7f828745
WATSON_BKT_MODOFFSET: 1cb7a
WATSON_BKT_MODVER: 10.0.17134.799
MODULE_VER_PRODUCT: Microsoft® Windows® Operating System
BUILD_VERSION_STRING: 17134.1.amd64fre.rs4_release.180410-1804
MODLIST_WITH_TSCHKSUM_HASH: f06ad8a6a7f7267c783c08e3a62df4696020d52f
MODLIST_SHA1_HASH: cdafa8057ac19b1a3608c439ebbfa992407212d6
NTGLOBALFLAG: 0
PROCESS_BAM_CURRENT_THROTTLED: 0
PROCESS_BAM_PREVIOUS_THROTTLED: 0
APPLICATION_VERIFIER_FLAGS: 0
DUMP_FLAGS: 94
DUMP_TYPE: 1
ANALYSIS_SESSION_HOST: MD2E86EC
ANALYSIS_SESSION_TIME: 12-02-2019 16:43:41.0439
ANALYSIS_VERSION: 10.0.18362.1 x86fre
THREAD_ATTRIBUTES:
ADDITIONAL_DEBUG_TEXT: Enable Pageheap/AutoVerifer ; Followup set based on attribute [Is_ChosenCrashFollowupThread] from Frame:[0] on thread:[PSEUDO_THREAD]
FAULTING_THREAD: 0005ef10
THREAD_SHA1_HASH_MOD_FUNC: 5d531e271dfb1ef7af4984c7ee0dd671c07337f5
THREAD_SHA1_HASH_MOD_FUNC_OFFSET: d858fa5fb04738fbbbbb9e4df89e26d53dc74794
OS_LOCALE: ENU
BUGCHECK_STR: APPLICATION_FAULT_INVALID_POINTER_READ_HEAP_CORRUPTION
PRIMARY_PROBLEM_CLASS: APPLICATION_FAULT
PROBLEM_CLASSES:
ID: [0n262]
Type: [HEAP_CORRUPTION]
Class: Primary
Scope: DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
BUCKET_ID
Name: Add
Data: Omit
PID: [0x6201c]
TID: [0x5ef10]
Frame: [0] : ntdll!RtlpAllocateHeap
ID: [0n262]
Type: [HEAP_CORRUPTION]
Class: Primary
Scope: BUCKET_ID
Name: Add
Data: Omit
PID: [0x6201c]
TID: [0x5ef10]
Frame: [0] : ntdll!RtlpAllocateHeap
ID: [0n313]
Type: [#ACCESS_VIOLATION]
Class: Addendum
Scope: BUCKET_ID
Name: Omit
Data: Omit
PID: [Unspecified]
TID: [0x5ef10]
Frame: [0] : ntdll!RtlpAllocateHeap
ID: [0n285]
Type: [INVALID_POINTER_READ]
Class: Primary
Scope: BUCKET_ID
Name: Add
Data: Omit
PID: [Unspecified]
TID: [0x5ef10]
Frame: [0] : ntdll!RtlpAllocateHeap
LAST_CONTROL_TRANSFER: from 00007ffa46d69725 to 00007ffa46d6cb7a
STACK_TEXT:
00000000`00000000 00000000`00000000 heap_corruption!javaw.exe+0x0
THREAD_SHA1_HASH_MOD: ca4e26064d24ef7512d2e94de5a93c38dbe82fe9
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: heap_corruption!javaw.exe
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: heap_corruption
IMAGE_NAME: heap_corruption
DEBUG_FLR_IMAGE_TIMESTAMP: 0
STACK_COMMAND: ** Pseudo Context ** ManagedPseudo ** Value: a3807e8 ** ; kb
FAILURE_BUCKET_ID: HEAP_CORRUPTION_c0000005_heap_corruption!javaw.exe
BUCKET_ID: APPLICATION_FAULT_INVALID_POINTER_READ_HEAP_CORRUPTION_heap_corruption!javaw.exe
FAILURE_EXCEPTION_CODE: c0000005
FAILURE_IMAGE_NAME: heap_corruption
BUCKET_ID_IMAGE_STR: heap_corruption
FAILURE_MODULE_NAME: heap_corruption
BUCKET_ID_MODULE_STR: heap_corruption
FAILURE_FUNCTION_NAME: javaw.exe
BUCKET_ID_FUNCTION_STR: javaw.exe
BUCKET_ID_OFFSET: 0
BUCKET_ID_MODTIMEDATESTAMP: 0
BUCKET_ID_MODCHECKSUM: 0
BUCKET_ID_MODVER_STR: 0.0.0.0
BUCKET_ID_PREFIX_STR: APPLICATION_FAULT_INVALID_POINTER_READ_
FAILURE_PROBLEM_CLASS: APPLICATION_FAULT
FAILURE_SYMBOL_NAME: heap_corruption!javaw.exe
WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/javaw.exe/8.0.2210.11/5d1dea24/ntdll.dll/10.0.17134.799/7f828745/c0000005/0001cb7a.htm?Retriage=1
TARGET_TIME: 2019-12-02T10:16:32.000Z
OSBUILD: 17134
OSSERVICEPACK: 753
SERVICEPACK_NUMBER: 0
OS_REVISION: 0
SUITE_MASK: 256
PRODUCT_TYPE: 1
OSPLATFORM_TYPE: x64
OSNAME: Windows 10
OSEDITION: Windows 10 WinNt SingleUserTS
USER_LCID: 0
OSBUILD_TIMESTAMP: unknown_date
BUILDDATESTAMP_STR: 180410-1804
BUILDLAB_STR: rs4_release
BUILDOSVER_STR: 10.0.17134.1.amd64fre.rs4_release.180410-1804
ANALYSIS_SESSION_ELAPSED_TIME: 307a
ANALYSIS_SOURCE: UM
FAILURE_ID_HASH_STRING: um:heap_corruption_c0000005_heap_corruption!javaw.exe
FAILURE_ID_HASH: {ddc2b378-b1e1-2aec-adc8-f11b7a5773a9}
Any help in fix/debug will be highly appreciated.

I got the solution of to prevent above heap corruption by calling NativeLibrary methods of PropertyHook in another thread. Somehow by calling NativeLibrary methods in different thread heap is not getting corrupted and sub-sequently JVM is not being crashed.

Related

VisualVM heap dump "Summary" shows way more roots than "Objects->Preset: GC Roots" shows, what does it mean?

I suspect a slow memory leak caused by JNI code. I'm seeing the GC Roots # in the summary of consecutive heap dumps climbing. After two hours it showed 470,000 GC roots, after six hours, almost a million more GC roots, after 33 hours over 7 million GC roots.
However, when I look at the Head Dump that says there are 7 million GC roots, and I choose the "Objects" view and the "GC Roots" preset, I select Aggregation "Types". This list shows a total count of less than 15,000 objects:
JNI global - count 7857
JNI local - count 5
Java frame - count 983
monitor used - count 7
sticky class - count 3596
thread object - count 145
Where are those 7 million roots?
Different GC roots can reffer to the same object instance. This explains the difference, since count from "GC root" view display number of unique instances. You can find more details using OQL. First let's display number of GC roots for particular GC type:
printHistogram()
function printHistogram() {
var roots = heap.roots()
var histoMap = new Array();
var result = new Array();
var cnt = 0;
while (roots.hasMoreElements()) {
var root = roots.nextElement();
var type = root.type;
if (histoMap[type] == undefined) {
histoMap[type] = 1;
} else {
histoMap[type]++;
}
}
for (var key in histoMap){
if (histoMap.hasOwnProperty(key)) {
result[cnt++] = { key: key, count: histoMap[key] };
}
return map(sort(result, "rhs.count - lhs.count"), '"Root count: "+it.count+" for type: "+it.key');
}
Running this query against your heap dump produces:
Root count: 12878043 for type: JNI local
Root count: 7858 for type: JNI global
Root count: 3599 for type: sticky class
Root count: 1631 for type: Java frame
Root count: 146 for type: thread object
Root count: 7 for type: monitor used
We can see that the majority of GC roots are of "JNI local" type. Let us see how many "JNI local" roots point to the same object instance. We can modify above query to:
printHistogram()
function printHistogram() {
var roots = heap.roots()
var histoMap = new Array();
var rootMap = new Array();
var result = new Array();
var cnt = 0;
while (roots.hasMoreElements()) {
var root = roots.nextElement();
if (root.type == "JNI local") {
var objid = root.id;
if (histoMap[objid] == undefined) {
histoMap[objid] = 1;
rootMap[objid] = root.referrer;
} else {
histoMap[objid]++;
}
}
}
for (var key in histoMap){
if (histoMap.hasOwnProperty(key)) {
result[cnt++] = { key: rootMap[key], count: histoMap[key] };
}
}
return map(sort(result, "rhs.count - lhs.count"), '"Root count: "+it.count+" for object: "+toHtml(it.key)');
}
The result is below:
Root count: 6439020 for object: java.lang.String#44429
Root count: 6439020 for object: java.lang.String#55081
Root count: 1 for object: java.nio.DirectByteBuffer#9
Root count: 1 for object: java.util.ArrayList#22281
Root count: 1 for object: java.lang.String#71518
We can see that two strings java.lang.String#44429 and java.lang.String#55081 are responsible for that huge number of GC roots. They have 6,5 million GC roots each.
Those "JNI local" GC root are referenced from MessageDispatherThread-1 (tid=216) from frame ca.digitalrapids.kayak.jni.KayakNativeWorkerThread.runNative (Native Method). See screenshots below:

OR-TOOLS EXCEPTION_ACCESS_VIOLATION when running TSP

When I run the TSP algorithm I get a fatal error on the native or-tools library.
There is a small chance to execute the TSP algo with success when running it only one time, but for consecutive executions without a big interval between them, it always happens.
I'm currently running it on Windows 10, but it tested it on Debian and Alpine and the problem still happens.
Here is a preview, but you can see the full log here (each time I get this error the problematic frame is different).
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000002a9e261c007, pid=12012, tid=9116
#
# JRE version: OpenJDK Runtime Environment (14.0.1+7) (build 14.0.1+7)
# Java VM: OpenJDK 64-Bit Server VM (14.0.1+7, mixed mode, sharing, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# J 10298 c2 org.neo4j.kernel.impl.store.LongerShortString.decode([JII)Lorg/neo4j/values/storable/TextValue; (120 bytes) # 0x000002a9e261c007 [0x000002a9e261bb80+0x0000000000000487]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\Users\hugo_\Workspace\Itini\Backend\service-itinerary-builder\hs_err_pid12012.log
Compiled method (c2) 124037 10298 4 org.neo4j.kernel.impl.store.LongerShortString::decode (120 bytes)
total in heap [0x000002a9e261b910,0x000002a9e261cc48] = 4920
relocation [0x000002a9e261ba70,0x000002a9e261bb70] = 256
main code [0x000002a9e261bb80,0x000002a9e261c6e0] = 2912
stub code [0x000002a9e261c6e0,0x000002a9e261c6f8] = 24
oops [0x000002a9e261c6f8,0x000002a9e261c708] = 16
metadata [0x000002a9e261c708,0x000002a9e261c770] = 104
scopes data [0x000002a9e261c770,0x000002a9e261ca40] = 720
scopes pcs [0x000002a9e261ca40,0x000002a9e261cb90] = 336
dependencies [0x000002a9e261cb90,0x000002a9e261cb98] = 8
handler table [0x000002a9e261cb98,0x000002a9e261cc28] = 144
nul chk table [0x000002a9e261cc28,0x000002a9e261cc48] = 32
Compiled method (c2) 124056 12326 4 org.neo4j.kernel.impl.newapi.DefaultPropertyCursor::propertyValue (38 bytes)
total in heap [0x000002a9e2cb7410,0x000002a9e2cb88f8] = 5352
relocation [0x000002a9e2cb7570,0x000002a9e2cb7750] = 480
main code [0x000002a9e2cb7760,0x000002a9e2cb8280] = 2848
stub code [0x000002a9e2cb8280,0x000002a9e2cb82c8] = 72
oops [0x000002a9e2cb82c8,0x000002a9e2cb82d8] = 16
metadata [0x000002a9e2cb82d8,0x000002a9e2cb8398] = 192
scopes data [0x000002a9e2cb8398,0x000002a9e2cb8618] = 640
scopes pcs [0x000002a9e2cb8618,0x000002a9e2cb8828] = 528
dependencies [0x000002a9e2cb8828,0x000002a9e2cb8838] = 16
handler table [0x000002a9e2cb8838,0x000002a9e2cb88c8] = 144
nul chk table [0x000002a9e2cb88c8,0x000002a9e2cb88f8] = 48
Java code:
public List<AlgoNode> solve(final Collection<AlgoNode> nodes, final AlgoNode start) {
if (nodes == null || nodes.isEmpty())
return new ArrayList<>();
if (nodes.size() == 1)
return new ArrayList<>(nodes);
// Setup Variables
var list = new ArrayList<>(nodes);
var depot = start == null ? 0 : list.indexOf(start);
var manager = new RoutingIndexManager(list.size(), 1, depot);
var routing = new RoutingModel(manager);
// Define dummy weight function
var transitCallbackIndex = routing.registerTransitCallback((fromIndex, toIndex) -> 1L);
routing.setArcCostEvaluatorOfAllVehicles(transitCallbackIndex);
// Solve
var parameters = main.defaultRoutingSearchParameters().toBuilder();
parameters.setFirstSolutionStrategy(FirstSolutionStrategy.Value.PATH_CHEAPEST_ARC);
var solution = routing.solveWithParameters(parameters.build()); // Problematic line
return new ArrayList<>(); // Dummy return
}
I also tryied making the method syncronized, using a lock and calling closeModel() after running the TSP, but no lucky.
seems related to https://github.com/google/or-tools/issues/2091
Please, don't hesitate to open a github issue with all this information...

How to increase Dataflow read parallelism from Cassandra

I am trying to export a lot of data (2 TB, 30kkk rows) from Cassandra to BigQuery. All my infrastructure is on GCP. My Cassandra cluster have 4 nodes (4 vCPUs, 26 GB memory, 2000 GB PD (HDD) each). There is one seed node in the cluster. I need to transform my data before writing to BQ, so I am using Dataflow. Worker type is n1-highmem-2. Workers and Cassandra instances are at the same zone europe-west1-c. My limits for Cassandra:
Part of my pipeline code responsible for reading transform is located here.
Autoscaling
The problem is that when I don't set --numWorkers, the autoscaling set number of workers in such manner (2 workers average):
Load balancing
When I set --numWorkers=15 the rate of reading doesn't increase and only 2 workers communicate with Cassandra (I can tell it from iftop and only these workers have CPU load ~60%).
At the same time Cassandra nodes don't have a lot of load (CPU usage 20-30%). Network and disk usage of the seed node is about 2 times higher than others, but not too high, I think:
And for the not seed node here:
Pipeline launch warnings
I have some warnings when pipeline is launching:
WARNING: Size estimation of the source failed:
org.apache.beam.sdk.io.cassandra.CassandraIO$CassandraSource#7569ea63
com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: /10.132.9.101:9042 (com.datastax.driver.core.exceptions.TransportException: [/10.132.9.101:9042] Cannot connect), /10.132.9.102:9042 (com.datastax.driver.core.exceptions.TransportException: [/10.132.9.102:9042] Cannot connect), /10.132.9.103:9042 (com.datastax.driver.core.exceptions.TransportException: [/10.132.9.103:9042] Cannot connect), /10.132.9.104:9042 [only showing errors of first 3 hosts, use getErrors() for more details])
My Cassandra cluster is in GCE local network and it seams that some queries are made from my local machine and cannot reach the cluster (I am launching pipeline with Dataflow Eclipse plugin as described here). These queries are about size estimation of tables. Can I specify size estimation by hand or launch pipline from GCE instance? Or can I ignore these warnings? Does it have effect on rate of read?
I'v tried to launch pipeline from GCE VM. There is no more problem with connectivity. I don't have varchar columns in my tables but I get such warnings (no codec in datastax driver [varchar <-> java.lang.Long]). :
WARNING: Can't estimate the size
com.datastax.driver.core.exceptions.CodecNotFoundException: Codec not found for requested operation: [varchar <-> java.lang.Long]
at com.datastax.driver.core.CodecRegistry.notFound(CodecRegistry.java:741)
at com.datastax.driver.core.CodecRegistry.createCodec(CodecRegistry.java:588)
at com.datastax.driver.core.CodecRegistry.access$500(CodecRegistry.java:137)
at com.datastax.driver.core.CodecRegistry$TypeCodecCacheLoader.load(CodecRegistry.java:246)
at com.datastax.driver.core.CodecRegistry$TypeCodecCacheLoader.load(CodecRegistry.java:232)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3628)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2336)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2295)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2208)
at com.google.common.cache.LocalCache.get(LocalCache.java:4053)
at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:4057)
at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4986)
at com.datastax.driver.core.CodecRegistry.lookupCodec(CodecRegistry.java:522)
at com.datastax.driver.core.CodecRegistry.codecFor(CodecRegistry.java:485)
at com.datastax.driver.core.CodecRegistry.codecFor(CodecRegistry.java:467)
at com.datastax.driver.core.AbstractGettableByIndexData.codecFor(AbstractGettableByIndexData.java:69)
at com.datastax.driver.core.AbstractGettableByIndexData.getLong(AbstractGettableByIndexData.java:152)
at com.datastax.driver.core.AbstractGettableData.getLong(AbstractGettableData.java:26)
at com.datastax.driver.core.AbstractGettableData.getLong(AbstractGettableData.java:95)
at org.apache.beam.sdk.io.cassandra.CassandraServiceImpl.getTokenRanges(CassandraServiceImpl.java:279)
at org.apache.beam.sdk.io.cassandra.CassandraServiceImpl.getEstimatedSizeBytes(CassandraServiceImpl.java:135)
at org.apache.beam.sdk.io.cassandra.CassandraIO$CassandraSource.getEstimatedSizeBytes(CassandraIO.java:308)
at org.apache.beam.runners.direct.BoundedReadEvaluatorFactory$BoundedReadEvaluator.startDynamicSplitThread(BoundedReadEvaluatorFactory.java:166)
at org.apache.beam.runners.direct.BoundedReadEvaluatorFactory$BoundedReadEvaluator.processElement(BoundedReadEvaluatorFactory.java:142)
at org.apache.beam.runners.direct.TransformExecutor.processElements(TransformExecutor.java:146)
at org.apache.beam.runners.direct.TransformExecutor.run(TransformExecutor.java:110)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Pipeline read code
// Read data from Cassandra table
PCollection<Model> pcollection = p.apply(CassandraIO.<Model>read()
.withHosts(Arrays.asList("10.10.10.101", "10.10.10.102", "10.10.10.103", "10.10.10.104")).withPort(9042)
.withKeyspace(keyspaceName).withTable(tableName)
.withEntity(Model.class).withCoder(SerializableCoder.of(Model.class))
.withConsistencyLevel(CASSA_CONSISTENCY_LEVEL));
// Transform pcollection to KV PCollection by rowName
PCollection<KV<Long, Model>> pcollection_by_rowName = pcollection
.apply(ParDo.of(new DoFn<Model, KV<Long, Model>>() {
#ProcessElement
public void processElement(ProcessContext c) {
c.output(KV.of(c.element().rowName, c.element()));
}
}));
Number of splits (Stackdriver log)
W Number of splits is less than 0 (0), fallback to 1
I Number of splits is 1
W Number of splits is less than 0 (0), fallback to 1
I Number of splits is 1
W Number of splits is less than 0 (0), fallback to 1
I Number of splits is 1
What I'v tried
No effect:
set read consistency level to ONE
nodetool setstreamthroughput 1000, nodetool setinterdcstreamthroughput 1000
increase Cassandra read concurrency (in cassandra.yaml): concurrent_reads: 32
setting different number of workers 1-40.
Some effect:
1. I'v set numSplits = 10 as #jkff proposed. Now I can see in logs:
I Murmur3Partitioner detected, splitting
W Can't estimate the size
W Can't estimate the size
W Number of splits is less than 0 (0), fallback to 10
I Number of splits is 10
W Number of splits is less than 0 (0), fallback to 10
I Number of splits is 10
I Splitting source org.apache.beam.sdk.io.cassandra.CassandraIO$CassandraSource#6d83ee93 produced 10 bundles with total serialized response size 20799
I Splitting source org.apache.beam.sdk.io.cassandra.CassandraIO$CassandraSource#25d02f5c produced 10 bundles with total serialized response size 19359
I Splitting source [0, 1) produced 1 bundles with total serialized response size 1091
I Murmur3Partitioner detected, splitting
W Can't estimate the size
I Splitting source [0, 0) produced 0 bundles with total serialized response size 76
W Number of splits is less than 0 (0), fallback to 10
I Number of splits is 10
I Splitting source org.apache.beam.sdk.io.cassandra.CassandraIO$CassandraSource#2661dcf3 produced 10 bundles with total serialized response size 18527
But I'v got another exception:
java.io.IOException: Failed to start reading from source: org.apache.beam.sdk.io.cassandra.Cassandra...
(5d6339652002918d): java.io.IOException: Failed to start reading from source: org.apache.beam.sdk.io.cassandra.CassandraIO$CassandraSource#5f18c296
at com.google.cloud.dataflow.worker.WorkerCustomSources$BoundedReaderIterator.start(WorkerCustomSources.java:582)
at com.google.cloud.dataflow.worker.util.common.worker.ReadOperation$SynchronizedReaderIterator.start(ReadOperation.java:347)
at com.google.cloud.dataflow.worker.util.common.worker.ReadOperation.runReadLoop(ReadOperation.java:183)
at com.google.cloud.dataflow.worker.util.common.worker.ReadOperation.start(ReadOperation.java:148)
at com.google.cloud.dataflow.worker.util.common.worker.MapTaskExecutor.execute(MapTaskExecutor.java:68)
at com.google.cloud.dataflow.worker.DataflowWorker.executeWork(DataflowWorker.java:336)
at com.google.cloud.dataflow.worker.DataflowWorker.doWork(DataflowWorker.java:294)
at com.google.cloud.dataflow.worker.DataflowWorker.getAndPerformWork(DataflowWorker.java:244)
at com.google.cloud.dataflow.worker.DataflowBatchWorkerHarness$WorkerThread.doWork(DataflowBatchWorkerHarness.java:135)
at com.google.cloud.dataflow.worker.DataflowBatchWorkerHarness$WorkerThread.call(DataflowBatchWorkerHarness.java:115)
at com.google.cloud.dataflow.worker.DataflowBatchWorkerHarness$WorkerThread.call(DataflowBatchWorkerHarness.java:102)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.datastax.driver.core.exceptions.SyntaxError: line 1:53 mismatched character 'p' expecting '$'
at com.datastax.driver.core.exceptions.SyntaxError.copy(SyntaxError.java:58)
at com.datastax.driver.core.exceptions.SyntaxError.copy(SyntaxError.java:24)
at com.datastax.driver.core.DriverThrowables.propagateCause(DriverThrowables.java:37)
at com.datastax.driver.core.DefaultResultSetFuture.getUninterruptibly(DefaultResultSetFuture.java:245)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:68)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:43)
at org.apache.beam.sdk.io.cassandra.CassandraServiceImpl$CassandraReaderImpl.start(CassandraServiceImpl.java:80)
at com.google.cloud.dataflow.worker.WorkerCustomSources$BoundedReaderIterator.start(WorkerCustomSources.java:579)
... 14 more
Caused by: com.datastax.driver.core.exceptions.SyntaxError: line 1:53 mismatched character 'p' expecting '$'
at com.datastax.driver.core.Responses$Error.asException(Responses.java:144)
at com.datastax.driver.core.DefaultResultSetFuture.onSet(DefaultResultSetFuture.java:179)
at com.datastax.driver.core.RequestHandler.setFinalResult(RequestHandler.java:186)
at com.datastax.driver.core.RequestHandler.access$2500(RequestHandler.java:50)
at com.datastax.driver.core.RequestHandler$SpeculativeExecution.setFinalResult(RequestHandler.java:817)
at com.datastax.driver.core.RequestHandler$SpeculativeExecution.onSet(RequestHandler.java:651)
at com.datastax.driver.core.Connection$Dispatcher.channelRead0(Connection.java:1077)
at com.datastax.driver.core.Connection$Dispatcher.channelRead0(Connection.java:1000)
at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:341)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:349)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:642)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:565)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:479)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:441)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
... 1 more
Maybe there is a mistake: CassandraServiceImpl.java#L220
And this statement looks like mistype: CassandraServiceImpl.java#L207
Changes I'v done to CassandraIO code
As #jkff proposed, I've change CassandraIO in the way I needed:
#VisibleForTesting
protected List<BoundedSource<T>> split(CassandraIO.Read<T> spec,
long desiredBundleSizeBytes,
long estimatedSizeBytes) {
long numSplits = 1;
List<BoundedSource<T>> sourceList = new ArrayList<>();
if (desiredBundleSizeBytes > 0) {
numSplits = estimatedSizeBytes / desiredBundleSizeBytes;
}
if (numSplits <= 0) {
LOG.warn("Number of splits is less than 0 ({}), fallback to 10", numSplits);
numSplits = 10;
}
LOG.info("Number of splits is {}", numSplits);
Long startRange = MIN_TOKEN;
Long endRange = MAX_TOKEN;
Long startToken, endToken;
String pk = "$pk";
switch (spec.table()) {
case "table1":
pk = "table1_pk";
break;
case "table2":
case "table3":
pk = "table23_pk";
break;
}
endToken = startRange;
Long incrementValue = endRange / numSplits - startRange / numSplits;
String splitQuery;
if (numSplits == 1) {
// we have an unique split
splitQuery = QueryBuilder.select().from(spec.keyspace(), spec.table()).toString();
sourceList.add(new CassandraIO.CassandraSource<T>(spec, splitQuery));
} else {
// we have more than one split
for (int i = 0; i < numSplits; i++) {
startToken = endToken;
endToken = startToken + incrementValue;
Select.Where builder = QueryBuilder.select().from(spec.keyspace(), spec.table()).where();
if (i > 0) {
builder = builder.and(QueryBuilder.gte("token(" + pk + ")", startToken));
}
if (i < (numSplits - 1)) {
builder = builder.and(QueryBuilder.lt("token(" + pk + ")", endToken));
}
sourceList.add(new CassandraIO.CassandraSource(spec, builder.toString()));
}
}
return sourceList;
}
I think this should be classified as a bug in CassandraIO. I filed BEAM-3424. You can try building your own version of Beam with that default of 1 changed to 100 or something like that, while this issue is being fixed.
I also filed BEAM-3425 for the bug during size estimation.

Access FreePastry program that is behind NAT

I'm trying to connect to my program that uses FreePastry behind a NAT but getting no where. mIP is my public IP, mBootport and mBindport is 50001. I have forworded this ports in my router to my computer stil it does not work. I disabled the firewall yet nothing. I disconnected the router and connect directly to the internet and stil it does not work. The only time it does work in on my local network. So something most be wrong in either the code of the config file but i can not see what is wrong.
Environment env = new Environment();
InetSocketAddress bootaddress = new InetSocketAddress(mIP, mBootport);
NodeIdFactory nidFactory = new RandomNodeIdFactory(env);
PastryNodeFactory factory = new SocketPastryNodeFactory(nidFactory, mBindport, env);
for (int curNode = 0; curNode < mNumNodes; curNode++) {
PastryNode node = factory.newNode();
NetworkHandler app = new NetworkHandler(node, mLog);
apps.add(app);
node.boot(bootaddress);
synchronized(node) {
while(!node.isReady() && !node.joinFailed()) {
node.wait(500);
if (node.joinFailed()) {
throw new IOException("Could not join the FreePastry ring. Reason:"+node.joinFailedReason());
}
}
}
System.out.println("Finished creating new node: " + node);
mLog.append("Finished creating new node: " + node + "\n");
}
Iterator<NetworkHandler> i = apps.iterator();
NetworkHandler app = (NetworkHandler) i.next();
app.subscribe();
public class NetworkHandler implements ScribeClient, Application {
int seqNum = 0;
CancellableTask publishTask;
Scribe myScribe;
Topic myTopic;
JTextArea mLog;
protected Endpoint endpoint;
public NetworkHandler(Node node, JTextArea log) {
this.endpoint = node.buildEndpoint(this, "myinstance");
mLog = log;
myScribe = new ScribeImpl(node,"myScribeInstance");
myTopic = new Topic(new PastryIdFactory(node.getEnvironment()), "example topic");
System.out.println("myTopic = "+myTopic);
mLog.append("myTopic = "+myTopic + "\n");
endpoint.register();
}
public void subscribe() {
myScribe.subscribe(myTopic, this);
}
}
freepastry.params
# this file holds the default values for pastry and it's applications
# you do not need to modify the default.params file to override these values
# instead you can use your own params file to set values to override the
# defaults. You can specify this file by constructing your
# rice.environment.Environment() with the filename you wish to use
# typically, you will want to be able to pass this file name from the command
# line
# max number of handles stored per routing table entry
pastry_rtMax = 1
pastry_rtBaseBitLength = 4
# leafset size
pastry_lSetSize = 24
# maintenance frequencies
pastry_leafSetMaintFreq = 60
pastry_routeSetMaintFreq = 900
# drop the message if pastry is not ready
pastry_messageDispatch_bufferIfNotReady = false
# number of messages to buffer while an app hasn't yet been registered
pastry_messageDispatch_bufferSize = 32
# FP 2.1 uses the new transport layer
transport_wire_datagram_receive_buffer_size = 131072
transport_wire_datagram_send_buffer_size = 65536
transport_epoch_max_num_addresses = 2
transport_sr_max_num_hops = 5
# proximity neighbor selection
transport_use_pns = true
# number of rows in the routing table to consider during PNS
# valid values are ALL, or a number
pns_num_rows_to_use = 10
# commonapi testing parameters
# direct or socket
commonapi_testing_exit_on_failure = true
commonapi_testing_protocol = direct
commonapi_testing_startPort = 5009
commonapi_testing_num_nodes = 10
# set this to specify the bootstrap node
#commonapi_testing_bootstrap = localhost:5009
# random number generator's seed, "CLOCK" uses the current clock time
random_seed = CLOCK
# sphere, euclidean or gt-itm
direct_simulator_topology = sphere
# -1 starts the simulation with the current time
direct_simulator_start_time = -1
#pastry_direct_use_own_random = true
#pastry_periodic_leafset_protocol_use_own_random = true
pastry_direct_gtitm_matrix_file=GNPINPUT
# the number of stubs in your network
pastry_direct_gtitm_max_overlay_size=1000
# the number of virtual nodes at each stub: this allows you to simulate multiple "LANs" and allows cheeper scaling
pastry_direct_gtitm_nodes_per_stub=1
# the factor to multiply your file by to reach millis. Set this to 0.001 if your file is in microseconds. Set this to 1000 if your file is in seconds.
pastry_direct_gtitm_delay_factor=1.0
#millis of the maximum network delay for the generated network topologies
pastry_direct_max_diameter=200
pastry_direct_min_delay=2
#setting this to false will use the old protocols which are about 200 times as fast, but may cause routing inconsistency in a real network. Probably won't in a simulator because it will never be incorrect about liveness
pastry_direct_guarantee_consistency=true
# rice.pastry.socket parameters
# tells the factory you intend to use multiple nodes
# this causes the logger to prepend all entries with the nodeid
pastry_factory_multipleNodes = true
pastry_factory_selectorPerNode = false
pastry_factory_processorPerNode = false
# number of bootstap nodehandles to fetch in parallel
pastry_factory_bootsInParallel = 1
# the maximum size of a message
pastry_socket_reader_selector_deserialization_max_size = 1000000
# the maximum number of outgoing messages to queue when a socket is slower than the number of messages you are queuing
pastry_socket_writer_max_queue_length = 30
pastry_socket_writer_max_msg_size = 20480
pastry_socket_repeater_buffer_size = 65536
pastry_socket_pingmanager_smallPings=true
pastry_socket_pingmanager_datagram_receive_buffer_size = 131072
pastry_socket_pingmanager_datagram_send_buffer_size = 65536
# the time before it will retry a route that was already found dead
pastry_socket_srm_check_dead_throttle = 300000
pastry_socket_srm_proximity_timeout = 3600000
pastry_socket_srm_ping_throttle = 30000
pastry_socket_srm_default_rto = 3000
pastry_socket_srm_rto_ubound = 10000
pastry_socket_srm_rto_lbound = 50
pastry_socket_srm_gain_h = 0.25
pastry_socket_srm_gain_g = 0.125
pastry_socket_scm_max_open_sockets = 300
pastry_socket_scm_max_open_source_routes = 30
# the maximum number of source routes to attempt, setting this to 0 will
# effectively eliminate source route attempts
# setting higher than the leafset does no good, it will be bounded by the leafset
# a larger number tries more source routes, which could give you a more accurate
# determination, however, is more likely to lead to congestion collapse
pastry_socket_srm_num_source_route_attempts = 8
pastry_socket_scm_socket_buffer_size = 32768
# this parameter is multiplied by the exponential backoff when doing a liveness check so the first will be 800, then 1600, then 3200 etc...
pastry_socket_scm_ping_delay = 800
# adds some fuzziness to the pings to help prevent congestion collapse, so this will make the ping be advanced or delayed by this factor
pastry_socket_scm_ping_jitter = 0.1
# how many pings until we call the node faulty
pastry_socket_scm_num_ping_tries = 5
pastry_socket_scm_write_wait_time = 30000
pastry_socket_scm_backoff_initial = 250
pastry_socket_scm_backoff_limit = 5
pastry_socket_pingmanager_testSourceRouting = false
pastry_socket_increment_port_after_construction = true
# if you want to allow connection to 127.0.0.1, set this to true
pastry_socket_allow_loopback = false
# these params will be used if the computer attempts to bind to the loopback address, they will open a socket to this address/port to identify which network adapter to bind to
pastry_socket_known_network_address = yahoo.com
pastry_socket_known_network_address_port = 80
pastry_socket_use_own_random = true
pastry_socket_random_seed = clock
# force the node to be a seed node
rice_socket_seed = false
# the parameter simulates some nodes being firewalled, base on rendezvous_test_num_firewalled
rendezvous_test_firewall = false
# probabilistic fraction of firewalled nodes
rendezvous_test_num_firewalled = 0.3
# don't firewall the first node, useful for testing
rendezvous_test_makes_bootstrap = false
# FP 2.1 uses the new transport layer
transport_wire_datagram_receive_buffer_size = 131072
transport_wire_datagram_send_buffer_size = 65536
# NAT/UPnP settings
nat_network_prefixes = 127.0.0.1;10.;192.168.
# Enable and set this if you have already set up port forwarding and know the external address
#external_address = 123.45.67.89:1234
#enable this if you set up port forwarding (on the same port), but you don't
#know the external address and you don't have UPnP enabled
#this is useful for a firwall w/o UPnP support, and your IP address isn't static
probe_for_external_address = true
# values how to probe
pastry_proxy_connectivity_timeout = 15000
pastry_proxy_connectivity_tries = 3
# possible values: always, never, prefix (prefix is if the localAddress matches any of the nat_network_prefixes
# whether to search for a nat using UPnP (default: prefix)
nat_search_policy = prefix
# whether to verify connectivity (default: boot)
firewall_test_policy = never
# policy for setting port forwarding the state of the firewall if there is already a conflicting rule: overwrite, fail (throw exception), change (use different port)
# you may want to set this to overwrite or fail on the bootstrap nodes, but most freepastry applications can run on any available port, so the default is change
nat_state_policy = change
# the name of the application in the firewall, set this if you want your application to have a more specific name
nat_app_name = freepastry
# how long to wait for responses from the firewall, in millis
nat_discovery_timeout = 5000
# how many searches to try to find a free firewall port
nat_find_port_max_tries = 10
# uncomment this to use UPnP NAT port forwarding, you need to include in the classpath: commons-jxpath-1.1.jar:commons-logging.jar:sbbi-upnplib-xxx.jar
nat_handler_class = rice.pastry.socket.nat.sbbi.SBBINatHandler
# hairpinning:
# default "prefix" requires more bandwidth if you are behind a NAT. It enables multiple IP
# addresses in the NodeHandle if you are behind a NAT. These are usually the internet routable address,
# and the LAN address (usually 192.168.x.x)
# you can set this to never if any of the following conditions hold:
# a) you are the only FreePastry node behind this address
# b) you firewall supports hairpinning see
# http://scm.sipfoundry.org/rep/ietf-drafts/behave/draft-ietf-behave-nat-udp-03.html#rfc.section.6
nat_nodehandle_multiaddress = prefix
# if we are not scheduled for time on cpu in this time, we setReady(false)
# otherwise there could be message inconsistency, because
# neighbors may believe us to be dead. Note that it is critical
# to consider the amount of time it takes the transport layer to find a
# node faulty before setting this parameter, this parameter should be
# less than the minimum time required to find a node faulty
pastry_protocol_consistentJoin_max_time_to_be_scheduled = 15000
# in case messages are dropped or something, how often it will retry to
# send the consistent join message, to get verification from the entire
# leafset
pastry_protocol_consistentJoin_retry_interval = 30000
# parameter to control how long dead nodes are retained in the "failed set" in
# CJP (see ConsistentJoinProtocol ctor) (15 minutes)
pastry_protocol_consistentJoin_failedRetentionTime = 900000
# how often to cleanup the failed set (5 mins) (see ConsistentJoinProtocol ctor)
pastry_protocol_consistentJoin_cleanup_interval = 300000
# the maximum number of entries to send in the failed set, only sends the most
recent detected failures (see ConsistentJoinProtocol ctor)
pastry_protocol_consistentJoin_maxFailedToSend = 20
# how often we send/expect to be sent updates
pastry_protocol_periodicLeafSet_ping_neighbor_period = 20000
pastry_protocol_periodicLeafSet_lease_period = 30000
# what the grace period is to receive a periodic update, before checking
# liveness
pastry_protocol_periodicLeafSet_request_lease_throttle = 10000
# how many entries are kept in the partition handler's table
partition_handler_max_history_size=20
# how long entries in the partition handler's table are kept
# 90 minutes
partition_handler_max_history_age=5400000
# what fraction of the time a bootstrap host is checked
partition_handler_bootstrap_check_rate=0.05
# how often to run the partition handler
# 5 minutes
partition_handler_check_interval=300000
# the version number of the RouteMessage to transmit (it can receive anything that it knows how to)
# this is useful if you need to migrate an older ring
# you can change this value in realtime, so, you can start at 0 and issue a command to update it to 1
pastry_protocol_router_routeMsgVersion = 1
# should usually be equal to the pastry_rtBaseBitLength
p2p_splitStream_stripeBaseBitLength = 4
p2p_splitStream_policy_default_maximum_children = 24
p2p_splitStream_stripe_max_failed_subscription = 5
p2p_splitStream_stripe_max_failed_subscription_retry_delay = 1000
#multiring
p2p_multiring_base = 2
#past
p2p_past_messageTimeout = 30000
p2p_past_successfulInsertThreshold = 0.5
#replication
# fetch delay is the delay between fetching successive keys
p2p_replication_manager_fetch_delay = 500
# the timeout delay is how long we take before we time out fetching a key
p2p_replication_manager_timeout_delay = 20000
# this is the number of keys to delete when we detect a change in the replica set
p2p_replication_manager_num_delete_at_once = 100
# this is how often replication will wake up and do maintainence; 10 mins
p2p_replication_maintenance_interval = 600000
# the maximum number of keys replication will try to exchange in a maintainence message
p2p_replication_max_keys_in_message = 1000
#scribe
p2p_scribe_maintenance_interval = 180000
#time for a subscribe fail to be thrown (in millis)
p2p_scribe_message_timeout = 15000
#util
p2p_util_encryptedOutputStream_buffer = 32678
#aggregation
p2p_aggregation_logStatistics = true
p2p_aggregation_flushDelayAfterJoin = 30000
#5 MINS
p2p_aggregation_flushStressInterval = 300000
#5 MINS
p2p_aggregation_flushInterval = 300000
#1024*1024
p2p_aggregation_maxAggregateSize = 1048576
p2p_aggregation_maxObjectsInAggregate = 25
p2p_aggregation_maxAggregatesPerRun = 2
p2p_aggregation_addMissingAfterRefresh = true
p2p_aggregation_maxReaggregationPerRefresh = 100
p2p_aggregation_nominalReferenceCount = 2
p2p_aggregation_maxPointersPerAggregate = 100
#14 DAYS
p2p_aggregation_pointerArrayLifetime = 1209600000
#1 DAY
p2p_aggregation_aggregateGracePeriod = 86400000
#15 MINS
p2p_aggregation_aggrRefreshInterval = 900000
p2p_aggregation_aggrRefreshDelayAfterJoin = 70000
#3 DAYS
p2p_aggregation_expirationRenewThreshold = 259200000
p2p_aggregation_monitorEnabled = false
#15 MINS
p2p_aggregation_monitorRefreshInterval = 900000
#5 MINS
p2p_aggregation_consolidationDelayAfterJoin = 300000
#15 MINS
p2p_aggregation_consolidationInterval = 900000
#14 DAYS
p2p_aggregation_consolidationThreshold = 1209600000
p2p_aggregation_consolidationMinObjectsInAggregate = 20
p2p_aggregation_consolidationMinComponentsAlive = 0.8
p2p_aggregation_reconstructionMaxConcurrentLookups = 10
p2p_aggregation_aggregateLogEnabled = true
#1 HOUR
p2p_aggregation_statsGranularity = 3600000
#3 WEEKS
p2p_aggregation_statsRange = 1814400000
p2p_aggregation_statsInterval = 60000
p2p_aggregation_jitterRange = 0.1
# glacier
p2p_glacier_logStatistics = true
p2p_glacier_faultInjectionEnabled = false
p2p_glacier_insertTimeout = 30000
p2p_glacier_minFragmentsAfterInsert = 3.0
p2p_glacier_refreshTimeout = 30000
p2p_glacier_expireNeighborsDelayAfterJoin = 30000
#5 MINS
p2p_glacier_expireNeighborsInterval = 300000
#5 DAYS
p2p_glacier_neighborTimeout = 432000000
p2p_glacier_syncDelayAfterJoin = 30000
#5 MINS
p2p_glacier_syncMinRemainingLifetime = 300000
#insertTimeout
p2p_glacier_syncMinQuietTime = 30000
p2p_glacier_syncBloomFilterNumHashes = 3
p2p_glacier_syncBloomFilterBitsPerKey = 4
p2p_glacier_syncPartnersPerTrial = 1
#1 HOUR
p2p_glacier_syncInterval = 3600000
#3 MINUTES
p2p_glacier_syncRetryInterval = 180000
p2p_glacier_syncMaxFragments = 100
p2p_glacier_fragmentRequestMaxAttempts = 0
p2p_glacier_fragmentRequestTimeoutDefault = 10000
p2p_glacier_fragmentRequestTimeoutMin = 10000
p2p_glacier_fragmentRequestTimeoutMax = 60000
p2p_glacier_fragmentRequestTimeoutDecrement = 1000
p2p_glacier_manifestRequestTimeout = 10000
p2p_glacier_manifestRequestInitialBurst = 3
p2p_glacier_manifestRequestRetryBurst = 5
p2p_glacier_manifestAggregationFactor = 5
#3 MINUTES
p2p_glacier_overallRestoreTimeout = 180000
p2p_glacier_handoffDelayAfterJoin = 45000
#4 MINUTES
p2p_glacier_handoffInterval = 240000
p2p_glacier_handoffMaxFragments = 10
#10 MINUTES
p2p_glacier_garbageCollectionInterval = 600000
p2p_glacier_garbageCollectionMaxFragmentsPerRun = 100
#10 MINUTES
p2p_glacier_localScanInterval = 600000
p2p_glacier_localScanMaxFragmentsPerRun = 20
p2p_glacier_restoreMaxRequestFactor = 4.0
p2p_glacier_restoreMaxBoosts = 2
p2p_glacier_rateLimitedCheckInterval = 30000
p2p_glacier_rateLimitedRequestsPerSecond = 3
p2p_glacier_enableBulkRefresh = true
p2p_glacier_bulkRefreshProbeInterval = 3000
p2p_glacier_bulkRefreshMaxProbeFactor = 3.0
p2p_glacier_bulkRefreshManifestInterval = 30000
p2p_glacier_bulkRefreshManifestAggregationFactor = 20
p2p_glacier_bulkRefreshPatchAggregationFactor = 50
#3 MINUTES
p2p_glacier_bulkRefreshPatchInterval = 180000
p2p_glacier_bulkRefreshPatchRetries = 2
p2p_glacier_bucketTokensPerSecond = 100000
p2p_glacier_bucketMaxBurstSize = 200000
p2p_glacier_jitterRange = 0.1
#1 MINUTE
p2p_glacier_statisticsReportInterval = 60000
p2p_glacier_maxActiveRestores = 3
#transport layer testing params
org.mpisws.p2p.testing.transportlayer.replay.Recorder_printlog = true
# logging
#default log level
loglevel = WARNING
#example of enabling logging on the endpoint:
#rice.p2p.scribe#ScribeRegrTest-endpoint_loglevel = INFO
logging_packageOnly = true
logging_date_format = yyyyMMdd.HHmmss.SSS
logging_enable=true
# 24 hours
log_rotate_interval = 86400000
# the name of the active log file, and the filename prefix of rotated log
log_rotate_filename = freepastry.log
# the format of the date for the rotating log
log_rotating_date_format = yyyyMMdd.HHmmss.SSS
# true will tell the environment to ues the FileLogManager
environment_logToFile = false
# the prefix for the log files (otherwise will be named after the nodeId)
fileLogManager_filePrefix =
# the suffix for the log files
fileLogManager_fileSuffix = .log
# wether to keep the line prefix (declaring the node id) for each line of the log
fileLogManager_keepLinePrefix = false
fileLogManager_multipleFiles = true
fileLogManager_defaultFileName = main
# false = append true = overwrite
fileLogManager_overwrite_existing_log_file = false
# the amount of time the LookupService tutorial app will wait before timing out
# in milliseconds, default is 30 seconds
lookup_service.timeout = 30000
# how long to wait before the first retry
lookup_service.firstTimeout = 500
Edit: Comfirmed with wireshark that the message indeed reach the computer freepastry just don't accept the connection.
Not sure what you mean by "not work". To test the connectivity between your client and your server (sit behind NAT), you just need do something like "telnet mIP mBindport" on your client side, assuming you have a telnet utility (default on Linux and Mac, you can install one, like nc ("netcat") on your windows).
If the port forwarding is set up correctly, you should see something like the following when the TCP connection is set up with your server.
Connected to localhost.
Escape character is '^]'.
Once the TCP session sets up correctly, you can stop the "telnet" program and use your real client (in java) to talk to your server, it should work fine.
If the TCP session didn't set up, you may want to check on the server side. Use either a wireshark or tcpdump to capture packets with filter "tcp port 50001", and run the telnet command above to check if there is a TCP packet come in.
If nothing show up in wireshark or tcpdump, then your firewall (like portforwarding) is not set up correctly.
If the TCP packet does show up in wireshark or tcpdump, then your server program may be at fault. Check the IP address it binds to using the command (linux):
netstat -antp | grep 50001
(on windows, the command is slightly different).
Typically it should bind to IP address 0.0.0.0 (all ip), if it doesn't, you should check whether the IP it binds to has connectivity/route to the outside world (outside the NAT).
Good luck.
I would try to set your IP as your local for the computer Free Pastry is running on. It sounds like the computer is getting the information but Free Pastry is looking for it on a different address. If you set your mIP to be local, I think it would work. This would be if it is behind the router/NAT.
Port forwarding forwards packets from your public IP on port 50001 to your internal computer IP on whatever port you set, normally the same 50001. If you set your program to listen on the public IP, it doesn't have access to it so it will not accept any packets/messages. Set to listen on the computers IP, or 0.0.0.0/localhost, it should accept any packets/messages on that port.

C callback with JNA makes JRE crash

I'm having problems handling callbacks in JNA.
I'm trying to use a C API that uses callbacks to handle several session events (logged in, logged out, connection problem...).
The session object (called sp_session) is an opaque struct. All the callbacks are registered in a sp_session_callbacks structure. According to the API, I am supposed to declare the callbacks object, and put it into a Config object that I will provide when creating the sp_session object. If I don't want to use certain callbacks, I am supposed to initialize them with null. The API is using the __stdcall calling convention.
Here is a snippet of the C header that's relevant to my problem:
#define SP_CALLCONV __stdcall
typedef struct sp_session sp_session; ///< Representation of a session
typedef enum sp_error {
SP_ERROR_OK = 0,
SP_ERROR_BAD_API_VERSION = 1,
/* More errors */
} sp_error;
typedef struct sp_session_callbacks {
/**
* Called when login has been processed and was successful
*/
void (SP_CALLCONV *logged_in)(sp_session *session, sp_error error);
/**
* Called when logout has been processed. Either called explicitly
* if you initialize a logout operation, or implicitly if there
* is a permanent connection error
*
* #param[in] session Session
*/
void (SP_CALLCONV *logged_out)(sp_session *session);
/**
* Called when there is a connection error, and the library has problems
* reconnecting to the Spotify service. Could be called multiple times (as
* long as the problem is present)
*/
void (SP_CALLCONV *connection_error)(sp_session *session, sp_error error);
/* More callbacks */
} sp_session_callbacks;
/**
* Initialize a session. The session returned will be initialized, but you will need
* to log in before you can perform any other operation
*/
SP_LIBEXPORT(sp_error) sp_session_create(const sp_session_config *config, sp_session **sess);
Here is my equivalent JNA code:
The sp_session object
public class sp_session extends PointerType{
public sp_session(Pointer address) {
super(address);
}
public sp_session() {
super();
}
}
The sp_session_callbacks object, containing all the callbacks
public class sp_session_callbacks extends Structure{
public LoggedIn logged_in;
public LoggedOut logged_out;
public ConnectionError connection_error;
}
The callbacks object (here is LoggedIn, but of course I have one for each callback)
public interface LoggedIn extends StdCallCallback {
public void logged_in(sp_session session, int error);
}
The native library, with the declaration of all the methods
public interface JLibspotify extends StdCallLibrary{
int sessionCreate(sp_session_config config, PointerByReference sess);
int sessionLogin(sp_session session, String username, String password);
// All the other methods defined by the API
}
And my main class, binding it all together
public class Test{
static{
System.loadLibrary("libspotify");
}
public static void main(String[] args){
JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class);
sp_session_config cfg = new sp_session_config();
}
sp_session_callbacks sessCallbacks = new sp_session_callbacks();
LoggedIn loggedInCallback = new LoggedIn(){
public void logged_in(sp_session session, int error) {
System.out.println("logged_in() called");
}
};
sessCallbacks.logged_in = loggedInCallback;
cfg.session_callbacks = sessCallbacks;
PointerByReference sessionPbr = new PointerByReference();
int error_id = sessionCreate(cfg, sessionPbr); // CRASHES HERE
sp_session mySession = new sp_session(sessionPbr.getValue());
}
}
So, the sessionCreate function call makes the JRE crash with the trace at the end of the post EXCEPTION_ACCESS_VIOLATION (0xc0000005) problematic frame: C [jna3666290841889849729.dll+0xa3f4].
It looks like the logged_in callback is causing this, because when I set it to null it runs ok. Plus, if I initialize the connection_error callback, that has the exact same signature, it doesn't crash either.
I'm running version 3.2.7 of JNA. I tried with an anterior version (3.0.9) and it also failed.
I'm running the JDK 1.7 beta version, but I tried with the 1.6 and it also failed.
Thank you!
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0499a3f4, pid=1368, tid=1344
#
# JRE version: 7.0-b129
# Java VM: Java HotSpot(TM) Client VM (21.0-b01 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [jna3666290841889849729.dll+0xa3f4]
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
--------------- T H R E A D ---------------
Current thread (0x01b79400): JavaThread "main" [_thread_in_native, id=1344, stack(0x00340000,0x00390000)]
siginfo: ExceptionCode=0xc0000005, reading address 0x1993053a
Registers:
EAX=0x19930522, EBX=0x100dc77c, ECX=0x00010004, EDX=0x1008d3e0
ESP=0x0038f58c, EBP=0x0038f5b4, ESI=0x0038f5a4, EDI=0x100b79b0
EIP=0x0499a3f4, EFLAGS=0x00210212
Top of Stack: (sp=0x0038f58c)
0x0038f58c: 100dc77c 0038f5a4 00010004 0038f688
0x0038f59c: 05983de0 05981330 0598289c 05983de0
0x0038f5ac: 05983de0 00000014 0038f688 1008d3ea
0x0038f5bc: 05983de0 10030d77 0038fc44 100b79b0
0x0038f5cc: ffffffff 1008d334 00000000 05983de0
0x0038f5dc: 1008d3e0 05983fc4 1008d9fd 0038f770
0x0038f5ec: 00000000 00000000 7275016a 055310b0
0x0038f5fc: 00000000 00010001 00000000 00000000
Instructions: (pc=0x0499a3f4)
0x0499a3d4: 01 00 89 e5 57 56 8d 75 f0 53 83 ec 1c 8b 7d 14
0x0499a3e4: 8b 5f 4c 8b 03 89 4c 24 08 89 74 24 04 89 1c 24
0x0499a3f4: ff 50 18 83 ec 0c 85 c0 0f 94 c0 0f b6 c0 85 c0
0x0499a404: 89 45 ec 75 19 8b 03 31 d2 89 54 24 08 89 74 24
Register to memory mapping:
EAX=0x19930522 is an unknown value
EBX=0x100dc77c is an unknown value
ECX=0x00010004 is an unknown value
EDX=0x1008d3e0 is an unknown value
ESP=0x0038f58c is pointing into the stack for thread: 0x01b79400
EBP=0x0038f5b4 is pointing into the stack for thread: 0x01b79400
ESI=0x0038f5a4 is pointing into the stack for thread: 0x01b79400
EDI=0x100b79b0 is an unknown value
Stack: [0x00340000,0x00390000], sp=0x0038f58c, free space=317k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [jna3666290841889849729.dll+0xa3f4] Java_com_sun_jna_Native_initialize_1ffi_1type+0x1054
C [libspotify.dll+0x8d3ea] sp_error_message+0x35a
C [jna3666290841889849729.dll+0xcb77] Java_com_sun_jna_Native_initialize_1ffi_1type+0x37d7
C [jna3666290841889849729.dll+0xc7c2] Java_com_sun_jna_Native_initialize_1ffi_1type+0x3422
C [jna3666290841889849729.dll+0x4561] Java_com_sun_jna_Pointer__1getString+0xa31
C [jna3666290841889849729.dll+0x4d2e] Java_com_sun_jna_Function_invokeInt+0x2e
j com.sun.jna.Function.invokeInt(I[Ljava/lang/Object;)I+0
j com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;Z)Ljava/lang/Object;+315
j com.sun.jna.Function.invoke(Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+214
j com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+341
j $Proxy0.sp_session_create(Lcom/nbarraille/jspotify/model/sp_session_config;Lcom/sun/jna/ptr/PointerByReference;)I+20
j com.nbarraille.jspotify.main.Test.main([Ljava/lang/String;)V+273
v ~StubRoutines::call_stub
V [jvm.dll+0x115f6d]
V [jvm.dll+0x1b788e]
V [jvm.dll+0x115fed]
V [jvm.dll+0xa2507]
V [jvm.dll+0xac867]
C [javaw.exe+0x209e]
C [javaw.exe+0xa23b]
C [javaw.exe+0xa2c5]
C [kernel32.dll+0x51194] BaseThreadInitThunk+0x12
C [ntdll.dll+0x5b429] RtlInitializeExceptionChain+0x63
C [ntdll.dll+0x5b3fc] RtlInitializeExceptionChain+0x36
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.sun.jna.Function.invokeInt(I[Ljava/lang/Object;)I+0
j com.sun.jna.Function.invoke([Ljava/lang/Object;Ljava/lang/Class;Z)Ljava/lang/Object;+315
j com.sun.jna.Function.invoke(Ljava/lang/Class;[Ljava/lang/Object;Ljava/util/Map;)Ljava/lang/Object;+214
j com.sun.jna.Library$Handler.invoke(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;+341
j $Proxy0.sp_session_create(Lcom/nbarraille/jspotify/model/sp_session_config;Lcom/sun/jna/ptr/PointerByReference;)I+20
j com.nbarraille.jspotify.main.Test.main([Ljava/lang/String;)V+273
v ~StubRoutines::call_stub
--------------- P R O C E S S ---------------
Java Threads: ( => current thread )
0x0182fc00 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=4664, stack(0x04170000,0x041c0000)]
0x0182ac00 JavaThread "C1 CompilerThread0" daemon [_thread_blocked, id=1728, stack(0x01b20000,0x01b70000)]
0x01829800 JavaThread "Attach Listener" daemon [_thread_blocked, id=112, stack(0x04020000,0x04070000)]
0x01826400 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=5836, stack(0x03ea0000,0x03ef0000)]
0x01819800 JavaThread "Finalizer" daemon [_thread_blocked, id=4724, stack(0x03f80000,0x03fd0000)]
0x01817800 JavaThread "Reference Handler" daemon [_thread_blocked, id=3940, stack(0x01ad0000,0x01b20000)]
=>0x01b79400 JavaThread "main" [_thread_in_native, id=1344, stack(0x00340000,0x00390000)]
Other Threads:
0x01816400 VMThread [stack: 0x01a30000,0x01a80000] [id=3876]
0x01843000 WatcherThread [stack: 0x040d0000,0x04120000] [id=4636]
VM state:not at safepoint (normal execution)
VM Mutex/Monitor currently owned by a thread: None
Heap
def new generation total 4928K, used 3630K [0x23450000, 0x239a0000, 0x289a0000)
eden space 4416K, 82% used [0x23450000, 0x237db858, 0x238a0000)
from space 512K, 0% used [0x238a0000, 0x238a0000, 0x23920000)
to space 512K, 0% used [0x23920000, 0x23920000, 0x239a0000)
tenured generation total 10944K, used 0K [0x289a0000, 0x29450000, 0x33450000)
the space 10944K, 0% used [0x289a0000, 0x289a0000, 0x289a0200, 0x29450000)
compacting perm gen total 12288K, used 860K [0x33450000, 0x34050000, 0x37450000)
the space 12288K, 7% used [0x33450000, 0x33527190, 0x33527200, 0x34050000)
ro space 10240K, 43% used [0x37450000, 0x3789ce40, 0x3789d000, 0x37e50000)
rw space 12288K, 53% used [0x37e50000, 0x384c2710, 0x384c2800, 0x38a50000)
Code Cache [0x01e90000, 0x01f20000, 0x03e90000)
total_blobs=234 nmethods=82 adapters=88 free_code_cache=32972224 largest_free_block=0
Dynamic libraries:
0x00880000 - 0x008b0000 C:\Program Files\Java\jdk1.7.0\bin\javaw.exe
0x778f0000 - 0x77a2d000 C:\Windows\SYSTEM32\ntdll.dll
0x77070000 - 0x77144000 C:\Windows\system32\kernel32.dll
0x75cf0000 - 0x75d3a000 C:\Windows\system32\KERNELBASE.dll
0x60000000 - 0x60041000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\midas32.dll
0x61000000 - 0x61028000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\plugin_base.m32
0x67000000 - 0x67048000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\plugin_nt.m32
0x64000000 - 0x64021000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\plugin_registry.m32
0x62000000 - 0x6202d000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\plugin_extra.m32
0x65000000 - 0x6501a000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\plugin_net.m32
0x63000000 - 0x630a6000 C:\Program Files\BitDefender\BitDefender 2011\Active Virus Control\Midas_00078_002\plugin_fragments.m32
0x75e10000 - 0x75eb0000 C:\Windows\system32\ADVAPI32.dll
0x775c0000 - 0x7766c000 C:\Windows\system32\msvcrt.dll
0x75d50000 - 0x75d69000 C:\Windows\SYSTEM32\sechost.dll
0x77670000 - 0x77711000 C:\Windows\system32\RPCRT4.dll
0x76f00000 - 0x76fc9000 C:\Windows\system32\USER32.dll
0x77a50000 - 0x77a9e000 C:\Windows\system32\GDI32.dll
0x77a30000 - 0x77a3a000 C:\Windows\system32\LPK.dll
0x75d70000 - 0x75e0d000 C:\Windows\system32\USP10.dll
0x74830000 - 0x749ce000 C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7600.16661_none_420fe3fa2b8113bd\COMCTL32.dll
0x772f0000 - 0x77347000 C:\Windows\system32\SHLWAPI.dll
0x775a0000 - 0x775bf000 C:\Windows\system32\IMM32.DLL
0x75eb0000 - 0x75f7c000 C:\Windows\system32\MSCTF.dll
0x72740000 - 0x727fe000 C:\Program Files\Java\jdk1.7.0\jre\bin\msvcr100.dll
0x01b80000 - 0x01e89000 C:\Program Files\Java\jdk1.7.0\jre\bin\client\jvm.dll
0x746c0000 - 0x746f2000 C:\Windows\system32\WINMM.dll
0x73920000 - 0x7392c000 C:\Program Files\Java\jdk1.7.0\jre\bin\verify.dll
0x73330000 - 0x73350000 C:\Program Files\Java\jdk1.7.0\jre\bin\java.dll
0x75d40000 - 0x75d45000 C:\Windows\system32\PSAPI.DLL
0x733a0000 - 0x733b3000 C:\Program Files\Java\jdk1.7.0\jre\bin\zip.dll
0x10000000 - 0x10259000 C:\Windows\System32\libspotify.dll
0x77150000 - 0x77185000 C:\Windows\system32\WS2_32.dll
0x77a40000 - 0x77a46000 C:\Windows\system32\NSI.dll
0x75ba0000 - 0x75cbc000 C:\Windows\system32\CRYPT32.dll
0x75ab0000 - 0x75abc000 C:\Windows\system32\MSASN1.dll
0x74ee0000 - 0x74f38000 C:\Windows\system32\WINHTTP.dll
0x74e90000 - 0x74edf000 C:\Windows\system32\webio.dll
0x754c0000 - 0x754d6000 C:\Windows\system32\CRYPTSP.dll
0x75260000 - 0x7529b000 C:\Windows\system32\rsaenh.dll
0x750a0000 - 0x750b7000 C:\Windows\system32\USERENV.dll
0x75a40000 - 0x75a4b000 C:\Windows\system32\profapi.dll
0x75a30000 - 0x75a3c000 C:\Windows\system32\CRYPTBASE.dll
0x728a0000 - 0x728b6000 C:\Program Files\Java\jdk1.7.0\jre\bin\net.dll
0x75480000 - 0x754bc000 C:\Windows\system32\mswsock.dll
0x75470000 - 0x75476000 C:\Windows\System32\wship6.dll
0x73950000 - 0x73960000 C:\Windows\system32\NLAapi.dll
0x75340000 - 0x75384000 C:\Windows\system32\DNSAPI.dll
0x71030000 - 0x71038000 C:\Windows\System32\winrnr.dll
0x71020000 - 0x71030000 C:\Windows\system32\napinsp.dll
0x71000000 - 0x71012000 C:\Windows\system32\pnrpnsp.dll
0x74fd0000 - 0x74fd5000 C:\Windows\System32\wshtcpip.dll
0x74d30000 - 0x74d4c000 C:\Windows\system32\IPHLPAPI.DLL
0x74d20000 - 0x74d27000 C:\Windows\system32\WINNSI.DLL
0x70c60000 - 0x70c66000 C:\Windows\system32\rasadhlp.dll
0x71ba0000 - 0x71bd8000 C:\Windows\System32\fwpuclnt.dll
0x73930000 - 0x7393f000 C:\Program Files\Java\jdk1.7.0\jre\bin\nio.dll
0x04990000 - 0x049e5000 C:\Users\nbarraille\AppData\Local\Temp\jna3666290841889849729.dll
VM Arguments:
jvm_args: -Djava.library.path=C:\Windows\System32 -Dfile.encoding=Cp1252
java_command: com.nbarraille.jspotify.main.Test
Launcher Type: SUN_STANDARD
Environment Variables:
PATH=C:/Program Files/Java/jdk1.7.0/bin/../jre/bin/client;C:/Program Files/Java/jdk1.7.0/bin/../jre/bin;C:/Program Files/Java/jdk1.7.0/bin/../jre/lib/i386;C:\Windows\System32
USERNAME=nbarraille
OS=Windows_NT
PROCESSOR_IDENTIFIER=x86 Family 6 Model 23 Stepping 10, GenuineIntel
--------------- S Y S T E M ---------------
OS: Windows 7 Build 7600
CPU:total 2 (2 cores per cpu, 1 threads per core) family 6 model 23 stepping 10, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1
Memory: 4k page, physical 3624108k(885020k free), swap 7246452k(3637664k free)
vm_info: Java HotSpot(TM) Client VM (21.0-b01) for windows-x86 JRE (1.7.0-ea-b129), built on Feb 10 2011 07:43:39 by "java_re" with unknown MS VC++:1600
time: Mon Mar 07 14:25:08 2011
elapsed time: 0 seconds
EDIT:
*Code to test the API in C*
#include "api.h"
/* --- Data --- */
const uint8_t g_appkey[] = {/*My appkey*/};
/* --------------------------- SESSION CALLBACKS ------------------------- */
static void logged_in(sp_session *sess, sp_error error){
printf("logged_in() called: \n");
}
static void log_message(sp_session *sess, const char *data){
printf("log_message() called %s : \n", data);
}
static void notify_main_thread(sp_session *sess){
printf("notify_main_thread() called \n");
}
static sp_session_callbacks session_callbacks = {
//.logged_in = (void*)&logged_in,
//.notify_main_thread = (void*)&notify_main_thread,
//.log_message = (void*)&log_message,
};
static sp_session_config spconfig = {
.api_version = 7,
.cache_location = "tmp",
.settings_location = "tmp",
.application_key = g_appkey,
.application_key_size = sizeof(g_appkey),
.user_agent = "jspotify",
.callbacks = &session_callbacks,
.userdata = NULL
};
int main(int argc, char **argv)
{
sp_session *sp;
const char *username = "foo";
const char *password = "bar";
spconfig.application_key_size = sizeof(g_appkey);
printf("Creating session \n");
sp_error err = sp_session_create(&spconfig, &sp);
if(err != 0){
printf("Error occured: %d \n", err);
return 0;
}
printf("Login\n");
sp_session_login(sp, username, password);
Sleep(10000);
return 0;
}
When I run it like this (without callbacks), the output is:
Creating session
Login
And when I register the callbacks (uncomment the lines), it doesn't even print anything!
It looks like it doesn't print anything when a callback is called, because if I comment the sp_session_login line, only the declaration of notify_main_thread (which is the only one printed) will prevent the program from printing...
When you have a C structure like:
struct Foo {
Bar* bar
}
i.e. one which contains a pointer to another structure, your JNA implementation of Bar (class Bar extends Structure) must also implement the Structure.ByReference interface -- otherwise JNA will think that struct Foo contains an instance of struct Bar instead of a pointer to a struct Bar, and an illegal memory access will result as the C code interprets a value in the Bar instance as a pointer.
You need to add implements Structure.ByReference to the sp_session_callbacks class.
Thanks for inspiring me to look at JNA -- it's pretty cool!
Output of this code is:
sp_session_create returned 0
sp_session_login returned 0
log_message() called:14:16:53.825 I [ap:1388] Connecting to AP ap.spotify.com:4070
log_message() called:14:16:54.061 I [ap:938] Connected to AP: 193.182.8.11:4070
log_message() called:14:16:54.765 E [ap:3396] Connection error: 401
Process finished with exit code 0
import com.sun.jna.*;
import com.sun.jna.ptr.PointerByReference;
import java.sql.Connection;
public class JNATest {
// static {
// System.loadLibrary("libspotify");
// }
public interface JLibspotify extends Library {
int sp_session_create(sp_session_config config, PointerByReference sess);
int sp_session_login(sp_session session, String username, String password);
// All the other methods defined by the API
}
public static class sp_session extends PointerType {
public sp_session(Pointer address) {
super(address);
}
public sp_session() {
super();
}
}
public static class sp_session_config extends Structure {
public int api_version = 7; // The version of the Spotify API your application is compiled with.
public String cache_location = ".";
public String settings_location = ".";
public Pointer application_key; // Your application key.
public int application_key_size; // The size of the application key in bytes
public String user_agent = "jspotify";
public sp_session_callbacks callbacks; // Delivery callbacks for session events. NULL if not interested in any callbacks
public Pointer userdata; // User supplied data for your application
public boolean compress_playlists;
public boolean dont_save_metadata_for_playlists;
public boolean initially_unload_playlists;
}
public interface LoggedIn extends Callback {
public void logged_in(sp_session session, int error);
}
public interface LoggedOut extends Callback {
public void logged_out(sp_session session, int error);
}
public interface ConnectionError extends Callback {
public void connection_error(sp_session session, int error);
}
public static class sp_session_callbacks extends Structure implements Structure.ByReference{
public LoggedIn logged_in; // Called when login has been processed and was successful
public LoggedOut logged_out; // Called when logout has been processded. Either called explicitly if you initialize a logout operation, or implicitly if there is a permanent connection error.
public Callback metadata_updated; // Called whenever metadata has been updated. If you have metadata cached outside of libspotify, you should purge your caches and fetch new versions.
public ConnectionError connection_error; // Called when there is a connection error, and the library has problems reconnecting to the Spotify service. Could be called multiple times (as long as the problem is present)
public Callback message_to_user; // Called when the acces point wants to display a message to the user. In the desktop client, these are shown in a blueish toolbar just below the search box.
public Callback notify_main_thread; // Called when processing needs to take place on the main thread. You need to call sp_session_process_events() in the main thread to get libspotify to do more work. Failure to do so may cause request timeouts, or a lost connections.
public Callback music_delivery; // Called when there is decompressed audio data available.
public Callback play_token_lost; // Music has been paused because only one account may play music at the same time.
public Callback log_message; // Logging callback
public Callback end_of_track; // End of track. Called when the currently played track has reached its end.
public Callback streaming_error; // Streaming error. Called when streaming cannot start or continue.
public Callback userinfo_updated; // Called after user info (anything related to sp_user objects) have been updated.
public Callback start_playback; // Called when audio playback should start. For this to work correctly the application must also implement get_audio_buffer_stats(). This function is called from an internal session thread - you need to have proper synchronization. This function must never block.
public Callback stop_playback; // Called when audio playback should stop. For this to work correctly the application must also implement get_audio_buffer_stats(). This function is called from an internal session thread - you need to have proper synchronization. This function must never block.
public Callback get_audio_buffer_stats; // Called to query application about its audio buffer. This function is called from an internal session thread - you need to have proper synchronization! This function must never block.
}
private static final char[] APP_KEY ={/* Appkey here**/;
public static void main(String[] args) throws InterruptedException {
JLibspotify lib = (JLibspotify) Native.loadLibrary("spotify", JLibspotify.class);
sp_session_config cfg = new sp_session_config();
Pointer ptr = new Memory(APP_KEY.length);
ptr.write(0, toBytes(APP_KEY), 0, APP_KEY.length);
cfg.application_key = ptr;
cfg.application_key_size = APP_KEY.length;
sp_session_callbacks sessCallbacks = new sp_session_callbacks();
LoggedIn loggedInCallback = new LoggedIn() {
public void logged_in(sp_session session, int error) {
System.out.println("logged_in() called");
}
};
ConnectionError connectionErrorCallback = new ConnectionError() {
public void connection_error(sp_session session, int error) {
System.out.println("connection_error() called");
}
};
LoggedOut loggedOutCallback = new LoggedOut() {
public void logged_out(sp_session session, int error) {
System.out.println("logged_out() called");
}
};
sessCallbacks.logged_in = loggedInCallback;
sessCallbacks.connection_error = connectionErrorCallback;
sessCallbacks.logged_out = loggedOutCallback;
sessCallbacks.log_message = new Callback() {
public void callback(sp_session session, String message) {
System.out.println("log_message() called:" + message);
}
};
cfg.callbacks = sessCallbacks;
PointerByReference sessionPbr = new PointerByReference();
int error_id = lib.sp_session_create(cfg, sessionPbr); // CRASHES HERE
System.out.println("sp_session_create returned " + error_id);
//
sp_session mySession = new sp_session(sessionPbr.getValue());
error_id = lib.sp_session_login(mySession, "foo", "bar");
System.out.println("sp_session_login returned " + error_id);
Thread.sleep(1000);
}
public static byte[] toBytes(char[] key){
byte[] b = new byte[key.length];
for(int i =0; i < key.length; i++){
if(key[i] > 127){
b[i] = (byte)(key[i] - 256);
}else{
b[i] = (byte)key[i];
}
}
return b;
}
}
Here's a C program which does the same thing (with fewer callbacks -- you'll need to add more). It's for OS X so you may need to change the #include. As I can't get spotify in Australia I can't test it to see whether a successful login hits a callback, but the logging callback works.
#include <stdio.h>
#include <libspotify/api.h>
void SP_CALLCONV log_message(sp_session *session, const char *data) {
fprintf(stderr,"log_message: %s\n", data);
fflush(stderr);
}
void SP_CALLCONV connection_error(sp_session *session, sp_error error) {
fprintf(stderr,"connection_error: %d\n", error);
fflush(stderr);
}
int main(int argc, char** argv) {
static byte APP_KEY[] = {
/*the API key */};
static sp_session_callbacks callbacks;
callbacks.log_message = log_message;
callbacks.connection_error = connection_error;
static sp_session_config cfg;
cfg.callbacks = &callbacks;
cfg.api_version = 7;
cfg.cache_location = ".";
cfg.settings_location = ".";
cfg.user_agent = "jspotify";
cfg.application_key = APP_KEY;
cfg.application_key_size = sizeof(APP_KEY);
sp_session* mySession;
int code = sp_session_create(&cfg, &mySession);
printf("sp_session_create returned %d\n", code);
sp_session_login(mySession, "foo", "bar");
printf("sp_session_login returned %d\n", code);
sleep(10);
}
If the C program calls callbacks which the Java version doesn't, then perhaps there's something wrong with the use of jna -- if not, perhaps there's something more to understand about spotify and when it calls callbacks. I agree that the docs seem to say that a successful login will call a callback, but perhaps they're out of date?

Categories

Resources