00001 // v8_db.h 00002 00003 /* Copyright 2009 10gen Inc. 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #pragma once 00019 00020 #include <v8.h> 00021 #include <cstring> 00022 #include <cstdio> 00023 #include <cstdlib> 00024 00025 #include "engine.h" 00026 #include "../client/dbclient.h" 00027 00028 namespace mongo { 00029 00030 // These functions may depend on the caller creating a handle scope and context scope. 00031 00032 v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ); 00033 void installDBTypes( v8::Handle<v8::ObjectTemplate>& global ); 00034 void installDBTypes( v8::Handle<v8::Object>& global ); 00035 00036 // the actual globals 00037 00038 mongo::DBClientBase * getConnection( const v8::Arguments& args ); 00039 00040 // Mongo members 00041 v8::Handle<v8::Value> mongoConsLocal(const v8::Arguments& args); 00042 v8::Handle<v8::Value> mongoConsExternal(const v8::Arguments& args); 00043 00044 v8::Handle<v8::Value> mongoFind(const v8::Arguments& args); 00045 v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args); 00046 v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args); 00047 v8::Handle<v8::Value> mongoUpdate(const v8::Arguments& args); 00048 00049 00050 v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args); 00051 v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args); 00052 v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args); 00053 v8::Handle<v8::Value> internalCursorObjsLeftInBatch(const v8::Arguments& args); 00054 00055 // DB members 00056 00057 v8::Handle<v8::Value> dbInit(const v8::Arguments& args); 00058 v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ); 00059 v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ); 00060 00061 v8::Handle<v8::Value> dbRefInit( const v8::Arguments& args ); 00062 v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args ); 00063 v8::Handle<v8::Value> dbTimestampInit( const v8::Arguments& args ); 00064 00065 v8::Handle<v8::Value> binDataInit( const v8::Arguments& args ); 00066 v8::Handle<v8::Value> binDataToString( const v8::Arguments& args ); 00067 00068 v8::Handle<v8::Value> numberLongInit( const v8::Arguments& args ); 00069 v8::Handle<v8::Value> numberLongToNumber(const v8::Arguments& args); 00070 v8::Handle<v8::Value> numberLongValueOf(const v8::Arguments& args); 00071 v8::Handle<v8::Value> numberLongToString(const v8::Arguments& args); 00072 00073 v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args ); 00074 v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::AccessorInfo& info ); 00075 00076 v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info); 00077 00078 v8::Handle<v8::Value> bsonsize( const v8::Arguments& args ); 00079 00080 // call with v8 mutex: 00081 void enableV8Interrupt(); 00082 void disableV8Interrupt(); 00083 00084 // The implementation below assumes that SERVER-1816 has been fixed - in 00085 // particular, interrupted() must return true if an interrupt was ever 00086 // sent; currently that is not the case if a new killop overwrites the data 00087 // for an old one 00088 template < v8::Handle< v8::Value > ( *f ) ( const v8::Arguments& ) > 00089 v8::Handle< v8::Value > v8Callback( const v8::Arguments &args ) { 00090 disableV8Interrupt(); // we don't want to have to audit all v8 calls for termination exceptions, so we don't allow these exceptions during the callback 00091 if ( globalScriptEngine->interrupted() ) { 00092 v8::V8::TerminateExecution(); // experimentally it seems that TerminateExecution() will override the return value 00093 return v8::Undefined(); 00094 } 00095 v8::Handle< v8::Value > ret; 00096 string exception; 00097 try { 00098 ret = f( args ); 00099 } 00100 catch( const std::exception &e ) { 00101 exception = e.what(); 00102 } 00103 catch( ... ) { 00104 exception = "unknown exception"; 00105 } 00106 enableV8Interrupt(); 00107 if ( globalScriptEngine->interrupted() ) { 00108 v8::V8::TerminateExecution(); 00109 return v8::Undefined(); 00110 } 00111 if ( !exception.empty() ) { 00112 // technically, ThrowException is supposed to be the last v8 call before returning 00113 ret = v8::ThrowException( v8::String::New( exception.c_str() ) ); 00114 } 00115 return ret; 00116 } 00117 00118 template < v8::Handle< v8::Value > ( *f ) ( const v8::Arguments& ) > 00119 v8::Local< v8::FunctionTemplate > newV8Function() { 00120 return v8::FunctionTemplate::New( v8Callback< f > ); 00121 } 00122 00123 // Preemption is going to be allowed for the v8 mutex, and some of our v8 00124 // usage is not preemption safe. So we are using an additional mutex that 00125 // will not be preempted. The V8Lock should be used in place of v8::Locker 00126 // except in certain special cases involving interrupts. 00127 namespace v8Locks { 00128 // the implementations are quite simple - objects must be destroyed in 00129 // reverse of the order created, and should not be shared between threads 00130 struct RecursiveLock { 00131 RecursiveLock(); 00132 ~RecursiveLock(); 00133 bool _unlock; 00134 }; 00135 struct RecursiveUnlock { 00136 RecursiveUnlock(); 00137 ~RecursiveUnlock(); 00138 bool _lock; 00139 }; 00140 } // namespace v8Locks 00141 class V8Lock { 00142 v8Locks::RecursiveLock _noPreemptionLock; 00143 v8::Locker _preemptionLock; 00144 }; 00145 struct V8Unlock { 00146 v8::Unlocker _preemptionUnlock; 00147 v8Locks::RecursiveUnlock _noPreemptionUnlock; 00148 }; 00149 } 00150