Paradigms Notes Malak
Paradigms Notes Malak
Objective: Run two applications able to exchange information. Make sense out of the received
bytes. Meaningful data = information
Networking manager opens the connection (established) whatever is in the networking manager of
end A gets to the end of B through a socket API. through system calls.
The logical location of a process is its IP address of the host/ machine, and after that the id of that
process within the host which is the port.
While every process has a PID, it doesn’t necessarily have a port number if it doesn’t need since it
doesn’t communicate with other processes.
Process B, when granted a port, asks the OS to listen to the network for incoming connection
requests. Process B uses a system call to listen to incoming requests on its behalf. In case we bypass
step 1: binding, process B will be assigned a different port number each time the machine reboots,
that’s why we need a static port number for the server.
Process A asks the NM through the socket API to open a connection on its behalf to process B
identified by IP Y port X. Without asking for it, A receives the first available free port number by NM.
A opens the connection actively. Prior to open it, needs to know info of B. Client
B opens the connection passively. Server is process written is a language that opens the connection
passively and has a well know IP and port.
For a communication to happen between 2 processes, one acts as server, one as a client.
Client: Socket connectiontoServer = new socket(location of server: ip address and port number 7000)
ss = new ServerSocket(7000) may throw an exception if the port has already been granted to another
process. It returns an object of type serversocket.
Socket communicationfromclient = ss.accept(); representation of type socket of the opened
connection.
Socket supports methods like send and receive which are I/O operations. In java, they are modeled
under the java.io package. Rather, we have: encapsulated stream objects.
These are abstract classes that read and write respectively from undefined channels.
out of S is read by in of C.
When one is in “in” reading mode, the other should be blocked to write.
We need to have well established rule to ensure proper communication that are not given by the
socket api. It gives the power of establishing connection but not the rules that governs the
communication. These sets of rules that guarantee the exchange of data are called protocole.
The client and server should speak the same protocol even if they are written in different
programming languages.
Protocol is horizontal contract between 2 communicating processes at run time. Client developer and
server developer.
The client opens a connection with the server and informs the server whether it wants
to download or upload a file using a header.
Header contains the metadata and is sent before the data itself.
read until \n
System.out.println("Server waiting...");
Text oriented in and out (readLine(_)) vs bytes oriented in and out (writeDouble(___)
Both built on top of the same stream (in and out). Whenever headerreader stops \n, dataIn
continues. Because it the same in that they work on.
Bind
While (1)
Close connection
Read is a system call, and its expensive, that’s why we use the bufferreader to buffer a large
number / more than needed and then flush everything directly to the ram through a buffer. Can read
a line (headerline)
The search for the existence of the file is not specified. Because it doesn’t involve the client, it’s
server business.
read from disk to array bytes in ram and then send the content through network
the vulnerability is fully trusting the input header form the client and not sanitizing the filename form
the header before concatenating it with the path.
CLIEEEEENT
An end user will launch the client and specify whether they want the upload or download
Implement a protocol
IETF authority that standardized other protocols: http, ftp, telnet, ssh, smtp, pop3, imap.
In addition to ip and port, now we need also the protocol that this server speaks to get the resource
http server is 80. It doesn’t make sense to have a default client port because its assigned randomly by
the NM.
HTTP 1.1:
Ip and port of the server, protocol, id of resource (name of the file, path…).
These 4 info could be represented in different ways, that is why we need a standard for them
RFC URI
Open connection from terminal. Open a telnet client to connect to http server. The null protocol /
void protocol. No specific headers are sent during a telnet communication. Use it to open the
connection, end user sends http header.
If_modified_since if_not_match
P2
Such a paradigm should hide (abstract) all the programming hassle and details mentioned above:
Designing a specific protocol or, in the best case, adopting and adapting an existing (maybe
standard) protocol
Managing connections, as well as corresponding streams, on both sides
Implementing the protocol, including (application) error management, on both sides
What is the verb is also consider a variable (generic protocol: not specific to the verb/method) allow
client to express a function name and parameters that the function takes an send them to server side
that will extract function name to look it up, if doesn’t exist, the generic protocol will express it to the
client, otherwise, invoke the function and extract the parameters related to it and pass them in the
function, execute, get result, and send it back to client side.
In addition to the contract/ generic protocol, we need a formal description of the function supported
by server side through a java interface, C header file, (remote API is the contract between
client/server) server: here is the API I support and implement, client needs to know the details of
those supported functions.
Using such a paradigm, because the protocol is generic, it can be reused for multiple application
having the same generic layer in both sides using libraries…. What we need to provide for each
application, is to surpass the low level, and we design the contract as an API that the server
implements, and the client uses. (Remote procedure call: RPC)
This paradigm requires taking the parameters that we remotely feed the function with and
converting them from in their in-memory representation to a network convenient representation
(stream of bytes) In such a way the server is able to reconstruct the parameters. The conversion is
called parameters serialization/ marshalling, the inverse action is called unmarshalling/
deserialization. The way it is done is also a generic part of the technology that provides the generic
protocol. The API/contract tells us how to do the serialization in the client side.
Abstraction on top of client server that provides a generic protocol the contract becomes the API.
We would like to have the luxury of invoking this remote services as if they were local and have the
consumer and fool it and make it think the service/ function is local while we now its remote.
As developer, we know when we call a function, its local. So how is this done?
Service consumer has also an implementation of the API. It needs to call add and it needs to be local.
Its not the business implementation, it has the same prototype to fool the consumer. It exposes the
same protype but not the real business implementation.
Send Add + the marshelled x+y will be sent, and the other side will invoke the according business
implementation. Locally exposing to the consumer, a method with the exact same interface (c:
prototype, java: interface) but the implementation is not the same. Takes parameters, marshall
them.
Example of calling a remote function as its local from consumer side, same protype of real
implementation.
Consumer has the same interface diff implementation = proxy implementation. Proxies the call from
consumer to other side.
2 parts, app dependent and API dependent, takes parameters, marshals them. Once marshaled, and
have the name of the function, send this to the other side, the generic protocol takes whatever
function name, marshalled parameters, I will express them to the other side where the real
implementation is happening. Part 2.
2-layer RPC library and client stub/ service proxy which implements the API.
Tool like compiler that once we have the API, you take it and compile it using the tool provided as
input and would generate the proxy implementation. There is a tool for automating the process.
Take prototype of function ( float add(float, float); ) introspect this function, see that is takes two
float and return one float, generate a c code that provides an implementation like this.
Stub/ Skeleton generator (compiler) generate code sous forme de 2 parts: one for client one for
server. Service consumer developer uses the client stub through the api interface.
Why not affording the integration between programs written in different languages
Have the service API as a descriptive language, that sets itself at the same distance from all
programming languages. Neutral representation. Like XML, Json…
That language takes a (api) as input and gives the client/server stubs
The first was CORBA, came with its own API definition language IDL (idl2c, idl2java, idl2python) and
genenric protocol IIOP
WSDL is xml based for XML/SOAP SOAP is the generic protocol and based on HTTP making it a web
service technology. Xml doesn’t impose naming, so wsdl is xml based but defines its own schemes for
api
Consumer sees 1 and 12. Other steps are transparent to the consumer. (abstraction)
Write the header file first, (business implementation) and have a took that takes it an converts it to
descriptive language of the service API.
Why we might use code first: in case you are a python developer, so you use an API generator that
will convert python to desciptive IDL rather than you learning IDL and doing API first.
The 7.0 and 5.0 have been marshaled from float to stringified text between to tags.
We define them, but never call them. They get called back by the run time. Callback: provide the
definition, don’t use, runtime uses it on our behalf.
-cp classpath
Drawback: because we want such a discoverability, then we shouldn’t have an API, a priori. If you
don’t have an API, then you can’t create using a tool automate the creation if the stub in different
languages, you can only provide a documentation or make the extra effort to develop the sdk per
supported language to the consumer.
Its not rpc, bcz the function is not called from the consumer side, the documentation is provided for
them to use it.
Why the calculator is not a rest service? Because its not data driven its service oriented
spring framework as an application server (server side java runtime environment on top jvm it will
create a web server and manage your server side java apps, first expose web server because we need
http) as opposed to xml soap where we use java api for xml web services. More powerful that node
(a runtime server environment for js app)
restcontroller is up to us to make it adhere to rest constraints or not. It can’t be rest because not
data driven, service oriented.
Requestmapping: bind/ expose the object that will be instantiated on our behalf by spring from this
calculator class, expose it and bind it to this path (route) : @RequestMapping("/calculator")
Because it’s a get method, x and y are to be found in the url as part of the request header to be
passed to add method.
Because we did the mapping of the classes with calculator, so spring would take notes that any get
request to /cal/add, know the params and extract the parameters and invoke a callback. It will be
called by spring on the once instantiated object of the class when a request similar is received.
We expose the method, provde the definition, but never call it ourselves, spring does the callback
In compute all, because im returning a complex object, and bcz am not using a strict tech like
xml/soap where by the returned object can only be serialized using wsdl marshalling, as a designer of
service, I made the choice of using json representation. Convert the java object into json.
Its not rpc, bcz the function is not called from the consumer side, the documentation is provided for
them to use it. So we need an API for them to use for it to become RPC.
We need an API definition language to support RPC. Swagger -> Swagger API specification - > Open
API specification. (the language) x
Code first, have a tool to generate for us the API using Open API specification.
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-ui:1.5.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Include the openAPI dependency that will intercept at run time + code and monitor the execution of
the application (requests and replies) take notes of them and was able to generate an api according
to open api spec
Access http://localhost:8080/v3/api-docs
The api according to open api spec (findings) is found in this url
From this api, swagger can generate the stub in the requested language.
@generated Value: jpa annotation to give a hint to hibernate (orm framework) to let dbms generate
on our behalf the id of new added instances.
Active record pattern / repo pattern: for each entity there is a corresponding repositories=> brand
(static method create)
@repositoryrestresource: entity can be managed by the repo upon rest requests coming from client
side. Expose it through rest.
Steaky sessions: load balancer sends requests coming form the same user to one and only box/server
Memory vs time: instead of remembering the id, we generate a token containing the user id and all
info and will add a digital signature on the server can generate. Send it and completely forget about
it, the client saves the token, and will send the token back with all subsequent requests. Servers have
no memory of the token, but through computing it has a key that allows them to check if the key to
the token. JWT to support statelessness, token-based session tracking vs cookie-based session
tracking. Less memory.
P3: Performance
In fx server,
If another connection request happens, it won’t be honored because the while(true) didn’t move to
the next iteration. Best case, delay in establishing the connection thanks to timeouts.
Design the server to be multithreaded: will have the main thread blocked at accept waiting for clients
to connect. As soon as it accepts a connection, it will delegate to the client, it won’t block the main
process that will go back directly to the listening phase. 50 concurrent clients = 50 threads + the main
one.
We create thread, We overwrite run, but we don’t call it. We rather call start(), that will create a
thread and call run inside that thread. We implement run and call start.
Run time support: go from address of f call to f definition. How to know which part of the code it was
called. The call address needs to be remembered.
One stack per thread, because we can’t mix all of them in one.
Upgrade run time environment to move to multithreading as os takes care of one thread.
Ex: jvm
a non blocking function doesn’t return, because you don’t wait, it doesn’t make sense.
File f = fopen(), You wait for it to return the result => its blocking, so this approach is not working
even if its non blocking now. The same line, but wait in another space. So we don’t need the
assignment because we will be waiting.
Provide a recipe the once the function yields a results from the thread, pass it as parameter n+1 the
last one which is what u would like to perform on that result.
Open on my behalf the file, and once opened and you have the representation, apply this treatment
on this file. The treatment, recipe is by itself a function definition. We define what should be done,
and It will be taken care of it by the time run once fopen yields a result by the run time environment.
It’s a call back because we define it and we never call it.
If we have more than one fopen function both have call back function, the order depends on which
outercall terminates first. Run tine env will take notes of both of them in a hash map
Thr1 – cbf 1
Thr2 – cbf 2
Inserted in the order of the termination of the thread. Thr2 terminates first, we push cbf2….cbf1
waits for its turn after cbf2 is terminated.
We have an event loop that fetches cbf from callback queue and moves them ti the call stack if
empty. Is not, wait. One at a time in call stack.
Need to remember the latest address at the level of the code. (functions calls)
Use one call stack to reduce memory usage and processing overhead.
Once the async function terminates and yield a result, send it to the CB function and the CB will act
on it.
The return address is pushed in the call stack, should not be mixed with other lines related to other
line of execution. It needs the stack to be empty. All lines are competing over 1 stack, we need some
waiting for the stack to be empty. (CB will be waiting in a queue)
Whenever the async function executes in a thread, it registers its callback, once I’m done, execute
the call back on the result I will yield. It needs to save the return address of the CB in the call stack.
Which may be busy and other callbacks will also be ready to enter the call stack. Thus, they need to
be kept on hold in the buffer queue. It can’t execute the call back before saving the return address. I
In case of multiple references in the same line of execution, they all enter the call stack.
the call back itself could be using an i/o operation or just fast cpu processing.
If I/O it returns right away, it doesn’t block, itself will register another callback. It won’t use the stack
for long, the returned address will be pushed and popped right away from the call stack.
Call back will be ready after 0ms (moved to the queue after xms), but the stack needs to be empty, it
is full with console.log(hello), our call back will be waiting in the queue, then moved to the stack.
The main issue is that the async function doesn’t return a result, they return void. But now we make
them return a promise. And then also returns a promise on the result returned by the call back after.
Return an object, not the result, but a pointer that allows us to track the result whenever its ready in
the future time. Proxi in time. Promise to have the result in the future time.
Calculator.then(c=>{c.add(x,y, {CB})}
Add Will be designed in such a way not take an additional callback, but a promise of the eventual
result.
Then will take the result of the call back and return it to the promise
.then(r =>console.log(r));
Then allows us to keep track of the result by returning a promise on it.
T = response.text()
Return t
Fopen(‘’ , « r »)
.then(f=>Fread(f))
.then(bytes => {
P = Fopen(‘ ‘, ‘w’)
}].then(o =>…………………
Customize the behavior of the promise constructor, we pass it in the function. Behavior is modeled
as a function. Instantiate promise class with the behavior. Reject and resolve are part of the language
/ runtime library. When we are called back, it will pass the actual resolve and reject methods.
CB gets to the queue if the run tile identifies a successful completion of the mother function.
2 promises into 1 promise who is an array of values of all the individual resolved promises.
P= Promise.all({p1,p2})
p.then(array => {
})
Case study:
Api interface: byte[ ] download DownloadChunk (string file, int start, int end);
If xml soap is used; we’ll have three wsdl files (because we have three wheres of the addresses of the
3 servers of fx) with there respective urls
Using zeep or soap… we’ll have N proxis/ client stubs, each pointing to a different url/server.
The stub will be asynchronous. Must look for the Use of a package that supports generating promise
based stubs.
In API should have another interface; get size takes string filename and return int filesize
Let chunks = []
N cs = size/M
Urls[ ]
P = Soap.clientPcreate(urls[i])
.then(fx=>fx.DownloadChunk(filename, cs * i , cs(i+1))
Chuncks.append(p);
Promise.all(chunks).then(real_chunks => (iterate over all the chunks => put them in one big array or
open a file and save all)
If 1 download takes 1min, how would all of it take? Nanoseconds because all are not blocking, and I
have the promise of each one of them.
Now we criticize promises (the logic is new, you work we something you can’t see through the .then)
Run time treats .then and async await the same way. Its just much readable and familiar.
Run time only understange .then it hasn’t been updated / upgraded to support async await, it
converts it back to .then structure
If async f1 return smth, it will return a promise on the answer, so we have to do f1.then to get the
return.
P4: Reactivity
Two objects of the class window; they share the same path, the point.
Entities involved: window: 1 actor with two instances, main actor on the other side that holds the
truth of the content of the path, source of truth, holds the truth about the path, creates, changes,
deletes the node from that path: os-> file system manager module.
User should have consistency, and ensure synchronization between different instances, but it costs
cpu time if it keeps checking for changes always.
Whenever there is smth new, call me back. The window can register itself with the truth holder, and
the file system orchestrates all the process instead of window trying to pull the information. File
system push the update in the interested parties: listeners (push system) thus fulfilling both
functional requirements: receive info as soon as change happen + low cost.
Each listener needs to subscribe with the file system so its aware of it, and it calls them back when
needed.
How they subscribe? SoT (source of truth) will maintain a list of subscribers. Expose a method called
subscribe( ) (api) takes a listener and add it to the list. Whenever an update happens, the sot needs
to notify(update u) (notify listener about the update)
s.update(notification);
For this to compile, it assumes that all subscribers support an update method. Update should be part
of the subscriber API. The contract between the source of truth and subscribers is that every
subscriber should support an update method. Expose update api to me so I (SoT) can callback this
method.
Having subscriber as an interface, sot commits itself to the interface rather than the type/ class of
each different subscriber. Each object can be instantiated from any class that implements the
interface. Its class will implement the update differently.
Sot only cares about the subscribers ability to receive the update but not how to implement it.
Sot calls each subscriber. Usually, the callee provides a service the calling entity. But the window
provides nothing to the sot. But the subscriber is the one taking advantage of the sot.
Observer design pattern: sot acting as the observable (active), each window is an observer(passive)
observing the sot. In a push system.
Decoupling???
Real time reaction at a low cost fulfilling the 2 requirements: func: user sees the change. Non-func:
performance.
Maps of nodes; key: path of the node, value: type of the node
Filesystem.java: observable, sot: no mention of window. It doesn’t know and care about notion of
window.
See notebook.
Stream is an unbounded series of events generated through time by the observable (stream source,
producer). Observer is the stream consumer.
Rx because there is a need to produce events and react to them asap at min cost.
Producer consumer
While most eng were happy with basic traditional observable design pattern, Rx went further and
tried to enhance. First remarque: observables are hot: as soon as you have a file system, its eager to
produce an event. Newcomers would have missed all previous events and will take it from the point
where they joined. Rx made an evolved version of observable for those who only live to produce
events for observer. Stream source just to produce events for observer this requires that you need to
have observers first observing the event. If observable has a list of observers, if someone joins later
one, it would have missed all the previous events.
Instead of pushing notifications to many observers. It doesn’t produce any event until there is an
observer and produce event related to it only. Observable has 1 observer per context.
Knows how to produce and doesn’t until there is an observable where it creates a context and.
Another observer may subscribe, and the observable will execute again with the new context of the
observable. It will not miss, because the observable started producing data when it subscribed.
The observable has the recipe to produce the data within each context.
Fct and observable Both are code, both produce data. Fct produce one data only once, while an
observable can produce a stream of events
We extend to define the recipe of how to use notify … and other functions provided by Observable
class.
Rx js, don’t need to extend the class to define the recipe, we instantiate new observable and pass the
recipe to produce the data that will be pushed to the only observer in that context.
Const myobservable = New Observable(observer => { for(let I =0; i<N; i++) observer.update(i)})
no data will be produced, we just defined the observable and defined the recipe (fct definition)
(fct call)
Are observable sync or async: we did two examples sync and async
4 or 5 observer, each its own stream and reacts to it its own way and the observable produces
stream,
You can add: This is why the latest I/O libraries are Rx Observable-based
(as opposed to promise-based). You can cite the Google
Angular HttpClient library (read more about it) as an evolution over the
promise-based fetch.
P4:
Scalability is the ability to maintain performance when the load grows. The cost shall not be
exponential to maintain the performance. It should be linear.
If decide to use hardware-based approaches, it’s a naïve approach as it reaches a dead end, each
time you’ll need to improve. (in-scaling)
Software level scaling out: adding software support, commodity level, entry level hardware. Make all
the machines (cluster of machines) act as one sharing their processes and computational power.
Array of 1M entries. How to do that in parallel using 2 machines? Divide and conquer. 2 partitions 2
boxes 2 executions. Each box has a limited storage. (make all disks appear as one big storage system
ex: GFS google file system, HDFS)
Mapping each element, parallelized by partitioning the initial collection of the data, submit to the
box, let the box perform the mapping on the partitions.
Hadoop is first distributed computing platform that’s able to host your own applications (user
defined) and run them. Apps should be written in a map reduce operations.
Setia home