Skip to content
Advertisements
Latest

Ruby Class Members: Getter & Setter

The simplest example of read_attr, write_attr in a class.

class Person  
  attr_reader :name, :age   
  attr_writer :name, :age   # creates the setter methods       
    
  def initialize(name)  
    [@name](http://twitter.com/name) = name  
  end  
endmike = Person.new('Mike')   
mike.age = 20               # calling setter method  
mike.age                    # calling getter method, returns 20

Reference

The example is verbatim from an easy to follow tutorial on Ruby class: https://medium.com/@rondwalker22/how-getter-setter-methods-work-in-ruby-c5f5da07f99

Ubiquitous Client for Redis Server: Netcat

Forget about redis-cli.

Just use nc

bash-5.0# nc -v  10.x.x.x 6379
10.x.x.x (10.x.x.x:6379) open
select 14
+OK

What is ncat?

NAME
     nc -- arbitrary TCP and UDP connections and listens

SYNOPSIS
     nc [-46AcDCdhklnrtUuvz] [-b boundif] [-i interval] [-p source_port] [-s source_ip_address] [-w timeout] [-X proxy_protocol] [-x proxy_address[:port]] [--apple-delegate-pid pid] [--apple-delegate-uuid uuid] [--apple-ext-bk-idle]
        [--apple-nowakefromsleep] [--apple-ecn mode] [hostname] [port[s]]

DESCRIPTION
     The nc (or netcat) utility is used for just about anything under the sun involving TCP or UDP.  It can open TCP connections, send UDP packets, listen on arbitrary TCP and UDP ports, do port scanning, and deal with both IPv4 and IPv6.
     Unlike telnet(1), nc scripts nicely, and separates error messages onto standard error instead of sending them to standard output, as telnet(1) does with some.

Reference

SIngle Thread LRUCache in C++

#include <iostream>
#include <list>
#include <unordered_map>

using namespace std;

size_t capacity;

class LRUCache
{
public:
    bool Lookup(int key, int *price)
    {
        auto it = hash_table.find(key);
        if (it == hash_table.end())
        {
            return false;
        }

        *price = it->second.second;

        // update the key in the queue
        MoveToFront(key, it);
        return true;
    }

    void Insert(int key, int price)
    {
        auto it = hash_table.find(key);
        if (it != hash_table.end())
        {
            MoveToFront(key, it);
            return;
        }

        if (hash_table.size() == capacity)
            CleanTable();

        lru_queue.emplace_front(key);
        hash_table[key] = {lru_queue.begin(), price};
    }

    bool Erase(int key)
    {
        auto it = hash_table.find(key);
        if (it != hash_table.end())
        {
            lru_queue.erase(it->second.first);
            hash_table.erase(it);
            return true;
        }
        return false;
    }

    void PrintQueue()
    {
        for (auto it : lru_queue)
        {
            cout << it << " ";
        }
        cout << endl;
    }

private:
    typedef unordered_map<int, pair<list<int>::iterator, int>> Table;
    Table hash_table;

    void MoveToFront(int key, const Table::iterator &it)
    {
        // delete the node.
        lru_queue.erase(it->second.first);

        // create a new node at the front.
        lru_queue.emplace_front(key);
        it->second.first = lru_queue.begin();
    }

    void CleanTable()
    {
        hash_table.erase(lru_queue.back());
        lru_queue.pop_back();
    }

    list<int> lru_queue;
};

int main()
{
    capacity = 3;
    LRUCache cache;

    cache.Insert(1, 100);
    cache.Insert(2, 200);
    cache.Insert(3, 300);

    cache.PrintQueue();

    cache.Insert(4, 400);
    cache.PrintQueue();
}

Output

$ g++ -std=c++11 ./LRUCache.cpp
$ ./a.out
  3 2 1 

  4 3 2 

Benefits & Caveats

  • O(1) operations
  • Single thread operation
  • Each CleanTable results in free and malloc in the lru_queue

Understanding Ruby Symbols

Ruby is an interpreted language. It is dynamically typed and uses a new memory for a variable. A variable has a name and a value. Symbols are an optimized variable that holds single instance of memory. It is good for variables that assume the same values across the program such as hash table keys.

h = {'my_key' => 123}

The storage for my_key is allocated each time my_key is used. That’s waste of memory and many related bookkeeping tasks by the Ruby interpreter.

So declaring the key as a symbol makes sense as only one copy of my_key is kept in memory.

h = {:my_key => 123}

You have to use the : operator with each usage of a symbol.

irb(main):003:0> new_hash={:my_key => 123}
=> {:my_key=>123}

irb(main):004:0> new_hash[:my_key]
=> 123

# You must use the :

irb(main):005:0> new_hash[my_key]
NameError: undefined local variable or method `my_key' for main:Object
    from (irb):5
    
irb(main):006:0> new_hash['my_key']
=> nil

Written with StackEdit.

One Way Communication with Pipe in Linux

Pipe uses kernel buffer to store data. It is a unidirectional read/write buffer and connects two processes. Each end (read or write) Pipe mimics a file operation. A process can choose to read or write (but not both). The processes have to use at least two pipes for two-way communication.

Example Communication

  • Parent process can talk to a child with an EOF. Just close its write end of the pipe. The child would get EOF on reading.

Example

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <assert.h>

int main()
{
    int contact[2];
    pipe(contact);

    int fd = fork();
    if (fd == 0) { // child
       char c;
       close(contact[1]); // close the write end.

       while (read(contact[0], &c, 1) > 0) // each call checks for EOF.
           printf("c=%c", c);
       close(contact[0]);
       exit(0);
    } else { // parent
        close(contact[0]); // close the read end.

        write(contact[1], "X", 1);
        close(contact[1]); // child sees EOF
        wait(NULL);
        exit(EXIT_SUCCESS);
    }
    return 1;
}

References

Written with StackEdit.

How a Regex Engine Work?

A regular expression defines a set of string.

A regex engine matches a pattern against input and returns true/false for the condition that pattern exists in the input.
I have got a C++ implementation of a regex engine which uses simple constructs of matching the following:

  1. A single character
  2. An equal length pattern and input
  3. A pattern that has ^ and $
  4. Wildcards (? and *)

It is inspired by https://nickdrane.com/build-your-own-regex/ and https://swtch.com/~rsc/regexp/regexp1.html.

The code is as following:

#include<iostream>

using namespace std;

bool MatchQuestion(const char * pattern, const char *input);
bool MatchStar(const char *pattern, const char *input);

bool matchOne(char pattern, char input)
{
  cout << "matchOne" << "patt=" << pattern << "input=" << input << endl;
 if (pattern == '\0')
     return true;

  if (input == '\0')
      return false;

  return pattern == input;
}

bool MatchSameLength(const char *pattern, const char* input) 
{
    if (*pattern == '\0')
        return true;

    return matchOne(pattern[0], input[0]) && MatchSameLength(pattern+1, input+1);
}

bool MatchAnywhere(const char *pattern, const char *input)
{
    //cout << "patt=" << *pattern << "input=" << *input << endl;
    if (*pattern == '\0')
        return true;

    if (*pattern == '$' && *input == '\0')
        return true;

    if (pattern[1] == '?') {
        return MatchQuestion(pattern, input);
    }

    if (pattern[1] == '*') {
        return MatchStar(pattern, input);
    }

    return matchOne(pattern[0], input[0]) && MatchAnywhere(pattern+1, input+1);
}

bool MatchQuestion(const char * pattern, const char *input)
{
    return (
        MatchAnywhere(pattern+2, input) ||
            (matchOne(*pattern, *input) && MatchAnywhere(pattern+2, input))
            );
}

bool MatchStar(const char *pattern, const char *input)
{
 return (
     MatchAnywhere(pattern+2, input) ||
     (matchOne(*pattern, *input) && MatchAnywhere(pattern, input+1))
 );
}

bool search(const char *pattern, const char *input )
{
    if (*pattern == '^') {
        return MatchAnywhere(pattern+1, input);
    }

    while (*input) {
        if (MatchAnywhere(pattern, input))
            return true;
        ++input;
        }
    return false;    
}

int main() {
    //cout << MatchSameLength("aab", "aab") << endl;
    //cout << MatchAnywhere("^b$", "b") << endl;

    cout << search("ax*b", "abc") << endl;
    return 1;
}
References

Written with StackEdit.

How to Add Syntax Highlight to WordPress Blog?

The default blog template and themes on WordPress do not have syntax highlighting enabled by default. I post many code blocks in my post and needed syntax highlight.
I am new to CSS so tried many solutions and found Prism to be the easiest and working out of the box.

How to Add Syntax Highlights?

  1. Download CSS code of Prism
  2. If you are on a premium plan to WordPress, you can create your CSS code for the blog/website.
    css editor
  3. Paste the Prism CSS code here. That’s all!

Why Redis Pipelining is a Good Idea?

What is PipeLining?

Pipelining is a form of asynchronous task execution. A Pipeline is a task that is composed of many subtasks. Each subtask may be dependent on its previous subtasks.

t1 => t2 => t3
            ^
        t4 =|

t2 depends on t1. t3 is dependent on t2 & t4.

While we are executing subtask t3 for primary task S1, we can also execute subtask t1 for another primary task S2. This is a pipelined execution.

How Redis Pipelining helps in Client-Server communication?
Each network request between the client and server involves a latency named Round-Trip-Time. Redis server reads a request from a client and client waits till the server writes the response.
We can rather ask the client to send many requests at once and collectively wait for the responses.

This helps us achieve:

  • Ability to counter RTT of a network.
  • Better throughput for client
  • Saves multiple reads from server to client.
  • The server sends single write with all responses

Classic Usage

  • POP3 uses pipelining

References

How to Write Clean Code?

Basic Hygiene

  • Leave the place cleaner than you got it.

Naming Convention

  • Do one thing in a function. Name should reflect the action. Function name is a verb.
  • Declare literals ([a-z]+, [0-9]+) as constants.

Functions

  • The function should not exceed twenty lines.
  • Each if, else, while statement can become a function.
  • The function can have one or two levels of indentation.
  • A function must do only one thing. The one thing is discovered when function can’t be reduced further. The reduced name is similar to the function’s current name.

This post is updated until the book “Clean Code” completes!

Reference

Written with StackEdit.

What is a Data Platform?

Over time, organizations need to go beyond a single DB for querying and storing data to a set of DBs that cater to different business requirements. A Data Platform might comprise:

  • Search Index
  • A relational DB
  • NoSQL DB
  • Data Warehouse

Why a Data Warehouse?

It is a subject of interest to understand how the application uses the DB. The inspection can happen with a set of queries to know the DB usage. But it might affect your primary workload, so you can create isolated replica nodes for such purpose.
However, there is a time when the schema of DB data is not suitable for querying that global view of the DB. So using an ETL pipeline, data is stored in the desired schema in a data warehouse such as S3.

Why a Search Index

Used for allowing applications to search the DB. Primarily Lucene based solution such as ES, Solr. The index is mostly eventually consistent with the DB. It is expensive to update index in the write path.

Why Docker is a Long Term Future for Platform?

What make Docker so popular and long-lasting?

  • Container is essentially OS level virtualization. Each application gets illusion of its own OS, having almost absolute control over it. Another advantage is that host OS knows about the container processes and hence can share its resources among hosted containers.
  • The concept of containers was started by FreeBSD, refined by Solaris and re-implemented by Linux.
  • Containers are better than two other levels of virtualization:
    • ABI/platform level, where application integrates with the platform (Google App Engine), doesn’t scale well.
    • Hardware level, where a virtual hardware runs the OS (e.g. virtual machines, hypervisors).
  • Docker containers run close to the real hardware, and host OS has knowledge of resource usage. Hence it’s an optimal sweet spot for virtualization.
  • Joyent SmartOS is built on OpenSolaris and provides Solaris features to Linux like Docker containers. It acheives that by allowing Linux APIs translated to Solaris APIs. Everything runs on the bare metal hence.
  • SmartOS containers get ZFS, Dtrace by default 🙂
  • SmartOS containers are very secure as they run in zones.

I hope to cover Smart OS design internals, Docker container on Linux details in next posts.

Reference

Linux Memory Management Tricks

Tips to Improve Dynamic Memory Performance

Instead of using memset() to initialize malloc()’ed memory, use calloc(). Because when you call memset(), VM system has to map the pages in to memory in order to zero initialize them. It’s very expensive and wasteful if you don’t intend to use the pages right away.

calloc() reserves the needed address space but does not zero initialize them unless memory is used. Hence it postpones the need to load pages in to memory. It also lets the system initialize pages as they’re used, as opposed to all at once.

  • Lazy allocation: A global(normal variable or a buffer) can be replaced with a static and a couple of functions to allow its access.

  • memcpy() & memmove() needs both blocks to be memory resident. Use them if size of blocks is small(>16KB), you would be using the blocks right away, if blocks are not page aligned, blocks overlap.
    But if you intend to postpone the use, you would increasing the working set of the application. For small amount of data, use memcpy().

  • To check heap dysfunctional behavior: $ MALLOC_CHECK_=1 ./a.out
    It’ll give an address related to each violation of dynamic memory routines.

  • Electric fence : Works very well with gdb

  • Libsafe: for libc routines

Internet Not working eh? How Ubuntu Resolves DNS?

Problem

I upgraded my Ubuntu from 16.04 to 18. And the Internet stopped working. 😦

I tried rebooting interface, adding a new interface to ifconfig. But it did not help.

What helped was an answer on AskUbuntu

How it worked?

The answer is in how Ubuntu lookup domains like http://www.google.com.

Step 1
Check the domain in the local DNS, also called a DNS stub.

Step 2
If Step 1 fails (local DNS lookup is a miss), it contacts a public DNS such as 8.8.8.8 also called Google Public DNS.

Since after the upgrade public DNS was not set, the internet seemed inaccessible!

How to Update Public DNS?

open /etc/resolv.conf
Add DNS=8.8.8.8

Done 🙂

Written with StackEdit.I

Notes on Go Structure Tags

Go has a feature to create a user-defined type with struct. Go also allows the program to specify meta-information with structure field.
This meta-information is called Tags. A tag usually helps in packaging/unpacking a user-defined type structure.

  package main

  import (
      "encoding/json"
      "fmt"
  )

  type Test struct {
      // json tags indicate the key name to use in json data
      Name    string `json:"myname"`
      Country string `json:"region"`
  }

  func main() {
      // The order of json need not match the order of structure fields.
      p := map[string]string{"region": "earth", "myname": "hello"}

      marshalled, err := json.Marshal(p)
      fmt.Println(marshalled, err)

      // get the var back from marshalled data
      var m Test
      json.Unmarshal(marshalled, &m)
      fmt.Printf("name=%v\n", m.Name)
      fmt.Printf("name=%v\n", m.Country)
  }

Why should I use json tags

  • The benefit of json tags is the flexibility to marshal with either a JSON or a struct.
  • JSON input for marshaling is convenient and flexible with elements ordering.

Reference

Adding Query Params to a URL in Ruby with HTTP

The clearest example was in a StackOverflow post

require 'uri'

def add_param(url, param_name, param_value)
 uri = URI(url)
 params = URI.decode_www_form(uri.query || "") << [param_name, param_value]
 uri.query = URI.encode_www_form(params)
 uri.to_s
end

You can pass a map of params key & values and get expected URL.

Another example

 # prepare params.
 params = { 'id' => '12' }

 path = 'http://localhost/'
 uri = URI(path)

 uri.query = URI.encode_www_form(params)

Output

http://localhost?id=12

Reference

%d bloggers like this: